Here's the kind of table I am trying to make on xaml:
User input:
ABCDE
Table generated:
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 |
The user input will always be a string of char, the table will always have 2 rows, the data will always be double. The number of columns changes depending on the length of the string that the user inputs. The user won't be able to edit the table through the interface.
I'm new to WPF and C#, and I hit a very sizeable roadblock here, all help is appreciated
CodePudding user response:
If you need dynamic columns, you should always use a DataTable
as data source. This way you can avoid to build the DataGrid
explicitly in C#/code-behind and instead use the auto-generation feature.
The two helper methods AddColumn
and AddRow
used in the example are candidates to be implemented as extension methods for the 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>
CodePudding user response:
(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);
The problem with this approach is that the user can't add the same letter/column twice because of the Dictionary but you can Adapt and change the code to fit your needing.