【问题标题】:WPF Datagrid flatten collections of collection objectsWPF Datagrid 展平集合对象的集合
【发布时间】:2017-08-22 15:03:32
【问题描述】:

我需要你的帮助。我有一个对象集合,其中包含集合,我需要显示其中的值。

这是我的收藏元素。它们的列表稍后将绑定到 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”属性是我需要在更改时更新的属性。

我的视图模型:

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

         };
    }
}

现在数据网格应该有以下列:

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

然后我将此属性附加到数据网格。 并添加了这个...

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

【问题讨论】:

    标签: c# wpf datagrid


    【解决方案1】:

    ElementStates 的长度总是 2 吗?如果是,则有两种选择:

    1. 选项 1:您可以将两个 State 值作为属性包含到您的 ElementContainer 类中。
    2. 选项 2:您可以这样调用 var q = Enitites.Select(e=&gt;e.Nbr, e.Name, e.ElementStates.Where(es=&gt;es.Name="On").First().Value, e.ElementStates.Where(es=&gt;es.Name="Open").First().Value);

    【讨论】:

    • 您好 Dimos。谢谢您的回答。不,状态的数量因元素类型而异。用户稍后可以选择他想要显示的元素类型和状态。但他只能选择一种元素类型。所以网格中的所有元素都是相同的类型。
    • “On”和“Open”状态是否总是在 ElementStates 列表中?如果是,那么第二个选项将起作用
    • 不幸的是,没有。用户想要查看的状态名称在 columnConfigs 中。通过设置对话框,用户可以 f.e.选择元素类型“TV”和状态“IsOn”和“IsInputHDMI1”,或者他可以选择元素类型“门”和状态“IsOpen”
    • 在这种情况下,您可以在代码中添加列。有关更多信息,请参阅stackoverflow.com/questions/6885711/…。有多少种状态类型可用?
    • 嗨迪莫斯。再次感谢您的回答。理论上有无限种可用的状态。几乎是 3 到 10。我已经编辑了这个问题。代码中的绑定是我之前尝试过的,但我没有弄清楚如何做到这一点以仅更新更改的值。
    猜你喜欢
    • 1970-01-01
    • 2011-07-23
    • 2011-01-02
    • 1970-01-01
    • 1970-01-01
    • 2013-11-29
    • 2012-12-21
    • 2021-05-01
    • 1970-01-01
    相关资源
    最近更新 更多