Search code examples
wpfxamlwpfdatagrid

How to Update DataGrid ItemsSource when change its Property?


This is an example code:

public class GridViewWindowViewModel : INotifyPropertyChanged
    {
        public GridViewWindowViewModel()
        {
            Tables = new ObservableCollection<string> { "Person", "Car" };
            SainaAccessEntity = new SainaAccessEntity { TableName = "Person" };
        }

        private SainaAccessEntity _SainaAccessEntity;

        public SainaAccessEntity SainaAccessEntity
        {
            get { return _SainaAccessEntity; }
            set
            {
                if (_SainaAccessEntity != value)
                {
                    _SainaAccessEntity = value;
                    OnPropertyChanged();
                }
            }
        }

        private ObservableCollection<string> _Tables;

        public ObservableCollection<string> Tables
        {
            get { return _Tables; }
            set
            {
                if (_Tables != value)
                {
                    _Tables = value;
                    OnPropertyChanged();
                }
            }
        }

        public event PropertyChangedEventHandler PropertyChanged = delegate { };
        private void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }

    }

this is Model Class :

public class SainaAccessEntity : INotifyPropertyChanged
    {
        private string _TableName;

        public string TableName
        {
            get { return _TableName; }
            set
            {
                if (value != _TableName)
                {
                    _TableName = value;
                    OnPropertyChanged();
                }
            }
        }

        public event PropertyChangedEventHandler PropertyChanged = delegate { };
        private void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }

Custom Data Grid View:

public class MyDataGrid : DataGrid
{
    public MyDataGrid()
    {
        var x = new ObservableCollection<Person> { new Person { Name = "Ali", Family = "Jalilvand" } };
    }
    public SainaAccessEntity SainaAccessEntity
    {
        get { return (SainaAccessEntity)GetValue(SainaAccessEntityProperty); }
        set { SetValue(SainaAccessEntityProperty, value); }
    }
    public static readonly DependencyProperty SainaAccessEntityProperty =
        DependencyProperty.Register("SainaAccessEntity", typeof(SainaAccessEntity), typeof(MyDataGrid), new PropertyMetadata(null, SainaAccessEntity_Changed));

    private static void SainaAccessEntity_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var u = d as MyDataGrid;
        if (u.SainaAccessEntity.TableName == "Person")
        {
            u.ItemsSource = new ObservableCollection<Person> { new Person { Name = "Ali", Family = "Bayat" } };
        }
        else
        {
            u.ItemsSource = new ObservableCollection<Car1> { new Car1 { Name = "BMW", Model = "518",Color="Red" } };
        }

    }

}

Car And Person Model:

public class Car1
{
    public string Model { get; set; }
    public string Name { get; set; }
    public string Color { get; set; }

}

public class Person
{
    public string Name { get; set; }
    public string Family { get; set; }
}

Main Window XAML:

<Window x:Class="TestWpfApplication.GridViewWindow"
        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:TestWpfApplication"
        mc:Ignorable="d"
        Title="GridViewWindow" Height="300" Width="300">
    <Window.Resources>
        <local:GridViewWindowViewModel x:Key="Vm"/>
    </Window.Resources>
    <Grid DataContext="{StaticResource Vm}">
        <Grid.RowDefinitions>
            <RowDefinition Height="*"/>
            <RowDefinition Height="auto"/>
        </Grid.RowDefinitions>
        <local:MyDataGrid  VerticalAlignment="Top" SainaAccessEntity="{Binding SainaAccessEntity, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
        <ComboBox Margin="0,5.694,0,0" Grid.Row="1" ItemsSource="{Binding Tables, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" SelectedItem="{Binding SainaAccessEntity.TableName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"></ComboBox>
    </Grid>
</Window>

How to Update DataGrid ItemsSource when change its Property? I have Custom DataGrid in WPF, it has a Property that define table name, and I want to dynamically change ItamsSource, when change this Property...


Solution

  • The SainaAccessEntity property of your custom DataGrid is bound to the SainaAccessEntity property of the view model but you never set this property when the selection in the ComboBox changes.

    The Tables property of the view model should return an ObservableCollection<SainaAccessEntity> instead of an ObservableCollection<string>:

    public class GridViewWindowViewModel : INotifyPropertyChanged
    {
        public GridViewWindowViewModel()
        {
            Tables = new ObservableCollection<SainaAccessEntity>
                {
                    new SainaAccessEntity { TableName = "Person" },
                    new SainaAccessEntity { TableName = "Car" },
                };
            SainaAccessEntity = Tables[0];
        }
    
        private SainaAccessEntity _SainaAccessEntity;
    
        public SainaAccessEntity SainaAccessEntity
        {
            get { return _SainaAccessEntity; }
            set
            {
                if (_SainaAccessEntity != value)
                {
                    _SainaAccessEntity = value;
                    OnPropertyChanged();
                }
            }
        }
    
        private ObservableCollection<SainaAccessEntity> _Tables;
        public ObservableCollection<SainaAccessEntity> Tables
        {
            get { return _Tables; }
            set
            {
                if (_Tables != value)
                {
                    _Tables = value;
                    OnPropertyChanged();
                }
            }
        }
    
        public event PropertyChangedEventHandler PropertyChanged = delegate { };
        private void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
    

    You should then bind the SelectedItem property of the ComboBox to the SainaAccessEntity property of the view model and set the DisplayMemberPath property of the ComboBox to "TableName":

    <ComboBox Margin="0,5.694,0,0" Grid.Row="1" ItemsSource="{Binding Tables, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" 
                      SelectedItem="{Binding SainaAccessEntity, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
                      DisplayMemberPath="TableName"></ComboBox>
    

    With these changes the ItemsSource of the DataGrid should be changed as expected when you select an item in the ComboBox.