【问题标题】:WPF - displaying a "dynamic" tableWPF - 显示“动态”表
【发布时间】:2018-01-29 19:36:04
【问题描述】:

我想在 WPF 中显示一个项目表。一般来说,这并不难,除了:

  • 我知道,我只想在运行时显示哪些列(用户以某种方式定义它们),并且
  • 我想避免使用代码隐藏:XAML,我想在其中显示表格位于 DataTemplate 内,而 DataTemplate 位于另一个 DataTemplate 内等。引入 CodeBehind 会有问题(尽管我会这样做如果我没有其他选择)。

我虽然使用 WPF 的 DataGrid,它足够聪明,可以在运行时提取列名(取决于集合项的属性),但我知道我只想在运行时显示哪些列 - 我必须创建对象在运行时具有特定属性,还有什么问题(如果可能的话)。

另外,我真的不需要专门使用DataGrid,因为这将是一个简单的字符串表,仅供预览 - 它也可以显示在带有 ItemsControl 的 Grid 内部 - 我只需要提供具有列和行的视图。

所以问题是:

  • 如何仅从 ViewModel (DataContext) 和 XAML 自定义 DataGrid 中显示的列?,或
  • 当列仅在运行时已知时,如何显示预览数据的表格?

【问题讨论】:

标签: c# wpf xaml datagrid


【解决方案1】:

由于似乎对这个问题很感兴趣并且我自己找到了解决方案,所以就到这里了(附加属性 rulez!)

为了清楚起见,我创建了模型类来包装字符串列表:

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; }
}

现在我们定义附加属性:

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));
}

用法很琐碎:

(...)
xmlns:h="clr-namespace:<namespace-of-DataGridHelper>"
(...)    

<DataGrid AutoGenerateColumns="False" h:DataGridHelper.TableData="{Binding ResultData}" />

显然DataContext 必须通过ResultData 发布TableData。不要忘记AutoGenerateColumns,否则您会收到额外的“单元格”列。

【讨论】:

    猜你喜欢
    • 2012-08-24
    • 2012-02-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-10-25
    • 1970-01-01
    相关资源
    最近更新 更多