Привязка элемента на основе MVVM к двум элементам управления Windows Phone

#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));
                    }
                });

            });
        }
    }