You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

泛型继承类存储父级ObservableCollection的实现与问题咨询

模型与集合关联的实现问题及解决方案

现有实现代码

泛型基类

public class ModelBase<T> : ObservableObject, IDataErrorInfo
{
    public CustomObservableCollection<T> ParentCollection;

    public int Id { get; set; }  // 通用属性
}

具体模型类

public class Model1: ModelBase<Model1>
{
    public string Name { get; set; } // 专属属性

    // 数据验证示例:检查名称唯一性
    if (ParentCollection?.Where(c => c.Id != Id).Any(c => c.Name == Name) == true)
    {
        // 处理重复逻辑
    }
}

public class Model2: ModelBase<Model2>
{}

自定义ObservableCollection

public class CustomObservableCollection<T> : ObservableCollection<T> where T : ModelBase<T>
{
    public CustomObservableCollection() : base() { }

    public CustomObservableCollection(List<T> list)
            : base(list)
    {
        foreach (T item in list)
        {
            item.ParentCollection = this;
        }
    }

    public void AddEdit(T item)
    {
        item.ParentCollection = this;
        base.Add(item);
    }

    protected override void InsertItem(int index, T item)
    {
        base.InsertItem(index, item);
        item.ParentCollection = this;
        // 初始化逻辑
    }

    // 希望在命令处理中直接调用的通用移动方法
    public void MoveItemUp(object parameter) 
    {
        // 待实现
    }
}

使用方式

CustomObservableCollection<Model1> Model1Collection = new (listOfModel1instances);

遇到的问题

  1. 编写GetMaxId方法时出现错误:Error CS1061 'ICollection' does not contain a definition for 'Max'
    public int GetMaxId(t item)
    {
         return item.Source.Max(i => i.Id);
    }
    
  2. 需要实现通用命令处理程序,仅通过传入选中项作为参数,完成所有类型项的上下移动排序操作,无需为每种类型单独写命令。

解决方案

问题1:修复GetMaxId方法报错

要使用Linq的Max方法,需满足两个条件:

  • 引入System.Linq命名空间
  • 确保集合实现IEnumerable<T>接口(CustomObservableCollection<T>继承自ObservableCollection<T>,天然实现该接口)

另外,代码中的item.Source应为模型的ParentCollection属性,修正后的方法如下:

using System.Linq;

public class CustomObservableCollection<T> : ObservableCollection<T> where T : ModelBase<T>
{
    // 其他现有代码...

    public int GetMaxId(T item)
    {
        // 空值判断避免空引用异常
        return item.ParentCollection?.Any() == true 
            ? item.ParentCollection.Max(i => i.Id) 
            : 0; // 根据业务需求设置默认值
    }
}

问题2:实现通用排序命令(上下移动)

步骤1:定义统一接口约束Order属性

为所有模型添加统一的Order属性约束,通过接口实现:

public interface IOrderedItem
{
    int Order { get; set; }
}

步骤2:让基类实现该接口

修改ModelBase<T>,使其继承IOrderedItem:

public class ModelBase<T> : ObservableObject, IDataErrorInfo, IOrderedItem
{
    public CustomObservableCollection<T> ParentCollection;
    public int Id { get; set; }
    public int Order { get; set; } // 实现IOrderedItem接口的属性
}

步骤3:在自定义集合中实现通用移动方法

更新CustomObservableCollection<T>的泛型约束,添加IOrderedItem,并实现通用的上下移动逻辑:

public class CustomObservableCollection<T> : ObservableCollection<T> 
    where T : ModelBase<T>, IOrderedItem // 添加IOrderedItem约束
{
    // 其他现有代码...

    // 通用向上移动方法
    public void MoveItemUp(T item)
    {
        int currentIndex = IndexOf(item);
        if (currentIndex <= 0) return; // 已是第一个元素,无需移动

        T previousItem = this[currentIndex - 1];
        // 交换Order属性值
        (item.Order, previousItem.Order) = (previousItem.Order, item.Order);
        // 交换集合中的位置
        Move(currentIndex, currentIndex - 1);
    }

    // 通用向下移动方法
    public void MoveItemDown(T item)
    {
        int currentIndex = IndexOf(item);
        if (currentIndex >= Count - 1) return; // 已是最后一个元素,无需移动

        T nextItem = this[currentIndex + 1];
        // 交换Order属性值
        (item.Order, nextItem.Order) = (nextItem.Order, item.Order);
        // 交换集合中的位置
        Move(currentIndex, currentIndex + 1);
    }
}

步骤4:实现通用命令处理程序

通过动态类型或反射,实现可以处理所有IOrderedItem类型的通用命令:

// 通用向上移动命令执行方法
public void ExecuteMoveUp(object parameter)
{
    if (parameter is not IOrderedItem orderedItem) return;

    // 通过反射获取当前项的ParentCollection
    var parentCollection = orderedItem.GetType()
                                     .GetProperty("ParentCollection")
                                     ?.GetValue(orderedItem) as dynamic;

    parentCollection?.MoveItemUp((dynamic)orderedItem);
}

// 通用向下移动命令执行方法
public void ExecuteMoveDown(object parameter)
{
    if (parameter is not IOrderedItem orderedItem) return;

    var parentCollection = orderedItem.GetType()
                                     .GetProperty("ParentCollection")
                                     ?.GetValue(orderedItem) as dynamic;

    parentCollection?.MoveItemDown((dynamic)orderedItem);
}

这样,无论传入的是Model1还是Model2实例,都可以通过同一个命令完成上下移动操作。

内容的提问来源于stack exchange,提问作者Michal Granát

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 02:45:18