There is:

StudentsList (ObservableCollection); GroupsList - ObservableCollection.

ComboBox (group selection); ListView (student selection)

After selecting a group, you must leave only the students of a particular group in ListView.

Should I have another ObservableCollection in the MainViewModel, which will consist of specific StudentList elements? (however, for some reason ListView is not updated) Or are there more rational ways?

Also in the ComboBox, next to the elements of the Group class, you must first put the field "All groups", how to do it ?? At the moment, ComboBox looks like this (it is not necessary to look):

<ComboBox ItemsSource="{Binding GroupsList}" SelectedItem="{Binding SelectedGroup, UpdateSourceTrigger=PropertyChanged}" Margin="20,0,20,20" SelectedIndex="0"> <ComboBox.ItemTemplate> <DataTemplate> <TextBlock Text="{Binding GroupNum}"/> </DataTemplate> </ComboBox.ItemTemplate> </ComboBox> 

Listview

 <ListView Name="StudentsView" ItemsSource="{Binding StudentsList}" SelectedItem="{Binding SelectedStudent, UpdateSourceTrigger=PropertyChanged}" Grid.Column="0" Grid.Row="1" Margin="20,0,0,0"> <ListView.ItemContainerStyle> <Style TargetType="ListViewItem"> <Setter Property="HorizontalContentAlignment" Value="Stretch"/> <Setter Property="VerticalContentAlignment" Value="Stretch"/> </Style> </ListView.ItemContainerStyle> <ListView.ItemTemplate> <DataTemplate> <Border Padding="10"> <Border.InputBindings> <MouseBinding Gesture="LeftDoubleClick" Command="{Binding DataContext.AddStudent, RelativeSource={RelativeSource FindAncestor, AncestorType=Window}}" CommandParameter="{Binding}"/> </Border.InputBindings> <StackPanel> <TextBlock Text="{Binding DisplayName}" FontWeight="Bold"/> <StackPanel Orientation="Horizontal"> <TextBlock Text="{Binding GetGroupNum}" Margin="10,0"/> </StackPanel> </StackPanel> </Border> </DataTemplate> </ListView.ItemTemplate> </ListView> 

Selectedgroup

 public Group SelectedGroup { get { return selectedGroup; } set { selectedGroup = value; OnPropertyChanged("SelectedGroup"); FullListStudents = StudentsList; StudentsList = new ObservableCollection<Student>(FullListStudents.Where( (x) => x.CurrentGroup == selectedGroup)); SelectedStudent = StudentsList.FirstOrDefault(); } } 

I don’t ask you to write specific implementations, just to prompt ideologically.

  • That is, you should have either a list of students or a specific group in the ListBox? - VladD
  • Стоит ли в MainViewModel заводить еще одну ObservableCollection, которая будет состоять из конкретных элементов StudentList? - as an option, just need OnPropertyChanged not to forget for it to call for the UI to know that it is time to update - Andrey NOP
  • Yes, the ListView must be either all students or a specific group selected in a combo box. I started a separate field, and changed the SelectedGroup handler, but the ListView is not updated. - TorSen
  • Since you were not looking for a ready-made implementation, I wrote the answer for the most part consisting of links. If necessary, I can add an example. If in the course of any questions - do not hesitate to ask. Perhaps you will be more comfortable to discuss in chat mode, you can always ping in the F # room . - user227049
  • I am not against the example, quite the contrary. Regarding the first: I suppose that then my SelectedGroup field when using the CollectionViewSource becomes irrelevant, which is not very good for me. Regarding the second: there is a similar situation, I would like to do without the CollectionViewSource, because when I use it in SelectedStudent, I also don’t need it, although I may be mistaken of something, but on the whole, the second option looks quite difficult for me. - TorSen

3 answers 3

In order to add an additional item to the ComboBox you can use the CompositeCollection . This question has already been asked several times; details can be found at the following links.

To install a filter, use ICollectionView , you can read more in a variety of sources - from books to questions on SO, below are several sources that will be useful

    You have a classic case of master / detail view.

    Perhaps it makes sense to drag the existence of a pseudogroup containing all students to the level of business logic. It will be easy. (I replaced the Student class with string , and removed the ObservableCollection<> for simplicity.)

     class Group { public Group(IEnumerable<string> students, string name) { Students = students; Name = name; } public string Name { get; } public IEnumerable<string> Students { get; } } class MainVM { public MainVM() { Groups = new[] { new Group(new[] { "Fritz", "Uwe", "Jan" }, "Norddeutschland"), new Group(new[] { "Johannes", "Christian", "Andreas" }, "Süddeutschland") }; var allStudents = Groups.SelectMany(g => g.Students).ToList(); var totalGroup = new Group(allStudents, "(all)"); GroupsAndTotal = new[] { totalGroup }.Concat(Groups); } public IEnumerable<Group> Groups { get; } public IEnumerable<Group> GroupsAndTotal { get; } public IEnumerable<string> AllStudents { get; } } 

    Well, the markup:

     <ComboBox VerticalAlignment="Top" ItemsSource="{Binding GroupsAndTotal}" DisplayMemberPath="Name" IsSynchronizedWithCurrentItem="True"/> <ListBox ItemsSource="{Binding GroupsAndTotal/Students}"/> 

    Result:

    This is how it turned out

    • Yes, I understand what you mean, thank you. However, I have a group that does not have a list of students, because of disagreements, I refused this idea. Selecting the option from the first link (suggested by Foggy Finder) I am trying to do something similar: Leave FullList Students - all students. StudentsList - students who will go to the ListView. In ComboBox, selecting a group, when installing the Sev-va SelectedGroup using Linq, I select students with the desired group. Problems 2: 1. For some reason, the DisplayMemberPath does not work as you do. 2. It is not clear how to associate the item "Any Group" with SelectedGroup. - TorSen
    • @TorSen: Why doesn't the group have a list of students? And where is he still to be? If you have a “group” entity, then you can at least make the calculated property IEnumerable<Student> Students => AllStudents.Where(st => st.Group == this); . - VladD
    • @TorSen: If you followed the filtering path, you can, too. - VladD
    • @TorSen: Perhaps the DisplayMemberPath not working because you are trying to bind to a field, and not a property? - VladD
    • Initially, the group had a collection of students, but later I abandoned this idea. (apparently for good reason). I can add more, but double-clicking on the ListView element opens a window with editing, so the IEnumerable option will probably not work, although I could be wrong. I am tied to Holy Island. - TorSen

    Total:

      <ComboBox Margin="20,0,20,20" SelectedItem="{Binding SelectedGroup}" DisplayMemberPath="{Binding GroupNum}" SelectedIndex="-1"> <ComboBox.ItemsSource> <CompositeCollection> <ComboBoxItem TabIndex="0" Content="Any Group" Selector.Selected="ComboBox_Selected"/> <CollectionContainer Collection="{Binding Source={StaticResource ComboBoxCollection}}"/> </CompositeCollection> </ComboBox.ItemsSource> </ComboBox> public Group SelectedGroup { get { return selectedGroup; } set { selectedGroup = value; OnPropertyChanged("SelectedGroup"); StudentsList.Clear(); if (value == null) { StudentsList = new ObservableCollection<Student>(FullListStudents); } else StudentsList = new ObservableCollection<Student>(FullListStudents.Where(x => x.CurrentGroup == selectedGroup)); OnPropertyChanged("StudentsList"); OnPropertyChanged("SelectedStudent"); } } private void ComboBox_Selected(object sender, RoutedEventArgs e) { ((MainViewModel)this.DataContext).SelectedGroup = null; } 

    Available problems:

    1. Incorrect group number displayed.
    2. Highlight the item "Any Group" in red.
    3. MVVM pattern violation.
    4. Doubtful (in my opinion) implementation of the Sv-va SelectedGroup.

      It works of course, as a last resort, you have to overload the ToString method of the group and leave it as is.