【问题标题】:WPF dynamic columns and values for DataGridDataGrid 的 WPF 动态列和值
【发布时间】:2015-07-27 05:57:37
【问题描述】:

我有两个 DataGrid。一个列出项目列表,另一个保存规范。

如果我在第一个网格中选择监视器,第二个网格应该显示它自己的规格。如果我选择 CPU,它应该在另一个网格上显示它的规格。

我正在寻找一个好的解决方案来做到这一点。截至目前,我计划创建一个具有字符串属性和 DataTable 的模型,这样我就可以创建将动态表绑定到第二个网格。但我正在寻找动态属性或更好的解决方案。

谢谢

【问题讨论】:

  • 你找到答案了吗?
  • 我会试一试告诉你
  • 好的,在这种情况下,如果我们假设“Monitor”是一个表名,那么 Size、Power、HDMI、USB、VGA 是 GenericRow 的属性。您应该只需创建新属性并分配值

标签: c# wpf xaml


【解决方案1】:

对于这种情况,我使用我的 GenericRow 和 GenericTable 类:

public class GenericRow : CustomTypeDescriptor, INotifyPropertyChanged
{

    #region Private Fields
    List<PropertyDescriptor> _property_list = new List<PropertyDescriptor>();
    #endregion

    #region INotifyPropertyChange Implementation

    public event PropertyChangedEventHandler PropertyChanged = delegate { };
    protected void OnPropertyChanged(string propertyName)
    {
        PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }

    #endregion INotifyPropertyChange Implementation

    #region Public Methods

    public void SetPropertyValue<T>(string propertyName, T propertyValue)
    {
        var properties = this.GetProperties()
                                .Cast<PropertyDescriptor>()
                                .Where(prop => prop.Name.Equals(propertyName));

        if (properties == null || properties.Count() != 1)
        {
            throw new Exception("The property doesn't exist.");
        }

        var property = properties.First();
        property.SetValue(this, propertyValue);

        OnPropertyChanged(propertyName);
    }

    public T GetPropertyValue<T>(string propertyName)
    {
        var properties = this.GetProperties()
                            .Cast<PropertyDescriptor>()
                            .Where(prop => prop.Name.Equals(propertyName));

        if (properties == null || properties.Count() != 1)
        {
            throw new Exception("The property doesn't exist.");
        }

        var property = properties.First();
        return (T)property.GetValue(this);
    }

    public void AddProperty<T, U>(string propertyName) where U : GenericRow
    {
        var customProperty =
                new CustomPropertyDescriptor<T>(
                                        propertyName,
                                        typeof(U));

        _property_list.Add(customProperty);
    }

    #endregion

    #region Overriden Methods

    public override PropertyDescriptorCollection GetProperties()
    {
        var properties = base.GetProperties();
        return new PropertyDescriptorCollection(
                            properties.Cast<PropertyDescriptor>()
                                      .Concat(_property_list).ToArray());
    }

    #endregion

}

和:

 public class GenericTable
{

    private string tableName = "";
    public string TableName
    {
        get { return tableName; }
        set { tableName = value; }
    }

    private ObservableCollection<DataGridColumn> columnCollection;
    public ObservableCollection<DataGridColumn> ColumnCollection
    {
        get { return columnCollection; }
        private set { columnCollection = value; }
    }

    private ObservableCollection<GenericRow> genericRowCollection;
    public ObservableCollection<GenericRow> GenericRowCollection
    {
        get { return genericRowCollection; }
        set { genericRowCollection = value; }
    }




    public GenericTable(string tableName)
    {
        this.TableName = tableName;
        ColumnCollection = new ObservableCollection<DataGridColumn>();
        GenericRowCollection = new ObservableCollection<GenericRow>(); 
    }

    /// <summary>
    /// ColumnName is also binding property name
    /// </summary>
    /// <param name="columnName"></param>
    public void AddColumn(string columnName)
    {
        DataGridTextColumn column = new DataGridTextColumn();
        column.Header = columnName;
        column.Binding = new Binding(columnName);
        ColumnCollection.Add(column);
    }



    public override string ToString()
    {
        return TableName; 
    }


}

您可以使用这两个类来创建动态行和列。使用 GenericRow 类,您可以生成具有所需属性名称的行,并且可以将相同的属性名称用于探测绑定的列。

对于 XAML 方面:

<DataGrid Name="dataGrid"
          local:DataGridColumnsBehavior.BindableColumns="{Binding ColumnCollection}"
          AutoGenerateColumns="False"
          ...>

最后是 DataGridColumsBehaior:

public class DataGridColumnsBehavior
{
    public static readonly DependencyProperty BindableColumnsProperty =
        DependencyProperty.RegisterAttached("BindableColumns",
                                            typeof(ObservableCollection<DataGridColumn>),
                                            typeof(DataGridColumnsBehavior),
                                            new UIPropertyMetadata(null, BindableColumnsPropertyChanged));
    private static void BindableColumnsPropertyChanged(DependencyObject source, DependencyPropertyChangedEventArgs e)
    {
        DataGrid dataGrid = source as DataGrid;
        ObservableCollection<DataGridColumn> columns = e.NewValue as ObservableCollection<DataGridColumn>;
        dataGrid.Columns.Clear();
        if (columns == null)
        {
            return;
        }
        foreach (DataGridColumn column in columns)
        {
            dataGrid.Columns.Add(column);
        }
        columns.CollectionChanged += (sender, e2) =>
        {
            NotifyCollectionChangedEventArgs ne = e2 as NotifyCollectionChangedEventArgs;
            if (ne.Action == NotifyCollectionChangedAction.Reset)
            {
                dataGrid.Columns.Clear();
                foreach (DataGridColumn column in ne.NewItems)
                {
                    dataGrid.Columns.Add(column);
                }
            }
            else if (ne.Action == NotifyCollectionChangedAction.Add)
            {
                foreach (DataGridColumn column in ne.NewItems)
                {
                    dataGrid.Columns.Add(column);
                }
            }
            else if (ne.Action == NotifyCollectionChangedAction.Move)
            {
                dataGrid.Columns.Move(ne.OldStartingIndex, ne.NewStartingIndex);
            }
            else if (ne.Action == NotifyCollectionChangedAction.Remove)
            {
                foreach (DataGridColumn column in ne.OldItems)
                {
                    dataGrid.Columns.Remove(column);
                }
            }
            else if (ne.Action == NotifyCollectionChangedAction.Replace)
            {
                dataGrid.Columns[ne.NewStartingIndex] = ne.NewItems[0] as DataGridColumn;
            }
        };
    }
    public static void SetBindableColumns(DependencyObject element, ObservableCollection<DataGridColumn> value)
    {
        element.SetValue(BindableColumnsProperty, value);
    }
    public static ObservableCollection<DataGridColumn> GetBindableColumns(DependencyObject element)
    {
        return (ObservableCollection<DataGridColumn>)element.GetValue(BindableColumnsProperty);
    }
}

最后,您可以创建 GenericRows 并将它们添加到 GenericTable 中。它就像一个小型视图模型。在 XAML 端,不要忘记将 rowscollection 绑定为 DataGrid 的 itemsource。

【讨论】:

    猜你喜欢
    • 2011-03-05
    • 1970-01-01
    • 2014-12-15
    • 1970-01-01
    • 2012-04-24
    • 1970-01-01
    • 2017-10-23
    • 2011-12-16
    • 2013-01-05
    相关资源
    最近更新 更多