Привязать источник элементов к выбранному элементу

#c# #wpf

#c# #wpf

Вопрос:

Это моя структура данных:

 public class Movie : IMovie
{
    public string Title { get; set; }
    public string Description { get; set; }
    public List<IActor> Actors { get; set; }
}

public class Actor : IActor
{
    string FirstName { get; set; }
    string LastName { get; set; }
}
  

И это моя ViewModel:

 public class MovieViewModel : BaseViewModel
    {
        public ObservableCollection<IMovie> Movies { get; set; } = new ObservableCollection<IMovie>();

        public MovieViewModel()
        {
            foreach (var movie in blc.GetAllMovies())
                Movies.Add(movie);
        }
    }
  

В моем MainWindow я добавляю dataContext этим:

 this.DataContext = new MovieViewModel();
  

У меня есть 2 списка. Когда я выбираю фильм в первом списке, я хочу отобразить всех действующих лиц во втором списке.

Мне удалось отобразить фильмы. По какой-то причине актеры не отображаются при нажатии на какой-либо фильм.

 <ListBox x:Name="moviesListBox" ItemsSource="{Binding Movies}" SelectedItem="{Binding SelectedMovie, Mode=TwoWay}" />
<ListBox x:Name="actorsListBox" ItemsSource="{Binding SelectedMovie.Actors}" SelectedItem="{Binding SelectedActor, Mode=TwoWay}" />
  

Что здесь не так?

Комментарии:

1. Как SelectedMovie.Cast определяется?

2. @LewsTherin извините, там должно быть Actors . Это опечатка, когда я копировал это в so .

3. Совершенно не уверен, но просто по сходству с WinForms, доступен ли этот SelectedValue = {} атрибут? Если да, может быть, стоит попробовать?

4. Является SelectedMovie свойством класса MovieViewModel и выдает ли оно уведомление об изменении свойства?

5. Можете ли вы подтвердить, что список действующих лиц заполнен? Ваш код может быть в порядке, но без данных! Также у вас есть datatemplate для актеров? Зачем вам нужны имена в ваших списках?

Ответ №1:

Вы не показали, где / как определяется SelectedMovie (как он существует в своей viewmodel), но

  1. viewmodel, в котором содержится SelectedMovie (предположительно, DataContext формы / страницы, содержащей элементы управления ListBox), должен реализовывать интерфейс INotifyPropertyChanged (MVVM Light ViewModelBase делает это за вас)

  2. Свойство SelectedMovie должно вызывать событие PropertyChanged в своем установщике. Если вы используете MVVM Light, ViewModelBase предоставляет установленный метод для выполнения этого за вас.

Пример (с использованием MVVM Light; обратите внимание, что я опустил много деталей, чтобы сосредоточиться на основной проблеме):

 <Window 
    DataContext={Binding MyViewModel, Source={StaticResource Locator}}
    >
    <ListBox x:Name="moviesListBox" ItemsSource="{Binding Movies}" SelectedItem="{Binding SelectedMovie, Mode=TwoWay}" />
    <ListBox x:Name="actorsListBox" ItemsSource="{Binding SelectedMovie.Actors}" SelectedItem="{Binding SelectedActor, Mode=TwoWay}" /> 
</Window>

public MovieViewModel : ViewModelBase
{
    public ObservableCollection<IMovie> Movies { get; } = new ObservableCollection<IMovie>();

    public MovieViewModel()
    {
        foreach (var movie in blc.GetAllMovies())
            Movies.Add(movie);
    }

    private Movie _selectedMovie;
    public Movie SelectedMovie
    {
        get
        {
            return _selectedValue;
        }
        set
        {
            Set(ref _selectedValue, value);
        }
    }
}

public class ViewModelLocator
{
    // Constructor to register ViewModels, etc...
    //


    public MovieViewModel MyViewModel => /* resolve the view model */
}
  

Ответ №2:

В вашем SelectedMovie свойстве нет MovieViewModel свойства. Вы должны добавить его и вызывать PropertyChanged событие всякий раз, когда оно установлено, как предложено @C Robinson, или вы могли бы привязаться непосредственно к SelectedItem свойству moviesListBox :

 <ListBox x:Name="actorsListBox" ItemsSource="{Binding SelectedItem.Actors, ElementName=actorsListBox}"
                                SelectedItem="{Binding SelectedActor, Mode=TwoWay}" />
  

Ответ №3:

В вашем SelectedActor свойстве нет ViewModel свойства.

ViewModel

 public ObservableCollection<IMovie> Movies { get; set; } = new ObservableCollection<IMovie>();

private IMovie _selectedMovie
public IMovie SelectedMovie
{
   get => _selectedMovie;
   set
   {
      _selectedMovie = value;
      RaisePropertyChanged(nameof(SelectedMovie));
   }
}
  

Поэтому, когда вы будете выбирать фильм, будет вызван установщик SelectedMovie. Там это вызовет событие изменения свойства для SelectedMovie, а затем пользовательский интерфейс обновит второй список.