微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

c# – 使用MVVM在WPF Toolkit DataGrid中显示/编辑复杂对象

我有一组复杂的模型,每个模型包含一系列接口实例到其他复杂模型,我需要显示这些父和子复杂模型,允许编辑父和子复杂模型的所有属性.

如何最好地显示此数据并允许单独编辑父对象和子对象的属性,以及通过多个单元格的选择和上下文菜单单击的组合(即,跨多个父项更改子模型上的相同属性值) ?我还需要能够通过编辑机制(当前的DataGrid单元格)中的搜索来执行诸如将模型属性值设置为其他复杂模型实例的操作吗?

下面是类的一般示例,它近似于我在应用程序中使用的内容.

enum ChildType 
{ 
    One,Two,Three
}

class ComplexType
{
    public long ID { get; set; }
    public string Name { get; set; }

    public override string ToString()
    { 
        return Name;
    }
}        

class IChildModel
{
    ChildType Type { get; set; }
    string Name { get; set; }
}

class ChildModel1 : IChildModel
{
    public ChildType Type { get; set; }
    public string Name { get; set; }
    public string Property1 { get; set; }
    public decimal Property2 { get; set; }
    public ComplexType Property3 { get; set; }
}

class ChildModel2 : IChildModel
{
    public ChildType Type { get; set; }
    public long Property1 { get; set; }
    public string Property2 { get; set; }
}

class Parent
{
    public long ID { get; set; }
    public string Name { get; set; }
    public CustomObservableCollection<IChildModel> Children { get; set; }
}

class viewmodel
{
    public CustomObservableCollection<Parent> Parents { get; set; }
}

到目前为止,我已经使用DataGrid实现了应用程序,并使用反射动态生成View代码隐藏中的列.子复杂对象实例的列的绑定使用CustomObservableCollection<>上的下标. (自定义集合允许通过通用值进行索引[在这种情况下为枚举ChildType]).特别是绑定使得难以在多个父级子实例上的相同属性上正确设置值(通过列上的多选和上下文菜单单击以设置值).再一次,我正在处理View中代码隐藏的这些大规模更改,使用反射绑定路径解析来设置属性值(感觉不对;讨厌这样做).我希望能够在viewmodel上设置选定的子项,并将属性属性名称和新值传递给viewmodel中的命令以进行更改.即使能够传递命令,子类型,属性和新值也会很好(我认为).

我通过Google,stackoverflow,Code Project等进行的研究指出了我目前的解决方案,但我觉得我正在考虑这个问题并且应该有一个更好的MVVM方法.

编辑

此应用程序的主要焦点是允许在视图中编辑多个父模型实例和子模型实例,其中用户可以比较多个实例的值,并允许跨多个相同类型的对象设置父或子属性的值相同的值(即Parent1和Parent2都有一个ChildModel1,用户想要将两个父对象的ChildModel1的Property3上的Name设置为“X”).虽然,应用程序仍然必须允许对父对象和子对象的属性进行单独编辑(DataGrid似乎确实很好地满足了要求).为了满足这些要求,我在视图中实现了动态列创建.下面是这个逻辑看起来的一般示例.

private void DataGrid_TargetUpdated(object sender,DataTransferEventArgs e)
{
    var vm = DataContext as viewmodel;

    if (vm != null && vm.Parents != null) {
        List<ChildType> processedChildTypes = new List<ChildType>();

        foreach (var parent in vm.Parents) {
            for (int childindex = 0; childindex < parent.Children.Count; ++childindex) {
                var child = vm.Children[childindex];

                if (!processedChildTypes.Contains(child.Type)) {    // Ensure each child type is only processed once
                    processedChildTypes.Add(child.Type);
                    CreateChildPropertyColumns(processedChildTypes,child);
                }
        }
    }
}

private void CreateChildPropertyColumns(List<ChildType> processedChildTypes,IChildModel child)
{
    PropertyInfo[] childProperties = child.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly); // Only use properties declared on the child type
    Type childInterfaceType = typeof(IChildModel);

    foreach (PropertyInfo childProperty in childProperties) {   
        // Only create a column if the property is editable
        if (childProperty.CanWrite) {
            if (childInterfaceType.IsAssignableFrom(childProperty.PropertyType)) {
                var subChild = childProperty.GetValue(child,null) as IChildModel;

                if (subChild != null && !processedChildTypes.Contains(subChild.Type)) {
                    processedChildTypes.Add(subChild.Type);
                    CreateChildPropertyColumns(processedChildTypes,subChild);
                }
            }
            else
                dataGrid.Columns.Add(CreateChildPropertyColumn(child.Type,childProperty));
        }
    }
}

private DataGridColumn CreateChildPropertyColumn(ChildType childType,PropertyInfo propertyInfo)
{
    DataGridColumn column = null;
    var binding = new Binding(string.Format("Children[{0}].{1}",childType,propertyInfo.Name));

    /* Create column based on PropertyInfo here */
    /* Default case is a text column */
    column = new DataGridTextColumn() { Binding = binding };
    column.Header = propertyInfo.Name;

    return column;
}

解决方法

我认为在这种情况下使用DataGrid不是一个好主意.大多数情况下,用户很少一次查看/编辑MULTIPLE Parent,ChildModel2和ComplexType.

您必须考虑用户如何查看/编辑数据并提出更简单的UI.例如,如果用户大多数时间查看/编辑Parent和ChildModel并且很少查看/编辑ComplexType,那么您可以放置​​文本框来编辑父级和DataGrid来编辑其ChildModel.

这样,您可以使用更简单的UI并且更容易编写代码.我认为编写保存多个Parent的代码要比这个示例复杂得多.

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。

相关推荐