WPF MVVM hierarchy selected

I am currently implementing an application that displays a hierarchy using ListBoxes ( TreeView , ListBoxes not recommended).

Looks like the article: WPFs CollectionViewSource (with source) .

enter image description here

Classes:

 public class Mountains : ObservableCollection<Mountain> { public ObservableCollection<Lift> Lifts { get; } public string Name { get; } } public class Lift { public ObservableCollection<string> Runs { get; } } 

The example uses CollectionViewSource instances (see XAML) to simplify the design. An instance of the Mountains class is the DataContext for the window.


The problem is this: I would like the Mountains class to have the SelectedRun property, and it should be set to the currently selected run.

 public class Mountains : ObservableCollection<Mountain> { public ObservableCollection<Lift> Lifts { get; } public string Name { get; } public string SelectedRun { get; set; } } 

I may have missed some basic principle, but how can I achieve this?

+4
source share
3 answers

You can read about using '/' in bindings. See the "Current Position Indexes" section in this MSDN article.

Here is my solution:

Xaml

  <Grid.RowDefinitions> <RowDefinition Height="Auto"/> <RowDefinition/> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition/> <ColumnDefinition/> <ColumnDefinition/> </Grid.ColumnDefinitions> <TextBlock Margin="5" Grid.Row="0" Grid.Column="0" Text="Mountains"/> <TextBlock Margin="5" Grid.Row="0" Grid.Column="1" Text="Lifts"/> <TextBlock Margin="5" Grid.Row="0" Grid.Column="2" Text="Runs"/> <ListBox Grid.Row="1" Grid.Column="0" Margin="5" ItemsSource="{Binding Mountains}" DisplayMemberPath="Name" IsSynchronizedWithCurrentItem="True" /> <ListBox Grid.Row="1" Grid.Column="1" Margin="5" ItemsSource="{Binding Mountains/Lifts}" DisplayMemberPath="Name" IsSynchronizedWithCurrentItem="True"/> <ListBox Grid.Row="1" Grid.Column="2" Margin="5" ItemsSource="{Binding Mountains/Lifts/Runs}" IsSynchronizedWithCurrentItem="True" SelectedItem="{Binding SelectedRun}"/> </Grid> 

C # (note that you do not need to implement INotifyPropertyChanged if the properties are not changed, not just selected)

 public class MountainsViewModel { public MountainsViewModel() { Mountains = new ObservableCollection<Mountain> { new Mountain { Name = "Whistler", Lifts = new ObservableCollection<Lift> { new Lift { Name = "Big Red", Runs = new ObservableCollection<string> { "Headwall", "Fisheye", "Jimmy's" } }, new Lift { Name = "Garbanzo", Runs = new ObservableCollection<string> { "Headwall1", "Fisheye1", "Jimmy's1" } }, new Lift {Name = "Orange"}, } }, new Mountain { Name = "Stevens", Lifts = new ObservableCollection<Lift> { new Lift {Name = "One"}, new Lift {Name = "Two"}, new Lift {Name = "Three"}, } }, new Mountain {Name = "Crystal"}, }; } public string Name { get; set; } private string _selectedRun; public string SelectedRun { get { return _selectedRun; } set { Debug.WriteLine(value); _selectedRun = value; } } public ObservableCollection<Mountain> Mountains { get; set; } } public class Mountain { public string Name { get; set; } public ObservableCollection<Lift> Lifts { get; set; } } public class Lift { public string Name { get; set; } public ObservableCollection<string> Runs { get; set; } } 
+4
source

This is how I do it. You want you to fire the INotifyPropertyChanged event when setting properties. To get the selected run, you will need to get MainViewModel.SelectedMountain.SelectedLift.SelectedRun.

 public class MainViewModel: ViewModelBae { ObservableCollection<MountainViewModel> mountains public ObservableCollection<MountainViewModel> Mountains { get { return mountains; } set { if (mountains != value) { mountains = value; RaisePropertyChanged("Mountains"); } } } MountainViewModel selectedMountain public MountainViewModel SelectedMountain { get { return selectedMountain; } set { if (selectedMountain != value) { selectedMountain = value; RaisePropertyChanged("SelectedMountain"); } } } } public class MountainViewModel: ViewModelBae { ObservableCollection<LiftViewModel> lifts public ObservableCollection<LiftViewModel> Lifts { get { return lifts; } set { if (lifts != value) { lifts = value; RaisePropertyChanged("Lifts"); } } } LiftViewModel selectedLift public LiftViewModel SelectedLift { get { return selectedLift; } set { if (selectedLift != value) { selectedLift = value; RaisePropertyChanged("SelectedLift"); } } } } public class LiftViewModel: ViewModelBae { ObservableCollection<string> runs public ObservableCollection<string> Runs { get { return runs; } set { if (runs != value) { runs = value; RaisePropertyChanged("Runs"); } } } string selectedRun public string SelectedRun { get { return selectedLift; } set { if (selectedLift != value) { selectedLift = value; RaisePropertyChanged("SelectedLift"); } } } } <ListBox ItemsSource="{Binding Mountains}" SelectedItem="{Binding SelectedMountain, Mode=TwoWay}"> <ListBox ItemsSource="{Binding SelectedMountain.Lifts}" SelectedItem="{Binding SelectedMountain.SelectedLift, Mode=TwoWay}"> <ListBox ItemsSource="{Binding SelectedMountain.SelectedLift.Runs}" SelectedItem="{Binding SelectedMountain.SelectedLift.SelectedRun, Mode=TwoWay}"> 
+2
source

Your ViewModel also does not have to be a collection; it must contain collections and properties associated with the view. SelectedRun should be the property of this ViewModel (MountainViewModel), not the mountains. MountainViewModel must display a collection of Mountains and SelectedRun and must be bound to the ItemsSource and SelectedItem of the list.

0
source

Source: https://habr.com/ru/post/1402948/


All Articles