使用TemplateColumn将WPF DataGrid绑定到DataTable [英] Binding WPF DataGrid to DataTable using TemplateColumns
问题描述
我根本无法获取绑定以成功获取datagrid中的数据。
我有一个包含MyDataType多个列的DataTable
public class MyData
{
string nameData {get; set;}
bool showData {get; set;
}
MyDataType有2个属性(一个字符串,一个布尔值)
我创建了一个测试DataTable
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对象,这是我遇到麻烦的地方。 p>
我的XAML看起来像这样
< Window.Resources>
< ResourceDictionary>
< DataTemplate x:Key =MyDataTemplateDataType =MyData>
< StackPanel Orientation =Horizontal>
< Button Background =GreenHorizontalAlignment =RightVerticalAlignment =CenterMargin =5,0,0,0Content ={Binding Path = nameData}>< / Button>
< TextBlock Background =GreenHorizontalAlignment =CenterVerticalAlignment =CenterMargin =5,0,0,0Text ={Binding Path = nameData}>< / TextBlock>
< / StackPanel>
< / DataTemplate>
< / ResourceDictionary>
< /Window.Resources>
< Grid>
< dg:DataGrid Grid.Row =1ItemsSource ={Binding}AutoGenerateColumns =True
x:Name =dataGrid1SelectionMode =SingleCanUserAddRows =False
CanUserSortColumns =trueCanUserDeleteRows =FalseAlternatingRowBackground =AliceBlue
AutoGeneratingColumn =dataGrid1_AutoGeneratingColumn/>
< / Grid>
现在我所做的一切加载都是试图将DataTable绑定到WPF DataGrid
dt = GetDummyData();
dataGrid1.ItemsSource = dt.DefaultView;
TextBlock和Button显示,但它们不绑定,这将使它们留空。
如果他们有任何想法如何解决这个问题,任何人都可以让我知道。
这应该很简单,那就是微软让我们相信的。
我在 AutoGenerating
事件中设置了 Column.CellTemplate
,但仍然没有绑定。
请帮助!!!
编辑:更新以反映Aran Mulholland的输入(见评论)
显然, DataGrid
正在传递整个 DataRowView
到每个单元格。这就是为什么绑定不起作用的原因。您的 DataTemplate
期望 DataContext
的类型为 MyData
而是它的类型为 DataRowView
。我想提出(有点hack-ish)解决方法来获取你想要的 DataContext
是创建一个自定义的 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 =Window1Height =300Width =300>
< Window.Resources>
< ResourceDictionary>
< DataTemplate x:Key =MyDataTemplateDataType =DataRowView>
< StackPanel Orientation =Horizontal>
< Button Background =GreenHorizontalAlignment =RightVerticalAlignment =CenterMargin =5,0,0,0Content ={Binding Path = nameData}>< / Button>
< TextBlock Background =GreenHorizontalAlignment =CenterVerticalAlignment =CenterMargin =5,0,0,0Text ={Binding Path = nameData}>< / TextBlock>
< / StackPanel>
< / DataTemplate>
< / ResourceDictionary>
< /Window.Resources>
< Grid>
< dg:DataGrid Grid.Row =1AutoGenerateColumns =Truex:Name =dataGrid1SelectionMode =Single
CanUserAddRows =FalseCanUserSortColumns =trueCanUserDeleteRows = False
AlternatingRowBackground =AliceBlueAutoGeneratingColumn =dataGrid1_AutoGeneratingColumn
ItemsSource ={Binding}VirtualizingStackPanel.VirtualizationMode =Standard/>
< / Grid>
< / Window>
System.Data;
使用System.Windows;
使用Microsoft.Windows.Controls;
命名空间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),新建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)资源[MyDataTemplate];
e.Column = column;
}
}
public class DataRowColumn:DataGridTemplateColumn
{
public DataRowColumn(string column){ColumnName = column; }
public string ColumnName {get;私人集合
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);
返回元素;
}
}
public class MyData
{
public MyData(string name,bool data){nameData = name; showData = data; }
public string nameData {get;组; }
public bool showData {get;组; }
}
}
注意:使用集装箱虚拟化或标准模式。如果 VirtualizationMode 设置为回收模板不适用。
I have tried everything and got nowhere so I'm hoping someone can give me the aha moment. I simply cannot get the binding to pull the data in the datagrid successfully.
I have a DataTable that contains multiple columns with of MyDataType
public class MyData
{
string nameData {get;set;}
bool showData {get;set;}
}
MyDataType has 2 properties (A string, a boolean) I have created a test DataTable
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;
}
I have a WPF DataGrid which I want to show my DataTable. But all I want to do is to change how each cell is rendered to show [TextBlock][Button] per cell with values bound to the MyData object and this is where I'm having a tonne of trouble.
My XAML looks like this
<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>
Now all I do once loaded is to attempt to bind the DataTable to the WPF DataGrid
dt = GetDummyData();
dataGrid1.ItemsSource = dt.DefaultView;
The TextBlock and Button show up, but they don't bind, which leaves them blank.
Could anyone let me know if they have any idea how to fix this.
This should be simple, thats what Microsoft leads us to believe.
I have set the Column.CellTemplate
during the AutoGenerating
event and still get no binding.
Please help!!!
Edit: Updated to reflect the input of Aran Mulholland (see comment)
Apparently the DataGrid
is passing the entire DataRowView
to each cell. That's why the binding doesn't work. Your DataTemplate
expects the DataContext
to be of type MyData
, but instead it is of type DataRowView
. My proposed (somewhat hack-ish) workaround to get the DataContext
you want is to create a custom DataGridTemplateColumn
that will extract the necessary item from the DataRowView
. The code is below:
<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; }
}
}
Note: This approach only appears to work with container virtualization off or in Standard mode. If the VirtualizationMode is set to Recycling the template is not applied.
这篇关于使用TemplateColumn将WPF DataGrid绑定到DataTable的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!