问题描述
||
下面的人为例子说明了我的问题。
我的ViewModel:
public class MyViewModel : ViewModel
{
public MyViewModel()
{
var table = new DataTable(\"MyDatatable\");
table.Columns.Add(\"Some Val\",typeof(double));
table.Columns.Add(\"Ref\");
var row = table.NewRow();
row[\"Some Val\"] = 3.14;
row[\"Ref\"] = new {Title = \"My Title\",Description = \"My Description\"};
table.Rows.Add(row);
MyDataView = table.DefaultView;
}
DataView MyDataView { get; set; }
}
现在我的问题出在我的Xaml代码中。我希望我的列标题之一是“我的标题”,而对应的行值是“我的描述” ...
我的Xaml:
<DataGrid ItemsSource=\"MyDataView\" AutoGenerateColumns=\"False\">
<DataGrid.Columns>
<!--This column works fine. -->
<DataGridTextColumn Header=\"Some Val\" Binding=\"{Binding \'Some Val\'}\" Width=\"50\"/>
<!--This column doesn\'t work... I\'m looking for something similar to this: -->
<DataGridTextColumn Header=\"{Binding Path=\'Ref.Title\'}\" Binding=\"{Binding Path=\'Ref.Description\'}\"/>
</DataGrid.Columns>
</DataGrid>
这有意义吗?第二列标题应为\“ My Title \”,单元格值为\“ My Description \”。关于如何执行此操作的任何想法?
解决方法
我相信您的第二栏应该是:
<DataGridTextColumn Header=\"{Binding Path=[\'Ref\'].Title}\"
Binding=\"{Binding Path=[\'Ref\'].Description}\"/>
编辑:
好的,看起来DataGridTextColumn不会从DataGrid继承DataContext。实际上,它不是FrameworkElement或Freezable,因此它根本没有DataContext。
该列应适用于任何数量的行,即使您只有1行也是如此。对于所有行,标头都必须是通用的,而绑定是特定于行的。但是,您正在尝试将两者都绑定到第一行。
如果您实际上有两行标题不同,那么应该在标题中显示哪一行?
对于描述,以下工作:
public class Test {
public string Title { get; set; }
public string Description { get; set; }
}
public class MyViewModel {
public MyViewModel() {
var table = new DataTable(\"MyDatatable\");
table.Columns.Add(\"Some Val\",typeof(double));
table.Columns.Add(\"Ref\",typeof(Test));
var row = table.NewRow();
row[\"Some Val\"] = 3.14;
row[\"Ref\"] = new Test() { Title = \"My Title\",Description = \"My Description\" };
table.Rows.Add(row);
MyDataView = table.DefaultView;
}
public DataView MyDataView { get; set; }
}
XAML看起来像:
<DataGrid ItemsSource=\"{Binding MyDataView}\" AutoGenerateColumns=\"False\">
<DataGrid.Columns>
<DataGridTextColumn Header=\"Some Val\" Binding=\"{Binding \'Some Val\'}\" Width=\"50\" />
<DataGridTextColumn Header=\"Test\" Binding=\"{Binding Path=[Ref].Description}\" />
</DataGrid.Columns>
</DataGrid>
如果在定义列时删除了“ 5”部分,那么“ 6”将引用一个字符串,而不是Test类型的对象。因此,我认为您将无法使用匿名类型。
JP理查森(JP Richardson)编辑:
根据CodeNaked的回答,使我想起了一些以前我知道可以解决的问题,这些问题使我得以完全解决问题。
首先,可以绑定到匿名数据类型。代码修改应为:
table.Columns.Add(\"Ref\",typeof(object));
代替:
table.Columns.Add(\"Ref\");
如CodeNaked所述,如果没有typeof(object),则默认对象类型为字符串。
而且,如CodeNaked所述,DataGridTextColumn既不“知道”该行的DataContext也不知道该DataGrid。对于每个Window对象(typicall MVVM场景,只有一个),应具有以下代码:
private static void RegisterDataGridColumnsToDataContext() {
FrameworkElement.DataContextProperty.AddOwner(typeof(DataGridColumn));
FrameworkElement.DataContextProperty.OverrideMetadata(typeof(DataGrid),new FrameworkPropertyMetadata(null,FrameworkPropertyMetadataOptions.Inherits,new PropertyChangedCallback(OnDataContextChanged)));
}
public static void OnDataContextChanged(DependencyObject d,DependencyPropertyChangedEventArgs e) {
DataGrid grid = d as DataGrid;
if (grid != null)
foreach (DataGridColumn col in grid.Columns)
col.SetValue(FrameworkElement.DataContextProperty,e.NewValue);
}
然后在显示窗口之前调用\“ RegisterDataGridColumnsToDataContext()\”。
修改MyViewModel看起来像这样:
public class MyViewModel : ViewModelBase {
...
public string ColumnTitle { get { return \"My Title\"; } }
...
}
修改后的Xaml将如下所示:
<DataGrid ItemsSource=\"{Binding MyDataView}\" AutoGenerateColumns=\"False\">
<DataGrid.Columns>
<DataGridTextColumn Header=\"Some Val\" Binding=\"{Binding \'Some Val\'}\" Width=\"50\" />
<DataGridTextColumn Header=\"{Binding (FrameworkElement.DataContext).ColumnTitle,RelativeSource={x:Static RelativeSource.Self}}\" Binding=\"{Binding Path=[Ref].Description}\" />
</DataGrid.Columns>
</DataGrid>
注意:最初,我在每行中都有列标题的原因是,我想不出另一种方式将其绑定到DataGridTextColumn的\'Header \'属性。我正计划将每个匿名对象的\'Title \'属性设置为相同。幸运的是,互联网盛行。