泛型继承类存储其父 ObservableCollection

问题描述 投票:0回答:1

我有几个收藏,每个都有特定的类别。我需要每个实例(模型)都存储其父集合(以便能够通过数据验证访问其他实例)。试图找到一些聪明的解决方案 - 开始怀疑是否有这样的。

到目前为止,我想出了以下内容。

通用基类:

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

    public int Id { get; set; }  // some generic prop
}

个人班(模特):

public class Model1: ModelBase<Model1>
{
    public string Name { get; set; } // Some specific prop

    // Data Error validation here, e.g. check of uniqueness
    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;

        // Initialize values
    }

    // Generic method - I would like to call this directly from command handler regardless of type T
    public void MoveItemUp(object parameter) 
    {

    }

}

用法:

CustomObservableCollection<Model1> Model1Collection = new (listOfModel1instances);

我也一直在尝试使用接口,但没有成功。

编辑1

我需要添加一些我在开始时忘记提及的信息。

在我的 CustomObservableCollection 类中,我希望有一些通用方法处理属于参数给定的 Item 的集合,例如

public int GetMaxId(t item)
{
     return item.Source.Max(i => i.Id);
}

我得到的: 错误 CS1061 'ICollection' 不包含 'Max' 的定义 ...

(给出的例子没有多大意义。但让我们假设,所有项目都具有 Order 属性。在命令处理程序中,我想对集合中的项目重新排序,例如,向上/向下移动选定的项目。在命令处理程序中,我所拥有的只是选定的项目由命令参数给出。
这将允许我对所有类型的项目只有一个命令。)

c# binding observablecollection
1个回答
0
投票

您的问题(以及您提供的附加信息)表明您集合中的项目需要访问父集合并且必须提供

Id
属性,例如,以便父集合可以使用 linq
Max
方法。

解决这两个目标的一种方法是定义一个像

ISourceAware
这样的接口,并通过在其声明中添加
CustomObservableCollection<T>
来约束
where T: ISourceAware
只接受实现它的项目。

public interface ISourceAware
{
    ICollection Source { get; set; }
    int Id { get; }
}
public class CustomObservableCollection<T> : ObservableCollection<T> where T: ISourceAware
{
    protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
    {
        base.OnCollectionChanged(e);
        if(e.Action.Equals(NotifyCollectionChangedAction.Add)) 
        {
            foreach (ISourceAware iitem in e.NewItems)
            {
                iitem.Source = this;
#if DEBUG
                var item = (Item)iitem;
                // Try a loopback test
                Console.WriteLine(
                    $"Index of {item.Description} is {item.ParentCollection.IndexOf(item)}");
#endif
            }
        }
    }
} 

集合处理自己的

CollectionChanged
通知,将自己设置为添加到其中的任何项目的
Source
。这解决了存储其父 ObservableCollection 的主要问题 - 您可以使用它进行验证,但您认为合适。


实现

ISourceAware
的类的最小示例:

public class Item : ISourceAware
{
    public string Description { get; set; } = string.Empty;
    public ICollection Source { get; set; }
    public CustomObservableCollection<Item> ParentCollection =>
        (CustomObservableCollection<Item>)Source;
    public int Id { get; set; }
}

测试

这是我为测试这个答案而编写的快速控制台代码。

static void Main(string[] args)
{
    Console.Title = "Test ISourceAware";
    var collection = new CustomObservableCollection<Item>();

    collection.Add(new Item { Description = "Item 1", Id = 1 });
    collection.Add(new Item { Description = "Item 2", Id = 2 });

    Console.WriteLine($"Min: {collection.Min(_ => _.Id)}");
    Console.WriteLine($"Max: {collection.Max(_ => _.Id)}");

    Console.ReadKey();
}

回复问题编辑

你发帖:

在我的 CustomObservableCollection 类中,我希望有一些通用方法处理属于参数给定的 Item 的集合,例如

public int GetMaxId(t item)
{
     return item.Source.Max(i => i.Id);
}

通常当你有一个

interface
类型时,你会想将它转换为它的基础类型,这是一个正确的方法的例子。

public class CustomObservableCollection<T> : ObservableCollection<T> where T: ISourceAware
{
    .
    .
    . 
    public static int GetMaxId(T item)
    {
        if (item.Source is ObservableCollection<T> items)
        {
            return items.Max(i => i.Id);
        }
        else throw new ArgumentException("Source must be an ObservableCollection<T>");
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.