displaying a "dynamic" table
I'd like to display a table of items in WPF. In general that's not that hard, except that:
DataTemplate
, which is inside another DataTemplate
etc. Introducing CodeBehind there will be problematic (though I will do that if I have no other options). I though of using WPF's DataGrid
, which is smart enough to extract column names in runtime (depending on properties of collection items), but I know which columns I want to display only at runtime - I would have to create object with specific properties at runtime, what is also problematic (if possible).
Also, I don't really need to use specifically the DataGrid
, as this will be simple table of strings for preview only - it may be as well displayed, say, inside Grid with ItemsControl - I just need to provide a view with columns and rows.
So the questions are:
Since it seems like there is interest for this problem and I found solution myself, here it goes (attached properties rulez!)
For clarity, I created model classes to wrap list of list of strings:
public class TableDataRow
{
public TableDataRow(List<string> cells)
{
Cells = cells;
}
public List<string> Cells { get; }
}
public class TableData
{
public TableData(List<string> columnHeaders, List<TableDataRow> rows)
{
for (int i = 0; i < rows.Count; i++)
if (rows[i].Cells.Count != columnHeaders.Count)
throw new ArgumentException(nameof(rows));
ColumnHeaders = columnHeaders;
Rows = rows;
}
public List<string> ColumnHeaders { get; }
public List<TableDataRow> Rows { get; }
}
Now we define the attached property:
public static class DataGridHelper
{
private static void TableDataChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var dataGrid = d as DataGrid;
var tableData = e.NewValue as TableData;
if (dataGrid != null && tableData != null)
{
dataGrid.Columns.Clear();
for (int i = 0; i < tableData.ColumnHeaders.Count; i++)
{
DataGridColumn column = new DataGridTextColumn
{
Binding = new Binding($"Cells[{i}]"),
Header = tableData.ColumnHeaders[i]
};
dataGrid.Columns.Add(column);
}
dataGrid.ItemsSource = tableData.Rows;
}
}
public static TableData GetTableData(DependencyObject obj)
{
return (TableData)obj.GetValue(TableDataProperty);
}
public static void SetTableData(DependencyObject obj, TableData value)
{
obj.SetValue(TableDataProperty, value);
}
// Using a DependencyProperty as the backing store for TableData. This enables animation, styling, binding, etc...
public static readonly DependencyProperty TableDataProperty =
DependencyProperty.RegisterAttached("TableData",
typeof(TableData),
typeof(DataGridHelper),
new PropertyMetadata(null, TableDataChanged));
}
The usage is trivial:
(...)
xmlns:h="clr-namespace:<namespace-of-DataGridHelper>"
(...)
<DataGrid AutoGenerateColumns="False" h:DataGridHelper.TableData="{Binding ResultData}" />
Obviously DataContext
must publish TableData
via ResultData
. Don't forget about AutoGenerateColumns
, otherwise you'll receive additional column "Cells".
上一篇: 从大型XML文件中删除节点
下一篇: 显示一个“动态”表格