寻求一种更优雅的方法来使用动态列填充 WPF DataGrid(每个对象的属性一列)

发布于 2024-12-07 06:57:18 字数 3403 浏览 0 评论 0原文

我正在尝试设置 WPF 数据网格。标准数据网格设置为接受显示在不同行上的对象列表,每个属性有一列。我实际上需要做相反的事情;列表中的每个属性对应一行,每个对象对应一列。因此,我从blindmeis这里提出的解决方案开始 为了处理动态数量的列,到目前为止效果很好。

我有一个 DataGridVM 类,我可以向其传递对象列表。每个对象都有自己的视图模型,该模型派生自 ParentalBaseVM 类。该对象的每个属性都有自己的视图模型,该模型派生自 ElementVM 类。

每个 ParentalBaseVM 都可以通过重写虚拟方法 PropertyLists 返回其每个对象属性的 ElementVM 列表 例如,在从 ParentalBaseVM 派生的类的示例中,我有:

    public override Dictionary<string, List<ElementVM>> PropertyLists
    {
        get
        {
            Dictionary<string, List<ElementVM>> iPropertyLists = new Dictionary<string, List<ElementVM>>();
            List<ElementVM> BasicProperties = new List<ElementVM>();
            BasicProperties.Add(iNBViewModel);
            BasicProperties.Add(iIDViewModel);
            iPropertyLists.Add("Basic", BasicProperties);
            List<ElementVM> AdvancedProperties = new List<ElementVM>();
            AdvancedProperties.Add(iNBViewModel);
            AdvancedProperties.Add(iIDViewModel);
            AdvancedProperties.Add(iXSAreaViewModel);
            iPropertyLists.Add("Advanced", AdvancedProperties);
            return iPropertyLists;
        }
        set
        {
        }
    }

如您所见,我可以通过将“Basic”或“Advanced”作为字符串传递来返回一组不同的属性。

DataGridVM 代码如下。我将对象列表 (columnList) 和表示的字符串(上例中的“Basic”或“Advanced”)传递给该对象

class DataGridVM
{
    private List<List<ElementVM>> iDataList;
    public DataGridVM(List<ParentalBaseVM> columnList, string rowListKey)
    {
        iDataList = new List<List<ElementVM>>();
        for (int i = 0; i < columnList[0].PropertyLists[rowListKey].Count; i++)
        {
            List<ElementVM> newRowList = new List<ElementVM>();
            for (int j = 0; j < columnList.Count; j++)
            {
                newRowList.Add(columnList[j].PropertyLists[rowListKey][i]);
            }
            iDataList.Add(newRowList);
        }
    }
    public List<List<ElementVM>> DataList
    {
        get
        {
            return iDataList;
        }
        set
        {
        }
    }
}

最后,使用以下方式填充数据网格:

testControlDataGrid.testDataGrid.ItemsSource = testDataGridVM.DataList;

然后动态生成列(CreateDataTemplate 中的代码设置绑定)

for (int i = 0; i < testDataGridVM.DataList[0].Count; i++)
        {

            testControlDataGrid.testDataGrid.Columns.Add(new DataGridTemplateColumn()
            {
                Header = "Col" + i,
                CellTemplate = CreateDataTemplate(TheTextBlock.GetType(),i)
            });
        }

这一切都很好,但感觉很混乱。传递“Basic”等字符串值并访问字典感觉是错误的。也许有一个优雅的解决方案,其中我有从 DataGridVM 派生的类,例如访问对象的“基本”属性的 DataGridVMBasicProperties,但我不确定这是否会导致重复大量代码。

另外,我不确定用返回属性列表的方法弄乱 ParentalBaseVM 类是否很好。我正在考虑也许将其移动到一个新的基类 PropertiesListGenerator ,它可以简单地将 ParentalBaseVM 传递给它,并返回 ElementVM 列表。派生可以是BasicPropertiesListGenerator,并且其进一步的派生可以是AdvancedPropertiesListGenerator。但是,如果并非所有 ParentalBaseVM 都包含“高级”列表而仅包含“基本”列表,则这可能会导致问题。我的主要目的是避免重复大量代码。

我从来没有充分使用委托或接口来真正理解它们,所以我的编码技能并没有真正发挥全部作用。也许他们可以帮助提供一个优雅的解决方案?

任何帮助表示赞赏。我对此很陌生,编程不是我的全职工作(显然)。如果您发现布局、可读性、遵循惯例方面有改进的空间,请随时提出建议,我当然不会被冒犯。

I am trying to setup a WPF datagrid. The standard datagrid is setup to accept a list of objects which are displayed on different rows, with a column for each property. I actually need to do the inverse; a row for each property, and a column for each object in the list. Therefore I started with the solution proposed by blindmeis here in order to handle a dynamic number of columns and it works well so far.

I have a class DataGridVM to which I can pass a list of objects. Each of the objects has its own View Model which derives from a class ParentalBaseVM. Each property of that object has its own View Model which derives from a class ElementVM.

Each ParentalBaseVM can return list of ElementVM for each of its object’s properties through overriding the virtual method PropertyLists
E.g. within an example of a class dervived from ParentalBaseVM I have:

    public override Dictionary<string, List<ElementVM>> PropertyLists
    {
        get
        {
            Dictionary<string, List<ElementVM>> iPropertyLists = new Dictionary<string, List<ElementVM>>();
            List<ElementVM> BasicProperties = new List<ElementVM>();
            BasicProperties.Add(iNBViewModel);
            BasicProperties.Add(iIDViewModel);
            iPropertyLists.Add("Basic", BasicProperties);
            List<ElementVM> AdvancedProperties = new List<ElementVM>();
            AdvancedProperties.Add(iNBViewModel);
            AdvancedProperties.Add(iIDViewModel);
            AdvancedProperties.Add(iXSAreaViewModel);
            iPropertyLists.Add("Advanced", AdvancedProperties);
            return iPropertyLists;
        }
        set
        {
        }
    }

As you can see, I can return a different set of properties by passing either “Basic” or “Advanced” as a string.

The DataGridVM code is below. I pass to this the list of objects (columnList) and the string which represents the (“Basic” or “Advanced” in the example above)

class DataGridVM
{
    private List<List<ElementVM>> iDataList;
    public DataGridVM(List<ParentalBaseVM> columnList, string rowListKey)
    {
        iDataList = new List<List<ElementVM>>();
        for (int i = 0; i < columnList[0].PropertyLists[rowListKey].Count; i++)
        {
            List<ElementVM> newRowList = new List<ElementVM>();
            for (int j = 0; j < columnList.Count; j++)
            {
                newRowList.Add(columnList[j].PropertyLists[rowListKey][i]);
            }
            iDataList.Add(newRowList);
        }
    }
    public List<List<ElementVM>> DataList
    {
        get
        {
            return iDataList;
        }
        set
        {
        }
    }
}

Finally, the datagrid is populated using:

testControlDataGrid.testDataGrid.ItemsSource = testDataGridVM.DataList;

And then the columns are generated dynamically (the code within CreateDataTemplate sets up the bindings)

for (int i = 0; i < testDataGridVM.DataList[0].Count; i++)
        {

            testControlDataGrid.testDataGrid.Columns.Add(new DataGridTemplateColumn()
            {
                Header = "Col" + i,
                CellTemplate = CreateDataTemplate(TheTextBlock.GetType(),i)
            });
        }

This all works fine, but it feels very messy. Passing string values like “Basic” and accessing dictionaries feels wrong. Perhaps there is an elegant solution where I have classes deriving from DataGridVM such as DataGridVMBasicProperties which accesses the “Basic” properties of the object, but I’m not sure if this would result in repeating lots and lots of code.

Also, I’m not sure cluttering up the ParentalBaseVM class with a method which returns the list of properties is great either. I was thinking of perhaps moving this to a new base class PropertiesListGenerator which can simply have a ParentalBaseVM passed to it, and returns a list of ElementVM. A derivation could be BasicPropertiesListGenerator, and a further derivation of this could be AdvancedPropertiesListGenerator. However, if not all ParentalBaseVM contain an "advanced" list and only the "basic" list then this may cause problems. My main aim here is to avoid repeating lots of code.

I have never used Delegates or Interfaces enough to truly understand them, so my coding skills aren’t really firing on all cylinders. Maybe they can help provide an elegant solution?

Any help is appreciated. I’m new to this and programming isn’t my full time job (evidently). If you see room for improvement in layout, readability, convention following, please feel free to suggest, I certainly will not be offended.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文