如何绑定自定义数据网格列
How to bind custom datagrid columns
我需要修改数据网格,使每一列 header 都有一个文本框、组合框和复选框,并且所有这些都必须绑定到一个 属性。我花了很多时间尝试使用默认的 DataGrid 来实现它,但我认为这是不可能的,所以我决定创建一个自定义的 DataGrid。
到目前为止,我有一个存储 DataTable
的可绑定 属性 BindableColumns
,所以我有需要显示的数据。问题是我不知道如何将该数据传递给 OnAutoGeneratedColumns
,因此我可以将列添加到 DataGrid
.
的 Columns
属性
public class BindableGrid : DataGrid
{
public DataTable BindableColumns
{
get { return (DataTable)GetValue(BindableColumnsProperty); }
set { SetValue(BindableColumnsProperty, value); }
}
public static readonly DependencyProperty BindableColumnsProperty =
DependencyProperty.Register("BindableColumns", typeof(DataTable), typeof(BindableGrid), new PropertyMetadata(null, BindableColumnsPropertyChanged));
private static void BindableColumnsPropertyChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
{
// This is where I get DataTable after binding
}
protected override void OnAutoGeneratedColumns(EventArgs e)
{
// This is where I need the DataTable to generate columns.
// I don't know how to invoke this method myself.
Columns.Add(new DataGridTemplateColumn
{
Header = "Test1",
HeaderTemplate = new DataTemplate()
});
}
}
和xaml:
<controls:BindableGrid ItemsSource="{Binding Data}" BindableColumns="{Binding Data}" AutoGenerateColumns="True">
</controls:BindableGrid>
编辑:
感谢@Ramin,我有了工作专栏。我在动态添加行时遇到了一些麻烦,因为 DataGrid
期望行作为 class 具有与列的绑定完全相同的变量名称。对于遇到问题的任何人,以下是我的解决方法:
for (var rowIndex = 0; rowIndex < data.Rows.Count; rowIndex++)
{
dynamic row = new ExpandoObject();
for (var i = 0; i < data.Columns.Count; i++)
// Create variables named after bindings, and assign values
((IDictionary<string, object>)row)[data.Columns[i].ColumnName.Replace(' ', '_')] = data.Rows[rowIndex].ItemArray[i];
// Add row to DataGrid
dg.Items.Add(row);
}
关于问题的根源,这里是一个带有模板化 header 的 DataGrid,其中包含一个文本框、组合框和一个复选框:
<DataGrid >
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding}" >
<DataGridTextColumn.HeaderTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBox Text="{Binding DataContext.Name, RelativeSource={RelativeSource AncestorType=DataGrid}}" />
<CheckBox IsChecked="{Binding DataContext.Value , RelativeSource={RelativeSource AncestorType=DataGrid}}"/>
<ComboBox ItemsSource="{Binding DataContext.Names , RelativeSource={RelativeSource AncestorType=DataGrid}}" SelectedIndex="0"/>
</StackPanel>
</DataTemplate>
</DataGridTextColumn.HeaderTemplate>
</DataGridTextColumn>
</DataGrid.Columns>
</DataGrid>
DataContext 正在使用自定义 class:
public MainWindow()
{
InitializeComponent();
DataContext = new MyClass() { Name = "Name0", Value = true, Names = new string[2] { "Name1", "Name2" } };
}
public class MyClass
{
public string Name { get; set; }
public bool Value { get; set; }
public string[] Names { get; set; }
}
编辑
您可以动态添加列:
public void addNewColumn(Header h, string bindcol)
{
DataGridColumn col = new DataGridTextColumn(){Binding=new Binding(bindcol)};
col.Header = h;
col.HeaderTemplate = (DataTemplate)FindResource("dgh") as DataTemplate;
dg.Columns.Add(col);
}
在App.xaml中:
<Application.Resources>
<DataTemplate x:Key="dgh">
<StackPanel Orientation="Horizontal">
<TextBox Text="{Binding Name}" />
<CheckBox IsChecked="{Binding Value}"/>
<ComboBox ItemsSource="{Binding Names}" SelectedIndex="0"/>
</StackPanel>
</DataTemplate>
</Application.Resources>
要测试(假设有一个名为 dg 的 DataGrid):
public MainWindow()
{
InitializeComponent();
var h1 = new Header()
{
Name = "Name0",
Value = true,
Names = new string[2] { "Name1", "Name2" }
};
var h2 = new Header()
{
Name = "Name1",
Value = true,
Names = new string[2] { "Name12", "Name22" }
};
addNewColumn(h1, "col1");
addNewColumn(h2, "col2");
}
public class Header
{
public string Name { get; set; }
public bool Value { get; set; }
public string[] Names { get; set; }
}
请注意 "col1" 和 "col2" 指的是数据网格的 ItemsSource。
我需要修改数据网格,使每一列 header 都有一个文本框、组合框和复选框,并且所有这些都必须绑定到一个 属性。我花了很多时间尝试使用默认的 DataGrid 来实现它,但我认为这是不可能的,所以我决定创建一个自定义的 DataGrid。
到目前为止,我有一个存储 DataTable
的可绑定 属性 BindableColumns
,所以我有需要显示的数据。问题是我不知道如何将该数据传递给 OnAutoGeneratedColumns
,因此我可以将列添加到 DataGrid
.
Columns
属性
public class BindableGrid : DataGrid
{
public DataTable BindableColumns
{
get { return (DataTable)GetValue(BindableColumnsProperty); }
set { SetValue(BindableColumnsProperty, value); }
}
public static readonly DependencyProperty BindableColumnsProperty =
DependencyProperty.Register("BindableColumns", typeof(DataTable), typeof(BindableGrid), new PropertyMetadata(null, BindableColumnsPropertyChanged));
private static void BindableColumnsPropertyChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
{
// This is where I get DataTable after binding
}
protected override void OnAutoGeneratedColumns(EventArgs e)
{
// This is where I need the DataTable to generate columns.
// I don't know how to invoke this method myself.
Columns.Add(new DataGridTemplateColumn
{
Header = "Test1",
HeaderTemplate = new DataTemplate()
});
}
}
和xaml:
<controls:BindableGrid ItemsSource="{Binding Data}" BindableColumns="{Binding Data}" AutoGenerateColumns="True">
</controls:BindableGrid>
编辑:
感谢@Ramin,我有了工作专栏。我在动态添加行时遇到了一些麻烦,因为 DataGrid
期望行作为 class 具有与列的绑定完全相同的变量名称。对于遇到问题的任何人,以下是我的解决方法:
for (var rowIndex = 0; rowIndex < data.Rows.Count; rowIndex++)
{
dynamic row = new ExpandoObject();
for (var i = 0; i < data.Columns.Count; i++)
// Create variables named after bindings, and assign values
((IDictionary<string, object>)row)[data.Columns[i].ColumnName.Replace(' ', '_')] = data.Rows[rowIndex].ItemArray[i];
// Add row to DataGrid
dg.Items.Add(row);
}
关于问题的根源,这里是一个带有模板化 header 的 DataGrid,其中包含一个文本框、组合框和一个复选框:
<DataGrid >
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding}" >
<DataGridTextColumn.HeaderTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBox Text="{Binding DataContext.Name, RelativeSource={RelativeSource AncestorType=DataGrid}}" />
<CheckBox IsChecked="{Binding DataContext.Value , RelativeSource={RelativeSource AncestorType=DataGrid}}"/>
<ComboBox ItemsSource="{Binding DataContext.Names , RelativeSource={RelativeSource AncestorType=DataGrid}}" SelectedIndex="0"/>
</StackPanel>
</DataTemplate>
</DataGridTextColumn.HeaderTemplate>
</DataGridTextColumn>
</DataGrid.Columns>
</DataGrid>
DataContext 正在使用自定义 class:
public MainWindow()
{
InitializeComponent();
DataContext = new MyClass() { Name = "Name0", Value = true, Names = new string[2] { "Name1", "Name2" } };
}
public class MyClass
{
public string Name { get; set; }
public bool Value { get; set; }
public string[] Names { get; set; }
}
编辑
您可以动态添加列:
public void addNewColumn(Header h, string bindcol)
{
DataGridColumn col = new DataGridTextColumn(){Binding=new Binding(bindcol)};
col.Header = h;
col.HeaderTemplate = (DataTemplate)FindResource("dgh") as DataTemplate;
dg.Columns.Add(col);
}
在App.xaml中:
<Application.Resources>
<DataTemplate x:Key="dgh">
<StackPanel Orientation="Horizontal">
<TextBox Text="{Binding Name}" />
<CheckBox IsChecked="{Binding Value}"/>
<ComboBox ItemsSource="{Binding Names}" SelectedIndex="0"/>
</StackPanel>
</DataTemplate>
</Application.Resources>
要测试(假设有一个名为 dg 的 DataGrid):
public MainWindow()
{
InitializeComponent();
var h1 = new Header()
{
Name = "Name0",
Value = true,
Names = new string[2] { "Name1", "Name2" }
};
var h2 = new Header()
{
Name = "Name1",
Value = true,
Names = new string[2] { "Name12", "Name22" }
};
addNewColumn(h1, "col1");
addNewColumn(h2, "col2");
}
public class Header
{
public string Name { get; set; }
public bool Value { get; set; }
public string[] Names { get; set; }
}
请注意 "col1" 和 "col2" 指的是数据网格的 ItemsSource。