使用 TemplateColumns 将 WPF DataGrid 绑定到 DataTable
Posted
技术标签:
【中文标题】使用 TemplateColumns 将 WPF DataGrid 绑定到 DataTable【英文标题】:Binding WPF DataGrid to DataTable using TemplateColumns 【发布时间】:2011-02-10 06:29:42 【问题描述】:我已经尝试了所有方法,但一无所获,所以我希望有人能给我带来欢呼的时刻。 我根本无法通过绑定成功拉取数据网格中的数据。
我有一个包含多个 MyDataType 列的 DataTable
public class MyData
string nameData get;set;
bool showData get;set;
MyDataType 有 2 个属性(一个字符串,一个布尔值) 我创建了一个测试数据表
DataTable GetDummyData()
DataTable dt = new DataTable("Foo");
dt.Columns.Add(new DataColumn("AnotherColumn", typeof(MyData)));
dt.Rows.Add(new MyData("Row1C1", true));
dt.Rows.Add(new MyData("Row2C1", false));
dt.AcceptChanges();
return dt;
我有一个 WPF DataGrid,我想显示我的 DataTable。 但我想要做的就是更改每个单元格的呈现方式,以显示每个单元格的 [TextBlock][Button] 值绑定到 MyData 对象,这就是我遇到麻烦的地方。
我的 XAML 看起来像这样
<Window.Resources>
<ResourceDictionary>
<DataTemplate x:Key="MyDataTemplate" DataType="MyData">
<StackPanel Orientation="Horizontal" >
<Button Background="Green" HorizontalAlignment="Right" VerticalAlignment="Center" Margin="5,0,0,0" Content="Binding Path=nameData"></Button>
<TextBlock Background="Green" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="5,0,0,0" Text="Binding Path=nameData"></TextBlock>
</StackPanel>
</DataTemplate>
</ResourceDictionary>
</Window.Resources>
<Grid>
<dg:DataGrid Grid.Row="1" ItemsSource="Binding" AutoGenerateColumns="True"
x:Name="dataGrid1" SelectionMode="Single" CanUserAddRows="False"
CanUserSortColumns="true" CanUserDeleteRows="False" AlternatingRowBackground="AliceBlue"
AutoGeneratingColumn="dataGrid1_AutoGeneratingColumn" />
</Grid>
现在我加载后所做的就是尝试将 DataTable 绑定到 WPF DataGrid
dt = GetDummyData();
dataGrid1.ItemsSource = dt.DefaultView;
TextBlock 和 Button 出现了,但它们没有绑定,因此它们是空白的。
任何人都可以让我知道他们是否知道如何解决这个问题。
这应该很简单,这就是微软让我们相信的。
我在AutoGenerating
事件期间设置了Column.CellTemplate
,但仍然没有绑定。
请帮忙!!!
【问题讨论】:
您是否尝试将 GetDummyData 中的数据表设置为 DataGrid.DataContext? 已经做过而且还是一样。 UIElements 上没有任何变化,因为它们似乎未绑定。我尝试使用 AutoGeneratingColumn 事件来设置我自己的 Column.CellTemplate ,但仍然没有。还有其他想法吗?谢谢谢谢 试试这个:C# Read Excel and Show in WPF DataGrid 【参考方案1】:编辑:更新以反映 Aran Mulholland 的意见(见评论)
显然DataGrid
将整个DataRowView
传递给每个单元格。这就是绑定不起作用的原因。您的DataTemplate
期望DataContext
的类型为MyData
,但实际上它的类型为DataRowView
。我提出的(有点骇人听闻的)解决方法是创建一个自定义的DataGridTemplateColumn
,以从DataRowView
中提取必要的项目。代码如下:
<Window x:Class="DataGridTemplateColumnSample.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:dg="clr-namespace:Microsoft.Windows.Controls;assembly=WPFToolkit"
Title="Window1" Height="300" Width="300">
<Window.Resources>
<ResourceDictionary>
<DataTemplate x:Key="MyDataTemplate" DataType="DataRowView">
<StackPanel Orientation="Horizontal">
<Button Background="Green" HorizontalAlignment="Right" VerticalAlignment="Center" Margin="5,0,0,0" Content="Binding Path=nameData"></Button>
<TextBlock Background="Green" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="5,0,0,0" Text="Binding Path=nameData"></TextBlock>
</StackPanel>
</DataTemplate>
</ResourceDictionary>
</Window.Resources>
<Grid>
<dg:DataGrid Grid.Row="1" AutoGenerateColumns="True" x:Name="dataGrid1" SelectionMode="Single"
CanUserAddRows="False" CanUserSortColumns="true" CanUserDeleteRows="False"
AlternatingRowBackground="AliceBlue" AutoGeneratingColumn="dataGrid1_AutoGeneratingColumn"
ItemsSource="Binding" VirtualizingStackPanel.VirtualizationMode="Standard" />
</Grid>
</Window>
using System.Data;
using System.Windows;
using Microsoft.Windows.Controls;
namespace DataGridTemplateColumnSample
public partial class Window1
public Window1()
InitializeComponent();
DataContext = GetDummyData().DefaultView;
private static DataTable GetDummyData()
var dt = new DataTable("Foo");
dt.Columns.Add(new DataColumn("OneColumn", typeof(MyData)));
dt.Columns.Add(new DataColumn("AnotherColumn", typeof(MyData)));
dt.Rows.Add(new MyData("Row1C1", true), new MyData("Row1C2", true));
dt.Rows.Add(new MyData("Row2C1", false), new MyData("Row2C2", true));
dt.AcceptChanges();
return dt;
private void dataGrid1_AutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e)
var column = new DataRowColumn(e.PropertyName);
column.Header = e.Column.Header;
column.CellTemplate = (DataTemplate)Resources["MyDataTemplate"];
e.Column = column;
public class DataRowColumn : DataGridTemplateColumn
public DataRowColumn(string column) ColumnName = column;
public string ColumnName get; private set;
protected override FrameworkElement GenerateElement(DataGridCell cell, object dataItem)
var row = (DataRowView) dataItem;
var item = row[ColumnName];
cell.DataContext = item;
var element = base.GenerateElement(cell, item);
return element;
public class MyData
public MyData(string name, bool data) nameData = name; showData = data;
public string nameData get; set;
public bool showData get; set;
注意:这种方法似乎只适用于关闭或处于标准模式的容器虚拟化。如果VirtualizationMode 设置为回收,则不会应用模板。
【讨论】:
数据网格将行传递给每一列以生成单元格,这是标准行为,列上的绑定定义了单元格的内容。我认为您的问题是您在代码上做所有事情。你有动态数量的列吗?如果不只是在 xaml 中设置列及其绑定。 我同意。如果这是我的项目,我会尽量避免以这种方式做事。不幸的是,项目要求(例如动态列)有时并没有给您留下太多空间来以“干净”的方式做事。 哦,哇。惊人的。它有效..谢谢。这100%回答了这个问题。我已经弄清楚这是被传递的行,但无法弄清楚如何到达该视图中要绑定的项目。非常感谢。不幸的是,在事先不知道数据的情况下,我看不出你会如何避免以这种方式做事。这有点违背了拥有与非库存列一起使用的灵活数据网格的目标。为数据类型为非库存列类型的实例定义您自己的 DataTemplateColumn,我原以为可以直接使用。我猜我可以做梦。【参考方案2】:在找到这个线程并遇到这里显示的代码问题后,我在 MSDN 上遇到了这个线程,它工作得更好!据我所知,根本没有虚拟化问题。
http://social.msdn.microsoft.com/Forums/en/wpf/thread/8b2e94b7-3c44-4642-8acc-851de5285062
代码:
private void dataGrid1_AutoGeneratingColumn(object sender, Microsoft.Windows.Controls.DataGridAutoGeneratingColumnEventArgs e)
if (e.PropertyType == typeof(MyData))
MyDataGridTemplateColumn col = new MyDataGridTemplateColumn();
col.ColumnName = e.PropertyName; // so it knows from which column to get MyData
col.CellTemplate = (DataTemplate)FindResource("MyDataTemplate");
e.Column = col;
e.Column.Header = e.PropertyName;
public class MyDataGridTemplateColumn : DataGridTemplateColumn
public string ColumnName
get;
set;
protected override System.Windows.FrameworkElement GenerateElement(DataGridCell cell, object dataItem)
// The DataGridTemplateColumn uses ContentPresenter with your DataTemplate.
ContentPresenter cp = (ContentPresenter)base.GenerateElement(cell, dataItem);
// Reset the Binding to the specific column. The default binding is to the DataRowView.
BindingOperations.SetBinding(cp, ContentPresenter.ContentProperty, new Binding(this.ColumnName));
return cp;
【讨论】:
以上是关于使用 TemplateColumns 将 WPF DataGrid 绑定到 DataTable的主要内容,如果未能解决你的问题,请参考以下文章
WPF:仅将使用“AddFontMemResourceEx”安装的字体用于进程
C# WPF 想要将数据存储在一个类中,并在不同 wpf 窗口中的多个不同类中使用