WPF:在MVVM中创建绑定到未知类型的最佳方法

Omr*_*ian 8 c# wpf datagrid mvvm

我正在寻找一种方法来显示DataGrid编译时未知类型的数据.

我有以下基类

public abstract class Entity
{
    // Some implementation of methods ...
}
Run Code Online (Sandbox Code Playgroud)

在运行时,我加载一个插件DLL并使用反射来获取从中派生的所有类型的列表Entity.例如:

public class A : Entity
{
    public LocalAddress Address{ get; set; }
}

public class B : Entity
{
    public Vendor Vendor { get; set; }

    public string Name { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

然后我从DB中检索了他们的实例列表

public IEnumerable<Entity> Entities { get; set; } // A list of instances of type A for example
Run Code Online (Sandbox Code Playgroud)

Entities是DataGrid的ItemsSource,但是什么是我可以将属性绑定到的最佳方式DataGrid?由于属性可能很复杂,我还需要能够绑定到特定路径,例如Address.HomeNum......

澄清

  1. 我只需要一次显示一个类型实例的一个网格.完整的场景是这样的:

    1. 我得到了一个Entity通过反射从插件DLL 派生的类型列表
    2. 我在列表中显示他们的名字.(在此示例中,该列表将包含AB
    3. 当用户点击特定项目时,假设AA从数据库中获取实例列表- 到目前为止一切顺利.
    4. 我想显示的该列表中A的实例DataGrid.
    5. 当用户从列表中选择另一个项目(意思是另一种类型,比方说B)时,我B从DB 获取一个实例列表,需要在网格中显示这些实例等等......
  2. 插件DLL是一个没有xamls的类库(我的用户也是制作这个插件的用户,我不希望他们必须DataTemplate为他们的实体编写s.我也不能DataTemplate像我一样制作预测的s我不知道在运行时我需要显示的类型.每种类型都可以有不同类型和数量的属性.我在complie-time中所知道的是它们都来源于Entity.

  3. 网格也应该是可编辑的.

Ree*_*sey 5

一个DataGrid似乎在这种情况下,不恰当的.如果您的列表绑定到两个单独的实体,它将会严重破坏.

一个更好的选择可能是使用其他一些ItemsControlDataTemplate为每种类型设置一个Entity.这将允许您为每个实体构建自定义编辑器,并具有要编辑的"列表".

如果您知道实体将始终是单一类型,我会构建该特定类型的集合,并绑定到它.


Biz*_*han 4

由于您事先不知道实体的属性名称,因此我认为最好的选择是将 DataGrid 保留在 Xaml 中,但将其 DataGridColumns 的定义和绑定移至后面的代码。

AddColumnsForProperty(PropertyInfo property, string parentPath = "")
{
     var title = property.Name;
     var path = parentPath + (parentPath=="" ? "" : ".") + property.Name;

     if(property.PropertyType == typeof(string))
     {
        var column = new DataGridTextColumn();
        column.Header = title;
        column.Binding = new Binding(path);
        dataGrid.Columns.Add(column);
     }
     else if(property.PropertyType == typeof(bool))
     {
        //use DataGridCheckBoxColumn and so on
     }
     else
     {
          //...
     }

     var properties = property.GetProperties();
     foreach(var item in properties)
     {
          AddColumnsForProperty(item, path);
     }
}
Run Code Online (Sandbox Code Playgroud)

现在,如果您执行这些操作,您将填充 dataGrid 列。并通过在可观察集合中添加所需类型的所有实例并将其绑定到 DataGrid 的 ItemsSource ,它应该可以工作。selectedItem 应该是从 Entity 派生的类之一的实例。列表框包含new A()and new B()(或 A 和 B 的任何现有实例),因此可以在以下语句中使用 selectedItem。

var propertyList = selectedItem.GetType().GetProperties();
foreach (var property in propertyList) 
    AddColumnsForProperty(PropertyInfo property);
Run Code Online (Sandbox Code Playgroud)

如何在代码中编写DataGridColumnTemplate


编辑:

在这种情况下不能使用成员,因为 INotifyPropertyChanged 应该参与其中,所以我用属性替换了成员。