Home > Back-end >  Wpf: How to bind SelectedItem from nested DataGrid
Wpf: How to bind SelectedItem from nested DataGrid

Time:10-22

I don't know how to properly bind SelectedItem from a nested DataGrid. In the main DataGrid I have a binding like this:

SelectedItem="{Binding SelectedElement}"

and it work OK - if I select element in DataGrid property SelectedElement from MainVM class is set to the selected element. I have a similar binding in the nested DataGrid:

SelectedItem="{Binding SelectedMyItem}"

but it doesn't work at all - when I select item in nested DataGrid, property SelectedMyItem is still null.

My question:
How do I bind the SelectedMyItem property so that it is set after selecting item in the DataGrid?

I am not getting any bind error information from the IDE.

Here is a simple example showing my problem:

Classes:

using System.Collections.ObjectModel;

namespace NesteGridMVVM
{
    public class MyItem
    {
        public string MyItemName { get; set; }
    }
    
    //======================================================================
    
    public class Element
    {
        private MyItem _selectedItem;

        public string ElementName { get; set; }
        public ObservableCollection<MyItem> MyItemsList { get; set; } = new ObservableCollection<MyItem>();

        //Binded to SelectedItem in nested DataGrid
        public MyItem SelectedMyItem
        {
            get => _selectedItem;
            set
            {
                _selectedItem = value;

                //Show, if MyItem was selected - it not work.
                System.Diagnostics.Debug.Print($"Selected MyItem: {_selectedItem.MyItemName}");
            }
        }
    }
    
    //======================================================================

    public class MainVM
    {
        private Element _selectedElement;

        public ObservableCollection<Element> ElementsList { get; set; } = new ObservableCollection<Element>();

        //Binded to SelectedItem in main DataGrid
        public Element SelectedElement
        {
            get => _selectedElement;
            set
            {
                _selectedElement = value;

                //Show, if Element was selected - it works OK
                System.Diagnostics.Debug.Print($"{_selectedElement.ElementName}");
            }
        }

        //ctor - populate view model
        public MainVM()
        {
            Element elem1 = new Element() { ElementName = "element-01" };
            Element elem2 = new Element() { ElementName = "element-02" };

            elem1.MyItemsList.Add(new MyItem() { MyItemName = "item-A" });
            elem1.MyItemsList.Add(new MyItem() { MyItemName = "item-B" });
            elem2.MyItemsList.Add(new MyItem() { MyItemName = "item-C" });

            ElementsList.Add(elem1);
            ElementsList.Add(elem2);
        }
    }
}

XAML:

<Window x:Class="NesteGridMVVM.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:NesteGridMVVM"
        mc:Ignorable="d"
        Title="MainWindow" Height="550" Width="600">

    <Window.DataContext>
        <local:MainVM /> 
    </Window.DataContext>

    <DataGrid
        x:Name="MainDG"
        ItemsSource="{Binding ElementsList}"
        AutoGenerateColumns="True"
        SelectedItem="{Binding SelectedElement}"
        RowDetailsVisibilityMode="Visible">
        <DataGrid.RowDetailsTemplate>
            <DataTemplate>
                <DataGrid
                    x:Name="NestedDG"
                    ItemsSource="{Binding MyItemsList}"
                    AutoGenerateColumns="True"
                    SelectedItem="{Binding SelectedMyItem}">
                </DataGrid>
            </DataTemplate>
        </DataGrid.RowDetailsTemplate>
    </DataGrid>
</Window>

CodePudding user response:

Looks to me like you can modify the binding trigger to be on PropertyChanged:

SelectedItem="{Binding SelectedMyItem, UpdateSourceTrigger=PropertyChanged}"

However, just a note on this:

When I run this in the debugger, the nested DataGrid selection fires before the outer DataGrid. Meaning the set for SelectedMyItem will fire before SelectedElement. This is of course only when you are changing rows in the outer DataGrid.

The full .xaml:

<Window x:Class="NesteGridMVVM.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:NesteGridMVVM"
        mc:Ignorable="d"
        Title="MainWindow" Height="550" Width="600">

    <Window.DataContext>
        <local:MainVM /> 
    </Window.DataContext>

    <DataGrid
        x:Name="MainDG"
        ItemsSource="{Binding ElementsList}"
        AutoGenerateColumns="True"
        SelectedItem="{Binding SelectedElement}"
        RowDetailsVisibilityMode="Visible">
        <DataGrid.RowDetailsTemplate>
            <DataTemplate>
                <DataGrid
                    x:Name="NestedDG"
                    ItemsSource="{Binding MyItemsList}"
                    AutoGenerateColumns="True"
                    SelectedItem="{Binding SelectedMyItem, UpdateSourceTrigger=PropertyChanged}">
                </DataGrid>
            </DataTemplate>
        </DataGrid.RowDetailsTemplate>
    </DataGrid>
</Window>
  • Related