【问题标题】:Wpf: How to bind SelectedItem from nested DataGridWpf:如何从嵌套的 DataGrid 中绑定 SelectedItem
【发布时间】:2021-12-08 15:11:27
【问题描述】:

我不知道如何从嵌套的 DataGrid 中正确绑定 SelectedItem。在主 DataGrid 中,我有一个这样的绑定:

SelectedItem="{Binding SelectedElement}"

它工作正常 - 如果我在 MainVM 类的 DataGrid 属性 SelectedElement 中选择 element 设置为所选元素。 我在嵌套的 DataGrid 中有类似的绑定:

SelectedItem="{Binding SelectedMyItem}"

但它根本不起作用 - 当我在嵌套 DataGrid 中选择 item 时,属性 SelectedMyItem 仍然是 null

我的问题:
如何绑定 SelectedMyItem 属性,以便在 DataGrid 中选择项目后对其进行设置?

我没有从 IDE 获得任何绑定错误信息。

这是一个显示我的问题的简单示例:

类:

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>

【问题讨论】:

    标签: c# wpf xaml mvvm datagrid


    【解决方案1】:

    在我看来你可以将绑定触发器修改为PropertyChanged

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

    不过,请注意:

    当我在调试器中运行它时,嵌套的 DataGrid 选择在外部 DataGrid 之前触发。这意味着setSelectedMyItem 将在SelectedElement 之前触发。当然,这只是在您更改外部 DataGrid 中的行时。

    完整的.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>
    

    【讨论】:

    • 非常感谢。这正是我想要实现的,但我不明白为什么添加 UpdateSourceTrigger = PropertyChanged 可以解决问题?
    • @AdamMroczek 通常只是 WPF 的一个怪癖,很多时候在WPF 中,绑定的默认触发器是当您离开字段或LostFocus 时。我猜测内部 DataGrid 的问题在于,它们每个都有自己独立的可聚焦对象,即使您单击另一个也可以保持“聚焦”。如果您想要一个示例,请使用带有默认文本绑定的TextBox - 它不会触发,直到您点击/点击离开。将触发器更改为 PropertyChanged 会在您键入时触发。
    猜你喜欢
    • 2012-06-12
    • 2020-11-08
    • 1970-01-01
    • 2014-01-09
    • 2015-08-04
    • 2012-02-12
    • 1970-01-01
    • 1970-01-01
    • 2015-06-23
    相关资源
    最近更新 更多