C# WPF - 如何动态创建具有动态列的 DataGrid(每列的存在取决于用户输入)
C# WPF - How can I dynamically make a DataGrid with dynamic columns (the existence of each column depends on the user input)
这是我想在 xaml 上制作的 table 类型:
用户输入:
ABCDE
Table 生成:
type
A
B
C
D
E
x
1.1
4.6
5.7
8.8
10.1
y
14.5
9.8
8.1
4.3
2.4
用户输入总是一串char,table总是有2行,数据总是double。列数根据用户输入的字符串的长度而变化。用户将无法通过界面编辑 table。
我是 WPF 和 C# 的新手,我在这里遇到了很大的障碍,感谢所有帮助
(Code-behind)
//clear rows & columns
DataGrid.Items.Clear();
DataGrid.Columns.Clear();
//add type Column
DataGridTextColumn typeColumn = new DataGridTextColumn();
typeColumn.Header = "Type";
typeColumn.Binding = new Binding("Type");
DataGrid.Columns.Add(typeColumn);
//Define rows
var xRow = new ExpandoObject() as IDictionary<string, object>;
var yRow = new ExpandoObject() as IDictionary<string, object>;
xRow.Add("Type", "X");
yRow.Add("Type", "Y");
//Get user input
string input = UserInput.Text;
//Add columns
for (int i = 0; i < input.Length; i++)
{
DataGridTextColumn column = new DataGridTextColumn();
column.Header = input[I];
column.Binding = new Binding(input[i].ToString());
DataGrid.Columns.Add(column);
//fill data
xRow.Add(input[i].ToString(), 1.1);
yRow.Add(input[i].ToString(), 1.1);
}
//Add rows
DataGrid.Items.Add(xRow);
DataGrid.Items.Add(yRow);
这种方法的问题在于用户无法添加相同的 letter/column 两次,因为字典,但您可以调整和更改代码以满足您的需要。
如果您需要动态列,您应该始终使用 DataTable
作为数据源。这样您就可以避免在 C#/code-behind 中显式构建 DataGrid
,而是使用 auto-generation 功能。
示例中使用的两个辅助方法 AddColumn
和 AddRow
是作为 DataTable
.
的扩展方法实现的候选方法
MainWindow.xaml.cs
private void OnSendButtonClick(object sender, EventArgs e)
{
var dataGridSource = new DataTable();
AddColumn<string>(dataGridSource, "type");
foreach (char character in this.TextInput.Text)
{
AddColumn<double>(dataGridSource, character.ToString());
}
// Generate 2 rows of pseudo data
var doubleGenerator = new Random();
for (int rowIndex = 0; rowIndex < 2; rowIndex++)
{
var columnValues = new List<object>();
columnValues.Add(rowIndex < 1 ? "x" : "y");
for (int columnIndex = 0; columnIndex < dataGridSource.Columns.Count; columnIndex++)
{
columnValues.Add(doubleGenerator.NextDouble());
}
AddRow(dataGridSource, columnValues);
}
this.Table.ItemsSource = dataGridSource.DefaultView;
}
private void AddColumn<TData>(DataTable dataTable, string columnName, int columnIndex = -1)
{
DataColumn newColumn = new DataColumn(columnName, typeof(TData));
dataTable.Columns.Add(newColumn);
if (columnIndex > -1)
{
newColumn.SetOrdinal(columnIndex);
}
int newColumnIndex = dataTable.Columns.IndexOf(newColumn);
// Initialize existing rows with default value for the new column
foreach (DataRow row in dataTable.Rows)
{
row[newColumnIndex] = default(TData);
}
}
private void AddRow(DataTable dataTable, IList<object> columnValues)
{
DataRow rowModelWithCurrentColumns = dataTable.NewRow();
dataTable.Rows.Add(rowModelWithCurrentColumns);
for (int columnIndex = 0; columnIndex < dataTable.Columns.Count; columnIndex++)
{
rowModelWithCurrentColumns[columnIndex] = columnValues[columnIndex];
}
}
MainWindow.xaml
<Window>
<StackPanel>
<TextBox x:Name="TextInput" />
<Button Content="Send"
Click="OnSendButtonClick" />
<DataGrid x:Name="Table" />
</StackPanel>
</Window>
这是我想在 xaml 上制作的 table 类型:
用户输入:
ABCDE
Table 生成:
type | A | B | C | D | E |
---|---|---|---|---|---|
x | 1.1 | 4.6 | 5.7 | 8.8 | 10.1 |
y | 14.5 | 9.8 | 8.1 | 4.3 | 2.4 |
用户输入总是一串char,table总是有2行,数据总是double。列数根据用户输入的字符串的长度而变化。用户将无法通过界面编辑 table。
我是 WPF 和 C# 的新手,我在这里遇到了很大的障碍,感谢所有帮助
(Code-behind)
//clear rows & columns
DataGrid.Items.Clear();
DataGrid.Columns.Clear();
//add type Column
DataGridTextColumn typeColumn = new DataGridTextColumn();
typeColumn.Header = "Type";
typeColumn.Binding = new Binding("Type");
DataGrid.Columns.Add(typeColumn);
//Define rows
var xRow = new ExpandoObject() as IDictionary<string, object>;
var yRow = new ExpandoObject() as IDictionary<string, object>;
xRow.Add("Type", "X");
yRow.Add("Type", "Y");
//Get user input
string input = UserInput.Text;
//Add columns
for (int i = 0; i < input.Length; i++)
{
DataGridTextColumn column = new DataGridTextColumn();
column.Header = input[I];
column.Binding = new Binding(input[i].ToString());
DataGrid.Columns.Add(column);
//fill data
xRow.Add(input[i].ToString(), 1.1);
yRow.Add(input[i].ToString(), 1.1);
}
//Add rows
DataGrid.Items.Add(xRow);
DataGrid.Items.Add(yRow);
这种方法的问题在于用户无法添加相同的 letter/column 两次,因为字典,但您可以调整和更改代码以满足您的需要。
如果您需要动态列,您应该始终使用 DataTable
作为数据源。这样您就可以避免在 C#/code-behind 中显式构建 DataGrid
,而是使用 auto-generation 功能。
示例中使用的两个辅助方法 AddColumn
和 AddRow
是作为 DataTable
.
MainWindow.xaml.cs
private void OnSendButtonClick(object sender, EventArgs e)
{
var dataGridSource = new DataTable();
AddColumn<string>(dataGridSource, "type");
foreach (char character in this.TextInput.Text)
{
AddColumn<double>(dataGridSource, character.ToString());
}
// Generate 2 rows of pseudo data
var doubleGenerator = new Random();
for (int rowIndex = 0; rowIndex < 2; rowIndex++)
{
var columnValues = new List<object>();
columnValues.Add(rowIndex < 1 ? "x" : "y");
for (int columnIndex = 0; columnIndex < dataGridSource.Columns.Count; columnIndex++)
{
columnValues.Add(doubleGenerator.NextDouble());
}
AddRow(dataGridSource, columnValues);
}
this.Table.ItemsSource = dataGridSource.DefaultView;
}
private void AddColumn<TData>(DataTable dataTable, string columnName, int columnIndex = -1)
{
DataColumn newColumn = new DataColumn(columnName, typeof(TData));
dataTable.Columns.Add(newColumn);
if (columnIndex > -1)
{
newColumn.SetOrdinal(columnIndex);
}
int newColumnIndex = dataTable.Columns.IndexOf(newColumn);
// Initialize existing rows with default value for the new column
foreach (DataRow row in dataTable.Rows)
{
row[newColumnIndex] = default(TData);
}
}
private void AddRow(DataTable dataTable, IList<object> columnValues)
{
DataRow rowModelWithCurrentColumns = dataTable.NewRow();
dataTable.Rows.Add(rowModelWithCurrentColumns);
for (int columnIndex = 0; columnIndex < dataTable.Columns.Count; columnIndex++)
{
rowModelWithCurrentColumns[columnIndex] = columnValues[columnIndex];
}
}
MainWindow.xaml
<Window>
<StackPanel>
<TextBox x:Name="TextInput" />
<Button Content="Send"
Click="OnSendButtonClick" />
<DataGrid x:Name="Table" />
</StackPanel>
</Window>