#c# #xaml #windows-phone-8 #mvvm #async-await
#c# #xaml #windows-phone-8 #mvvm #асинхронное ожидание
Вопрос:
У меня есть два элемента управления на одной странице :
1. RadSlider
2. ListBox
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<Grid.RowDefinitions>
<RowDefinition Height="*"></RowDefinition>
<RowDefinition Height="100"></RowDefinition>
</Grid.RowDefinitions>
<telerik:RadSlideView Name="imgSlidView" >
<telerik:RadSlideView.ItemTemplate>
<DataTemplate>
<Image Source="{Binding Src}"></Image>
</DataTemplate>
</telerik:RadSlideView.ItemTemplate>
<telerik:RadSlideView.ItemPreviewTemplate>
<DataTemplate>
<telerik:RadBusyIndicator></telerik:RadBusyIndicator>
</DataTemplate>
</telerik:RadSlideView.ItemPreviewTemplate>
</telerik:RadSlideView>
<ListBox Grid.Row="1" Name="lstImage">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"></StackPanel>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<Image Height="100" Margin="0,0,5,0" Source="{Binding Src}"></Image>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Я хочу привязать два элемента управления к одному источнику элемента таким образом, чтобы при выборе одного из них выбор другого также должен измениться.
Меня интересует решение на основе MVVM.
Мой код :
class CategoryViewModel : ViewModelBase
{
public ObservableCollection<ImageSource> ImageCollection { get; set; }
private ImageSource _CurrentImage;
public ImageSource CurrentImage
{
get { return _CurrentImage; }
set
{
_CurrentImage = value;
RaisePropertyChanged("CurrentImage");
}
}
}
В дополнение к этому у меня есть фрагмент кода, который возвращает IEnumerable, и я хочу, чтобы это было как источник элемента.
public static async Task<IEnumerable<Object>> GetCategoryNames()
{
if (Categories == null)
{
JDir dir = Newtonsoft.Json.JsonConvert.DeserializeObject<JDir>(await LoadFromJson());
Categories = ConvertJDirToCategory(dir);
return Categories.Select(p => new { Name = p.Name, Src = "Images/" p.Name ".jpg" });
}
else
{
return Categories.Select(p => new { Name = p.Name, Src = "Images/" p.Name ".jpg" });
}
}
Правильно ли я поступаю? Как мне поступить?
Заранее спасибо!
РЕДАКТИРОВАТЬ — из комментариев:
private static async Task<string> LoadFromJson()
{
string theData = string.Empty;
StorageFile file = await Windows.Storage.StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///data.json"));
using (StreamReader streamReader = new StreamReader(await file.OpenStreamForReadAsync()))
{
return await streamReader.ReadToEndAsync();
}
}
Комментарии:
1. Как это
LoadFromJson
реализовано?2. из папки установки
private static async Task<string> LoadFromJson() { string theData = string.Empty; StorageFile file = await Windows.Storage.StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///data.json")); using (StreamReader streamReader = new StreamReader(await file.OpenStreamForReadAsync())) { return await streamReader.ReadToEndAsync(); } }
3. Похоже, в чем проблема? почему бы просто не привязать результат из
GetCategoryNames
к вашей коллекции?4. Да, привязка работает нормально, но, как я спросил, изменяет ли выбор одного элемента управления выбор другого, также должен измениться. Как я могу реализовать это с помощью MVVM?
5. Добавьте свойство SelectedIndex типа int в ViewModel и привяжите его к свойству SelectedIndex элементов управления. Убедитесь, что вы внедрили INotifyPropertyChanged .
Ответ №1:
Спасибо всем, теперь моя проблема решена :
XAML :
DataContext="{Binding Category, Source={StaticResource Locator}}"
Два элемента управления :
<telerik:RadSlideView Name="imgSlidView" SelectedItem="{Binding SelectedItem,Mode=TwoWay}" ItemsSource="{Binding Images}">
<telerik:RadSlideView.ItemTemplate>
<DataTemplate>
<Image Source="{Binding}">
<telerik:RadContextMenu.ContextMenu>
<telerik:RadContextMenu IsZoomEnabled="False" OpenGesture="Tap">
<telerik:RadContextMenuItem Tap="RadContextMenuItem_Tap" Content="Share">
</telerik:RadContextMenuItem>
</telerik:RadContextMenu>
</telerik:RadContextMenu.ContextMenu>
</Image>
</DataTemplate>
</telerik:RadSlideView.ItemTemplate>
<telerik:RadSlideView.ItemPreviewTemplate>
<DataTemplate>
<telerik:RadBusyIndicator></telerik:RadBusyIndicator>
</DataTemplate>
</telerik:RadSlideView.ItemPreviewTemplate>
</telerik:RadSlideView>
<ListBox Grid.Row="1" ScrollViewer.HorizontalScrollBarVisibility="Auto" Name="lstImage" SelectedItem="{Binding SelectedItem,Mode=TwoWay}" ItemsSource="{Binding Images}">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"></StackPanel>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<Image Height="100" Margin="0,0,5,0" Source="{Binding}">
</Image>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Просмотр модели :
public class CategoryViewModel : ViewModelBase
{
private string _CategoryName;
public string CategoryName
{
get { return _CategoryName; }
set
{
DispatcherHelper.CheckBeginInvokeOnUI(() => { Set<string>(ref _CategoryName, value); });
}
}
private Uri _SelectedItem;
public Uri SelectedItem
{
get { return _SelectedItem; }
set
{
DispatcherHelper.CheckBeginInvokeOnUI(() => { Set<Uri>(ref _SelectedItem, value); });
}
}
private ObservableCollection<Uri> _Images;
public ObservableCollection<Uri> Images
{
get { return _Images; }
set { Set<ObservableCollection<Uri>>(ref _Images, value); }
}
public CategoryViewModel()
{
CategoryName = string.Empty;
Images = new ObservableCollection<Uri>();
}
}
XAML.cs
protected override void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e);
string Category = string.Empty;
NavigationContext.QueryString.TryGetValue("category", out Category);
if (this.DataContext is CategoryViewModel)
{
var vm = (CategoryViewModel)this.DataContext;
vm.Images.Clear();
JSONHelper.LoadFromJson().ContinueWith(t =>
{
vm.CategoryName = Category;
var images = t.Result.Dirs.FirstOrDefault(p => p.DirName == Category).Files;
Dispatcher.BeginInvoke(() =>
{
foreach (var img in images)
{
vm.Images.Add(new Uri(string.Format("Data/{0}/{1}", Category, img), UriKind.Relative));
}
});
});
}
}