WPF Datagrid展平了集合对象的集合

时间:2017-08-22 15:03:32

标签: c# wpf datagrid

我需要你的帮助。我有一个对象集合,里面有集合,我需要显示它们内部的值。

这是我的收藏元素。它们的列表稍后将绑定到Datagrid(ObjectBase只是INotifyPropertyChanged的一个实现)

public class ElementContainer : ObjectBase
{
    public Element ContainerElement { get; set; }

    private ObservableCollection<State> _elementStates;

    public ObservableCollection<State> ElementStates
    {
        get { return _elementStates; }
        set { _elementStates = value; OnPropertyChanged(); }
    }
}

我的元素:

public class Element
{
    public int Nbr { get; set; }
    public string Name { get; set; }
}

public class State: ObjectBase
{
    public string Name { get; set; }

    private bool _value;

    public bool Value
    {
        get { return _value; }
        set { _value = value; OnPropertyChanged(); }
    }

    public string StateType { get; set; }
}

State对象的“Value”属性是我需要更新的内容,如果它发生了变化。

我的ViewModel:

public class MainViewModel : ObjectBase
{

    private IList<ElementContainer> _enitites;

    public IList<ElementContainer> Enitites
    {
        get { return _enitites; }
        set { _enitites = value; OnPropertyChanged(); }
    }

    public MainViewModel()
    {
        Enitites = new ObservableCollection<ElementContainer>()
        {
            new ElementContainer() {
                                       ContainerElement =  new Element() {Nbr= 1, Name= "Test 1" },
                                       ElementStates = new ObservableCollection<State>()
                                       {
                                            new State() { Name = "On", Value = true,  StateType= "On" },
                                            new State() { Name = "Open", Value = false,  StateType= "Open" }
                                       }
                                    },

             new ElementContainer() {
                                       ContainerElement =  new Element() {Nbr= 2, Name= "Test 2" },
                                       ElementStates = new ObservableCollection<State>()
                                       {
                                            new State() { Name = "On", Value = false, StateType= "On" },
                                            new State() { Name = "Open", Value = true, StateType= "Open" }
                                       }
                                    }

         };
    }
}

现在,Datagrid应该包含以下列:

Nbr,姓名,开启,打开

“On”和“Open”列的CellValue应该是State的value属性。

有什么想法吗?

编辑:

我还尝试创建一个AttachedProperty来创建列:

public class ElementStatesGridExtensions
{
    public static ObservableCollection<ColumnConfig> GetColumnConfigs(DependencyObject obj)
    {
        return (ObservableCollection<ColumnConfig>)obj.GetValue(ColumnConfigsProperty);
    }

    public static void SetColumnConfigs(DependencyObject obj, ObservableCollection<ColumnConfig> value)
    {
        obj.SetValue(ColumnConfigsProperty, value);
    }


    public static readonly DependencyProperty ColumnConfigsProperty =
        DependencyProperty.RegisterAttached("ColumnConfigs", typeof(ObservableCollection<ColumnConfig>), typeof(ElementStatesGridExtensions), new PropertyMetadata(new PropertyChangedCallback(OnColumnsChanged)));

    static DeviceStateConverter converter = new DeviceStateConverter();

    static FrameworkElementFactory CreateFrameWorkFactoryWithBinding(ColumnConfig config)
    {
        var fwf = new FrameworkElementFactory(typeof(TextBlock));

        if (config != null && config.ColumnType != null)
        {

            if (config.ColumnType.Equals("State"))
            {
                fwf.SetBinding(TextBlock.TextProperty, new Binding("ElementStates")
                {
                    ConverterParameter = config.ColumnName,
                    Converter = converter,

                    UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged,
                    Mode = BindingMode.OneWay
                });
            }
        }
        return fwf;
    }


    static void OnColumnsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var dataGrid = d as DataGrid;
        dataGrid.Columns.Clear();


        dataGrid.Columns.Add(new DataGridTextColumn() { Header = "Nbr", Binding = new Binding("ContainerElement.Nbr") });
        dataGrid.Columns.Add(new DataGridTextColumn() { Header = "Name", Binding = new Binding("ContainerElement.Name") });


        foreach (var columnConfig in GetColumnConfigs(d))
        {
            dataGrid.Columns.Add(new DataGridTemplateColumn()
            {
                Header = columnConfig.ColumnHeader,
                CellTemplate = new DataTemplate()
                {
                    VisualTree = CreateFrameWorkFactoryWithBinding(columnConfig)
                }
            });
        }
    }
}

public class DeviceStateConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (value is ObservableCollection<stof.State> deviceStates && parameter != null)
        {
            var deviceState = deviceStates.FirstOrDefault(s => s.StateType?.ToUpper() == parameter.ToString().ToUpper());

            if (deviceState != null)
                return deviceState.Value;

        }

        return false;
    }
    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

然后我将此属性附加到datagrid。 并添加了这个......

public void RefeshStates(object sender, EventArgs e)
    {
        OnPropertyChanged("ElementStates");
    }

到ElementContainer类。

然后在ViewModel中迭代所有实体并将每个状态的PropertyChanged事件注册到ElementContainer。 所以现在,如果状态值发生变化,则会通知Container并且Collection将刷新。这不是一个好的解决方案。此外,所有其他元素的状态都将更新。

 foreach (ElementContainer container in Enitites)
        {

            foreach (State s in container.ElementStates)
            {
                s.PropertyChanged += container.RefeshStates;
            }
        }

1 个答案:

答案 0 :(得分:0)

ElementStates长度总是2吗?如果是,则有两个选项:

  1. 选项1:您可以将State两个值都包含在ElementContainer类中作为属性。
  2. 选项2:您可以调用类似var q = Enitites.Select(e=>e.Nbr, e.Name, e.ElementStates.Where(es=>es.Name="On").First().Value, e.ElementStates.Where(es=>es.Name="Open").First().Value);
  3. 之类的内容