显示一个“动态”表格

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

  • 我知道,我只想在运行时显示哪些列(用户以某种方式定义它们),以及
  • 我想避免使用代码隐藏:在XAML,在这里我想显示的表里面是一个DataTemplate ,这是另一个里面DataTemplate等引入代码隐藏会有问题(虽然我会做,如果我没有其他的选择) 。
  • 我虽然使用WPF的DataGrid ,它足够聪明,可以在运行时提取列名(取决于集合项的属性),但我知道哪些列只在运行时显示 - 我必须在运行时创建具有特定属性的对象,什么也有问题(如果可能的话)。

    另外,我并不需要专门使用DataGrid ,因为这只是用于预览的简单字符串表格 - 它可以在ItemsControl中显示,比如在Grid中 - 我只需要提供一个带有列的视图,行。

    所以问题是:

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

  • 既然它似乎对这个问题有兴趣,我自己找到了解决方案,在这里(附属性规则!)

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

    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 ,否则你会收到额外的列“单元格”。

    链接地址: http://www.djcxy.com/p/64739.html

    上一篇: displaying a "dynamic" table

    下一篇: Maintain relative position for child in a WPF canvas