泛型继承类存储父级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);
遇到的问题
- 编写
GetMaxId方法时出现错误:Error CS1061 'ICollection' does not contain a definition for 'Max'public int GetMaxId(t item) { return item.Source.Max(i => i.Id); } - 需要实现通用命令处理程序,仅通过传入选中项作为参数,完成所有类型项的上下移动排序操作,无需为每种类型单独写命令。
解决方案
问题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
相关产品推荐
相关产品推荐

