我有两个简单的模型类和一个ViewModel...
public class GridItem
{
public string Name { get; set; }
public int CompanyID { get; set; }
}
public class CompanyItem
{
public int ID { get; set; }
public string Name { get; set; }
}
public class ViewModel
{
public ViewModel()
{
GridItems = new ObservableCollection<GridItem>() {
new GridItem() { Name = "Jim", CompanyID = 1 } };
CompanyItems = new ObservableCollection<CompanyItem>() {
new CompanyItem() { ID = 1, Name = "Company 1" },
new CompanyItem() { ID = 2, Name = "Company 2" } };
}
public ObservableCollection<GridItem> GridItems { get; set; }
public ObservableCollection<CompanyItem> CompanyItems { get; set; }
}
...and a simple Window:
<Window x:Class="DataGridComboBoxColumnApp.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<DataGrid AutoGenerateColumns="False" ItemsSource="{Binding GridItems}" >
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding Name}" />
<DataGridComboBoxColumn ItemsSource="{Binding CompanyItems}"
DisplayMemberPath="Name"
SelectedValuePath="ID"
SelectedValueBinding="{Binding CompanyID}" />
</DataGrid.Columns>
</DataGrid>
</Grid>
</Window>
在App.xaml.cs中将ViewModel设置为主窗口的DataContext
:
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
MainWindow window = new MainWindow();
ViewModel viewModel = new ViewModel();
window.DataContext = viewModel;
window.Show();
}
}
如您所见,我将DataGrid的ItemsSource
设置为ViewModel的GridItems
集合。此部件正常工作时,将显示名为"Jim“的单一网格线。
我还希望将每一行中ComboBox的ItemsSource
设置为ViewModel的CompanyItems
集合。此部分不起作用: ComboBox保持为空,并且在调试器输出窗口中我看到一条错误消息:
System.Windows.Data错误:2:找不到目标元素的管理FrameworkElement或FrameworkContentElement。BindingExpression:Path=CompanyItems;DataItem=null;目标元素为'DataGridComboBoxColumn‘(HashCode=28633162);目标属性为'ItemsSource’(类型为'IEnumerable')
我相信WPF希望CompanyItems
是GridItem
的一个属性,但事实并非如此,这就是绑定失败的原因。
我已经尝试使用RelativeSource
和AncestorType
,如下所示:
<DataGridComboBoxColumn ItemsSource="{Binding CompanyItems,
RelativeSource={RelativeSource Mode=FindAncestor,
AncestorType={x:Type Window}}}"
DisplayMemberPath="Name"
SelectedValuePath="ID"
SelectedValueBinding="{Binding CompanyID}" />
但这在调试器输出中给出了另一个错误:
System.Windows.Data错误:4:无法找到具有引用'RelativeSource FindAncestor,AncestorType='System.Windows.Window',AncestorLevel=‘1’的绑定源。BindingExpression:Path=CompanyItems;DataItem=null;目标元素为'DataGridComboBoxColumn‘(HashCode=1150788);目标属性为'ItemsSource’(类型为'IEnumerable')
问题:如何将DataGridComboBoxColumn的ItemsSource绑定到ViewModel的CompanyItems集合?这有可能吗?
提前感谢您的帮助!
发布于 2011-03-24 02:37:24
请检查下面的DataGridComboBoxColumn xaml是否适用于您:
<DataGridComboBoxColumn
SelectedValueBinding="{Binding CompanyID}"
DisplayMemberPath="Name"
SelectedValuePath="ID">
<DataGridComboBoxColumn.ElementStyle>
<Style TargetType="{x:Type ComboBox}">
<Setter Property="ItemsSource" Value="{Binding Path=DataContext.CompanyItems, RelativeSource={RelativeSource AncestorType={x:Type Window}}}" />
</Style>
</DataGridComboBoxColumn.ElementStyle>
<DataGridComboBoxColumn.EditingElementStyle>
<Style TargetType="{x:Type ComboBox}">
<Setter Property="ItemsSource" Value="{Binding Path=DataContext.CompanyItems, RelativeSource={RelativeSource AncestorType={x:Type Window}}}" />
</Style>
</DataGridComboBoxColumn.EditingElementStyle>
</DataGridComboBoxColumn>
在这里,您可以找到针对您所面临问题的另一种解决方案:Using combo boxes with the WPF DataGrid
发布于 2011-03-24 04:22:32
documentation on MSDN about the ItemsSource
of the DataGridComboBoxColumn
表示只有静态资源、静态代码或组合框项目的内联集合才能绑定到ItemsSource
若要填充下拉列表,请首先使用以下选项之一设置ComboBox的ItemsSource属性:
如果我理解正确的话,绑定到DataContext的属性是不可能的。
事实上:当我在ViewModel中将CompanyItems
设置为静态属性时……
public static ObservableCollection<CompanyItem> CompanyItems { get; set; }
..。将ViewModel所在的命名空间添加到窗口...
xmlns:vm="clr-namespace:DataGridComboBoxColumnApp"
..。并将绑定更改为...
<DataGridComboBoxColumn
ItemsSource="{Binding Source={x:Static vm:ViewModel.CompanyItems}}"
DisplayMemberPath="Name"
SelectedValuePath="ID"
SelectedValueBinding="{Binding CompanyID}" />
..。然后它就起作用了。但是,将ItemsSource作为静态属性有时可能是可以的,但这并不总是我想要的。
发布于 2015-01-29 12:46:12
正确的解决方案似乎是:
<Window.Resources>
<CollectionViewSource x:Key="ItemsCVS" Source="{Binding MyItems}" />
</Window.Resources>
<!-- ... -->
<DataGrid ItemsSource="{Binding MyRecords}">
<DataGridComboBoxColumn Header="Column With Predefined Values"
ItemsSource="{Binding Source={StaticResource ItemsCVS}}"
SelectedValueBinding="{Binding MyItemId}"
SelectedValuePath="Id"
DisplayMemberPath="StatusCode" />
</DataGrid>
上面的布局对我来说工作得很好,应该也适用于其他人。这种设计选择也是有意义的,尽管在任何地方都没有得到很好的解释。但是,如果您的数据列包含预定义的值,则这些值在运行时通常不会更改。因此,创建一个CollectionViewSource
并初始化数据一次是有意义的。它还摆脱了较长的绑定来查找祖先并绑定到它的数据上下文(我一直觉得这是错误的)。
我把这篇文章留给那些为这个绑定而苦苦挣扎的人,并想知道是否有更好的方法(因为这个页面显然还会出现在搜索结果中,这就是我来到这里的原因)。
https://stackoverflow.com/questions/5409259
复制相似问题