How to bind Group Names and Items separately in different Comboboxes

Emon Haque 3,176 Reputation points
2020-09-29T08:59:09.113+00:00

I've an ICollectionView named MyObjects with group description. In code I can access group Name and Items this way:

foreach (var gr in MyObjects.Groups) 
{ 
    var group = gr as CollectionViewGroup; 
    var name = group.Name; 
    var item = group.Items.OfType<TestObject>(); 
    ... 
} 

I want to display the Name in one ComboBox and Items related to the selected group of that ComboBox in another ComboBox in a Grid like this:

<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition/>
        <ColumnDefinition/>
    </Grid.ColumnDefinitions>
    <ComboBox ItemsSource="{Binding MyObjects/Names}"
              DisplayMemberPath="Name"/>
    <ComboBox Grid.Column="1" 
              ItemsSource="{Binding MyObjects/Items}"
              DisplayMemberPath="Name"/>
</Grid>

obviously the above xaml doesn't work. Is there a way to bind those group Name and Items in different ComboBox?

Windows Presentation Foundation
Windows Presentation Foundation
A part of the .NET Framework that provides a unified programming model for building line-of-business desktop applications on Windows.
2,710 questions
0 comments No comments
{count} votes

Accepted answer
  1. Peter Fleischer (former MVP) 19,316 Reputation points
    2020-09-30T03:30:09.357+00:00

    Hi,
    the easiest way is include additional property for binding second combobox. try following demo:

    XAML:

    <Window x:Class="WpfApp1.Window85"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            xmlns:local="clr-namespace:WpfApp85"
            mc:Ignorable="d"
            Title="Window85" Height="450" Width="800">
      <Window.DataContext>
        <local:ViewModel/>
      </Window.DataContext>
      <Window.Resources>
        <Style TargetType="ComboBox">
          <Setter Property="VerticalAlignment" Value="Top"/>
          <Setter Property="Margin" Value="5"/>
        </Style>
      </Window.Resources>
      <Grid>
        <Grid.ColumnDefinitions>
          <ColumnDefinition/>
          <ColumnDefinition/>
        </Grid.ColumnDefinitions>
        <ComboBox ItemsSource="{Binding MyObjects.Groups}"
                  SelectedItem="{Binding CurrentGroup}"
                  DisplayMemberPath="Name"/>
        <ComboBox Grid.Column="1" 
                  ItemsSource="{Binding GroupItems}"
                  DisplayMemberPath="Info"/>
      </Grid>
    </Window>
    

    And classes:

    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.ComponentModel;
    using System.Linq;
    using System.Runtime.CompilerServices;
    using System.Windows;
    using System.Windows.Data;
    
    namespace WpfApp85
    {
      public class ViewModel : INotifyPropertyChanged
      {
        public ViewModel() => LoadData();
    
        ObservableCollection<TestObject> col = new ObservableCollection<TestObject>();
        CollectionViewSource cvs = new CollectionViewSource();
        public ICollectionView MyObjects { get => cvs.View; }
    
        private object _currentGroup = null;
        public object CurrentGroup
        {
          get => this._currentGroup;
          set
          {
            this._currentGroup = value;
            OnPropertyChanged(nameof(GroupItems));
          }
        }
        public IEnumerable<object> GroupItems
        {
          get
          {
            var group = this._currentGroup as CollectionViewGroup;
            return (group == null) ? null : group.Items.OfType<TestObject>();
          }
        }
    
        private void LoadData()
        {
          Random rnd = new Random();
          for (int i = 1; i < 100; i++)
            col.Add(new TestObject() { Group = $"Group{rnd.Next(1, 10)}", Info = $"Row {i:00}" });
          cvs.Source = col;
          cvs.GroupDescriptions.Add(new PropertyGroupDescription("Group"));
          cvs.SortDescriptions.Add(new SortDescription("Group", ListSortDirection.Ascending));
          cvs.SortDescriptions.Add(new SortDescription("Info", ListSortDirection.Ascending));
        }
        public event PropertyChangedEventHandler PropertyChanged;
        private void OnPropertyChanged([CallerMemberName] string propName = "") =>
          PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName));
      }
    
      public class TestObject
      {
        public string Group { get; set; }
        public string Info { get; set; }
      }
    }
    
    1 person found this answer helpful.

0 additional answers

Sort by: Most helpful