Wpf:如何从嵌套的 DataGrid 中绑定 SelectedItem
Wpf: How to bind SelectedItem from nested DataGrid
我不知道如何从嵌套的 DataGrid 中正确绑定 SelectedItem。在主 DataGrid 中,我有这样的绑定:
SelectedItem="{Binding SelectedElement}"
它工作正常 - 如果我 select element 在 DataGrid 属性 SelectedElement 来自 MainVM class 设置为 selected 元素。
我在嵌套的 DataGrid 中有一个类似的绑定:
SelectedItem="{Binding SelectedMyItem}"
但它根本不起作用 - 当我在嵌套 DataGrid 中 select item 时,属性 SelectedMyItem 仍然是 null.
我的问题:
我如何绑定 SelectedMyItem 属性 以便在 DataGrid 中 selecting 项目之后设置它?
我没有从 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>
在我看来,您可以将绑定触发器修改为开启 PropertyChanged
:
SelectedItem="{Binding SelectedMyItem, UpdateSourceTrigger=PropertyChanged}"
但是,请注意:
当我在调试器中 运行 这样做时,嵌套的 DataGrid 选择在外部 DataGrid 之前触发。这意味着 SelectedMyItem
的 set
将在 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>
我不知道如何从嵌套的 DataGrid 中正确绑定 SelectedItem。在主 DataGrid 中,我有这样的绑定:
SelectedItem="{Binding SelectedElement}"
它工作正常 - 如果我 select element 在 DataGrid 属性 SelectedElement 来自 MainVM class 设置为 selected 元素。 我在嵌套的 DataGrid 中有一个类似的绑定:
SelectedItem="{Binding SelectedMyItem}"
但它根本不起作用 - 当我在嵌套 DataGrid 中 select item 时,属性 SelectedMyItem 仍然是 null.
我的问题:
我如何绑定 SelectedMyItem 属性 以便在 DataGrid 中 selecting 项目之后设置它?
我没有从 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>
在我看来,您可以将绑定触发器修改为开启 PropertyChanged
:
SelectedItem="{Binding SelectedMyItem, UpdateSourceTrigger=PropertyChanged}"
但是,请注意:
当我在调试器中 运行 这样做时,嵌套的 DataGrid 选择在外部 DataGrid 之前触发。这意味着 SelectedMyItem
的 set
将在 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>