Search code examples
c#wpflistviewmvvmdata-binding

Binding and changing a listView dynamically using MVVM


I have an object consisting of a string and a string of arrays. I'm binding the string to a comboBox but what I want to also do is bind the array of that object to a listview and have it change dynamically depending on combox box value. The values in the array aren't populating, only the dataType of the array. I'm not married to using a listview but I thought it would be easiest.

Model -


namespace DataBinding_WPF.Model
{
    public class ExampleModel { }

    public class Example : INotifyPropertyChanged
    {
        private string _name;
        private string[] _ids;

        public string Name
        {
            get => _name;
            set
            {
                if (_name != value)
                {
                    _name = value;
                    RaisePropertyChanged("Name");
                }
            }
        }

        public string[] IDs
        {
            get => _ids;
            set
            {
                if (_ids != value)
                {
                    _ids = value;
                    RaisePropertyChanged("IDs");
                }
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;
        private void RaisePropertyChanged(string property)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new 
                    PropertyChangedEventArgs(property));
            }
        }
    }

ViewModel -

namespace DataBinding_WPF.ViewModel
{
    public class ExampleViewModel
    {
        public ObservableCollection<Example> Examples
        {
            get;
            set;
        }

        public void LoadExample()
        {
            ObservableCollection<Example> examples = new ObservableCollection<Example>();
            examples.Add(new Example { Name = "Mark", IDs = new string[] { "123", "456" }});
            examples.Add(new Example { Name = "Sally", IDs = new string[] { "789","101112" }});
            Examples = examples;
        }
    }
}

XAML -


    <Grid>
        <StackPanel HorizontalAlignment = "Left" >

            <ComboBox HorizontalAlignment="Left"   
                  VerticalAlignment="Top"   
                  Width="120"   
                  ItemsSource="{Binding Path=Examples}"    
                  SelectedItem="{Binding Path=Name, Mode=TwoWay}"  
                  DisplayMemberPath="Name"/>

            <ListView x:Name="myListView" 
                        ItemsSource="{Binding Path=Examples}"   
                        SelectedValue="{Binding Path=IDs}" 
                        Height="200" Margin="0,50,0,0" 
                              Width="Auto"
                        VerticalAlignment="Top"
                        Background="AliceBlue">
                <ListView.ItemTemplate>
                    <DataTemplate>
                        <StackPanel Orientation="Horizontal" >
                            <CheckBox 
                                    Name="myCheckBox"                            
                                    IsChecked="{Binding IsSelected,
                                        RelativeSource={RelativeSource AncestorType=ListViewItem}}"
                                        Margin="5, 0"/>
                            <TextBlock Text= "{Binding Path=IDs}" FontWeight="Bold" />
                        </StackPanel>
                    </DataTemplate>
                </ListView.ItemTemplate>
            </ListView>
        </StackPanel>
    </Grid>


Solution

  • If you want to show in ListBox the Ids of selected item in comboBox. You need to add SelectedItem property to your VM which also must implement INotifyPropertyChanged interface.

    namespace DataBinding_WPF.ViewModel
    {
        public class ExampleViewModel : INotifyPropertyChanged
        {
            public ObservableCollection<Example> Examples
            {
                get;
                set;
            }
    
            // SelectedItem in the ComboBox
            // SelectedItem.Ids will be ItemsSource for the ListBox
            private Example _selectedItem;
            public Example SelectedItem
            {
              get => _selectedItem;
              set {
                  _selectedItem = value;
                  OnPropertyChanged(nameof(SelectedItem));
              } 
            }
    
            // SelectedId in ListView
            private string _selectedId;
            public string SelectedId
            {
              get => _selectedId;
              set {
                  _selectedId= value;
                  OnPropertyChanged(nameof(SelectedId));
              } 
            }
             
            public void LoadExample()
            {
                ObservableCollection<Example> examples = new ObservableCollection<Example>();
                examples.Add(new Example { Name = "Mark", IDs = new string[] { "123", "456" }});
                examples.Add(new Example { Name = "Sally", IDs = new string[] { "789","101112" }});
                Examples = examples;
            }
        }
    }
    

    XAML

    <Grid>
            <StackPanel HorizontalAlignment = "Left" >
    
                <ComboBox HorizontalAlignment="Left"   
                      VerticalAlignment="Top"   
                      Width="120"   
                      ItemsSource="{Binding Path=Examples}"    
                      SelectedItem="{Binding SelectedItem}"  
                      DisplayMemberPath="Name"/>
    
                <ListView x:Name="myListView" 
                            ItemsSource="{Binding SelectedItem.Ids}"   
                            SelectedItem="{Binding SelectedId}" 
                            Height="200" Margin="0,50,0,0" 
                                  Width="Auto"
                            VerticalAlignment="Top"
                            Background="AliceBlue">
                    <ListView.ItemTemplate>
                        <DataTemplate>
                            <StackPanel Orientation="Horizontal" >
                                <CheckBox 
                                        Name="myCheckBox"                            
                                        IsChecked="{Binding IsSelected,
                                            RelativeSource={RelativeSource AncestorType=ListViewItem}}"
                                            Margin="5, 0"/>
                                <TextBlock Text= "{Binding}" FontWeight="Bold" />
                            </StackPanel>
                        </DataTemplate>
                    </ListView.ItemTemplate>
                </ListView>
            </StackPanel>
        </Grid>