我的问题:如何将SelectedItem从主数据网格绑定到辅助数据网格的ItemsSource?
详细说明: 我的观点中有两个数据网格。第一个显示团队的集合,第二个显示为所选团队中的人员列表。
当我从网格中选择一个团队时,我可以看到 SelectedTeam 属性正在正确更新,但人员网格没有被填充。
注意:我无法使用嵌套网格或SL数据网格中提供的很酷的主要细节功能。
UPDATE:使用ComboBox替换父数据网格会产生完全不同的结果,并且运行正常。 为什么ComboBox.SelectedItem和DataGrid.SelectedItem的行为如此不同?
谢谢,
标记
Simple Repro:
查看:
<UserControl x:Class="NestedDataGrid.MainPage"
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"
mc:Ignorable="d"
xmlns:data="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data">
<StackPanel x:Name="LayoutRoot">
<TextBlock Text="Teams:" />
<data:DataGrid ItemsSource="{Binding Teams}"
SelectedItem="{Binding SelectedTeam, Mode=TwoWay}"
AutoGenerateColumns="False">
<data:DataGrid.Columns>
<data:DataGridTextColumn Header="Id" Binding="{Binding TeamId}" />
<data:DataGridTextColumn Header="Desc" Binding="{Binding TeamDesc}" />
</data:DataGrid.Columns>
</data:DataGrid>
<TextBlock Text="Peeps:" />
<data:DataGrid ItemsSource="{Binding SelectedTeam.People}"
AutoGenerateColumns="False">
<data:DataGrid.Columns>
<data:DataGridTextColumn Header="Id"
Binding="{Binding PersonId}" />
<data:DataGridTextColumn Header="Name"
Binding="{Binding Name}" />
</data:DataGrid.Columns>
</data:DataGrid>
</StackPanel>
</UserControl>
CODE_BEHIND:
using System.Windows.Controls;
namespace NestedDataGrid
{
public partial class MainPage : UserControl
{
public MainPage()
{
InitializeComponent();
this.LayoutRoot.DataContext = new ViewModel();
}
}
}
视图模型:
using System.Collections.ObjectModel;
namespace NestedDataGrid
{
public class ViewModel: ObjectBase
{
public ViewModel()
{
ObservableCollection<Person> RainbowPeeps = new ObservableCollection<Person>()
{
new Person(){ PersonId=1, Name="George"},
new Person(){ PersonId=2, Name="Zippy"},
new Person(){ PersonId=3, Name="Bungle"},
};
ObservableCollection<Person> Simpsons = new ObservableCollection<Person>()
{
new Person(){ PersonId=4, Name="Moe"},
new Person(){ PersonId=5, Name="Barney"},
new Person(){ PersonId=6, Name="Selma"},
};
ObservableCollection<Person> FamilyGuyKids = new ObservableCollection<Person>()
{
new Person(){ PersonId=7, Name="Stewie"},
new Person(){ PersonId=8, Name="Meg"},
new Person(){ PersonId=9, Name="Chris"},
};
Teams = new ObservableCollection<Team>()
{
new Team(){ TeamId=1, TeamDesc="Rainbow", People=RainbowPeeps},
new Team(){ TeamId=2, TeamDesc="Simpsons", People=Simpsons},
new Team(){ TeamId=3, TeamDesc="Family Guys", People=FamilyGuyKids },
};
}
private ObservableCollection<Team> _teams;
public ObservableCollection<Team> Teams
{
get { return _teams; }
set
{
SetValue(ref _teams, value, "Teams");
}
}
private Team _selectedTeam;
public Team SelectedTeam
{
get { return _selectedTeam; }
set
{
SetValue(ref _selectedTeam, value, "SelectedTeam");
}
}
}
}
相关课程:
using System;
using System.ComponentModel;
namespace NestedDataGrid
{
public abstract class ObjectBase : Object, INotifyPropertyChanged
{
public ObjectBase()
{ }
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void _OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler pceh = PropertyChanged;
if (pceh != null)
{
pceh(this, new PropertyChangedEventArgs(propertyName));
}
}
protected virtual bool SetValue<T>(ref T target, T value, string propertyName)
{
if (Object.Equals(target, value))
{
return false;
}
target = value;
_OnPropertyChanged(propertyName);
return true;
}
}
public class Person: ObjectBase
{
private int _personId;
public int PersonId
{
get { return _personId; }
set
{
SetValue(ref _personId, value, "PersonId");
}
}
private string _name;
public string Name
{
get { return _name; }
set
{
SetValue(ref _name, value, "Name");
}
}
}
public class Team : ObjectBase
{
private int _teamId;
public int TeamId
{
get { return _teamId; }
set
{
SetValue(ref _teamId, value, "TeamId");
}
}
private string _teamDesc;
public string TeamDesc
{
get { return _teamDesc; }
set
{
SetValue(ref _teamDesc, value, "TeamDesc");
}
}
private ObservableCollection<Person> _people;
public ObservableCollection<Person> People
{
get { return _people; }
set
{
SetValue(ref _people, value, "People");
}
}
}
}
更新
用组合框和eveything替换第一个数据网格可以正常工作。为什么DataGrid.SelectedItem和ComboBox.SelectedItem的行为如此不同?
<StackPanel x:Name="LayoutRoot">
<TextBlock Text="Teams:" />
<ComboBox SelectedItem="{Binding SelectedTeam, Mode=TwoWay}"
ItemsSource="{Binding Teams}"/>
<TextBlock Text="{Binding SelectedTeam}" />
<TextBlock Text="Peeps:" />
<data:DataGrid ItemsSource="{Binding SelectedTeam.People}" />
</StackPanel>
答案 0 :(得分:1)
做了一些测试。
首先,我只想确认Binding本身是否正常工作。当为ListBox换出第二个DataGrid时,它非常有用。到目前为止,我已经确认第二个DataGrid的绑定引擎改变了其ItemsSource属性。
我还为ListBox换出了第一个DataGrid,然后第二个DataGrid开始工作得很开心。
此外,如果您在第一个数据网格上连接SelectionChanged事件并使用代码直接分配给第二个数据网格,它就会开始工作。
我还删除了第一个Grid上的SelectedItem绑定,并从第二个Grid的ItemsSource属性上设置了一个ElementToElement绑定。仍然没有快乐。
因此,问题通过框架绑定引擎缩小到一个DatGrid上的SelectedItem和另一个的ItemsSource。
Reflector提供了一条可能的线索。 Data
命名空间包含一个Extensions静态类,其目标是DependencyObject
,其AreHandlersSuspended
方法由静态变量支持。代码处理更改为ItemsSource属性的方法使用此方法,如果返回true则不执行任何操作。
我未经证实的怀疑是,在第一个Grid分配其SelectedItem属性的过程中,它已打开标志以避免无限循环。但是,由于此标志实际上是全局的,因此不会执行因此SelectedItem赋值而运行的任何其他合法代码。
任何人都有SL4和花式测试吗? 任何潜伏的MSFT人都想看看?
如果SL4仍然拥有它,则需要向Connect报告错误。
答案 1 :(得分:1)
更好的解决方案是使用add DataGridRowSelected命令。这比我之前的鼠标点击示例更适合MVVM模式。
这受到John Papa的一些代码的启发,我已经创建了一篇关于此http://thoughtjelly.blogspot.com/2009/12/binding-selecteditem-to-itemssource.html的详细信息。
[坐下来满足并点燃一支雪茄]
标记
答案 2 :(得分:1)
我遇到了同样的问题,并通过将其添加到我的代码隐藏中来“修复”它。
代码背后:
private void DataGrid_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (_model != null)
{
_model.RefreshDetail();
}
}
型号:
public void RefreshDetail()
{
RaisePropertyChanged("Detail");
}
答案 3 :(得分:0)
我有一个解决方法。它涉及一些代码背后,所以不会受到纯粹的MVVM狂热者的青睐! ; - )
<StackPanel x:Name="LayoutRoot">
<TextBlock Text="Teams:" />
<data:DataGrid x:Name="dgTeams"
SelectedItem="{Binding SelectedTeam, Mode=TwoWay}"
ItemsSource="{Binding Teams}" />
<TextBlock Text="{Binding SelectedTeam}" />
<TextBlock Text="Peeps:" />
<data:DataGrid x:Name="dgPeeps" />
</StackPanel>
代码背后:
public partial class MainPage : UserControl
{
public MainPage()
{
InitializeComponent();
this.LayoutRoot.DataContext = new ViewModel();
dgTeams.MouseLeftButtonUp += new MouseButtonEventHandler(dgTeams_MouseLeftButtonUp)
}
void dgTeams_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
DataGridRow row = DependencyObjectHelper.FindParentOfType<DataGridRow>(e.OriginalSource as DependencyObject);
///get the data object of the row
if (row != null && row.DataContext is Team)
{
dgPeeps.ItemsSource = (row.DataContext as Team).People;
}
}
}
FindParentOfType 方法详见:http://thoughtjelly.blogspot.com/2009/09/walking-xaml-visualtree-to-find-parent.html。
希望这有助于其他人。