简体   繁体   中英

Bind ItemsSource from SelectedItem

This is my data structure:

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

And this is my 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);
        }
    }

In my MainWindow I'am adding dataContext by this:

this.DataContext = new MovieViewModel();

I have 2 listboxes. When I select a movie in first listbox I want to display all actors in second listbox.

I managed to display movies. For some reason actors arent displayed when clicking on any movie.

<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}" />

What's wrong there?

You haven't shown where/how SelectedMovie is defined (how it exists in its viewmodel), but

  1. The viewmodel in which SelectedMovie is contained (presumably DataContext of the form/page containing the ListBox controls) must implement the INotifyPropertyChanged interface (the MVVM Light ViewModelBase does this for you)

  2. The SelectedMovie property must raise the PropertyChanged event in its setter. If you are using MVVM Light, ViewModelBase provides a Set method to do this for you.

Example (using MVVM Light; note I've omitted a lot of details to focus on the core issue):

<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 */
}

There is no SelectedMovie property in your MovieViewModel . You should add one and raise the PropertyChanged event whenever it's set as suggested by @C Robinson, or you could bind directly to the SelectedItem property of the moviesListBox :

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

There is no SelectedActor property in your 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));
   }
}

So when you will select a movie, SelectedMovie setter will be called. There it will raise property changed event for SelectedMovie, and then UI will update the second list.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM