ObservableCollection包装器转换为基本类型 [英] ObservableCollection wrapper to cast to a base type

查看:161
本文介绍了ObservableCollection包装器转换为基本类型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个名为 Client 的类,它是 Configurable 的子类。



我有一个 ObservableCollection< Client> ,我需要将它看作 ObservableCollection<配置> 。这将允许我从一些通用布局生成代码中将数据绑定到列表。它还必须允许我清除列表,并将项目添加到列表中。当然,向列表添加项目时,它必须执行运行时类型检查以验证正在添加的常规项目( Configurable )是否为适当的类型( Client )。



我想象一个叫做 ObservableSurrogateCollection< T> T 是普通类( Configurable )。你可以通过交给它来构造一个 ObservableCollection ,其中 T2 Ť。您可以对其进行数据绑定,并且包裹列表上的所有收集已更改事件均正确路由(双向)。



这是否存在?这不是我应该做的事吗?我认为我读过.NET 4.0将在语言级别支持这种功能?



我已经看过这些选项:




  • ReadOnlyObservableCollection< T> 。这非常接近。但是,因为它是只读的,我无法添加或清除项目。

  • 非通用的 ObservableCollection 。如果它存在,我似乎无法找到它。



预先感谢您的帮助! 不,这不存在AFAIK,但不应该很难实施;它当然会涉及变化的细微差别,因此您的收藏集在分配/添加时必须预期投射问题。请注意,数组( T [] 已经 就像这样(参考类型的数组具有方差支持,类型检查等),但是不能添加到数组中,并且不会触发更改事件。



实现这个主要是封装工作;对象构造(当数据绑定到新行时)会是棘手的问题,并且可能会强制您添加额外的接口。

4.0在这里不会添加任何内容:<一个href =http://marcgravell.blogspot.com/2009/02/what-c​​-40-covariance-doesn-do.html =nofollow noreferrer>什么C#4.0协方差*不做* / b>

未测试,但是:

  public class ObservableCollection< TBase,实际> :IList< TBase>,IBindingList,INotifyCollectionChanged 
其中,TBase:class
其中TActual:class,TBase
{

private readonly ObservableCollection< TActual> innerList;
$ b $ public ObservableCollection()
:this((IEnumerable< TActual>)null){}
public ObservableCollection(IEnumerable< TBase> data)
:this == null null:data.Cast< TActual>()){}
public ObservableCollection(IEnumerable< TActual> data)
{
innerList = data == null?新的ObservableCollection< TActual>()
:new ObservableCollection< TActual>(data);
innerList.CollectionChanged + = new NotifyCollectionChangedEventHandler(innerList_CollectionChanged);
}

void innerList_CollectionChanged(object sender,NotifyCollectionChangedEventArgs e)
{
ListChangedEventHandler handler = ListChanged;
if(handler!= null){
ListChangedEventArgs args = null;
switch(e.Action)
{
case NotifyCollectionChangedAction.Add:
args = new ListChangedEventArgs(ListChangedType.ItemAdded,e.NewStartingIndex);
休息;
case NotifyCollectionChangedAction.Remove:
args = new ListChangedEventArgs(ListChangedType.ItemDeleted,e.OldStartingIndex);
休息;
case NotifyCollectionChangedAction.Reset:
args = new ListChangedEventArgs(ListChangedType.Reset,-1);
休息;
case NotifyCollectionChangedAction.Replace:
args = new ListChangedEventArgs(ListChangedType.ItemChanged,e.NewStartingIndex);
休息;
case NotifyCollectionChangedAction.Move:
args = new ListChangedEventArgs(ListChangedType.ItemMoved,e.NewStartingIndex,e.OldStartingIndex);
休息;
}
if(args!= null)handler(this,args);
}
NotifyCollectionChangedEventHandler handler2 = CollectionChanged;
if(handler2!= null)handler2(this,e);

$ b公共无效AddIndex(PropertyDescriptor属性){

公共对象AddNew()
{
实际值=(实际值) Activator.CreateInstance(typeof运算(触觉));
Add(obj);
return obj;
}

public bool AllowEdit {get {return!IsReadOnly; }}
public bool AllowNew {get {return!IsFixedSize; }}
public bool AllowRemove {get {return!IsFixedSize; }}
$ b $ public void ApplySort(PropertyDescriptor property,ListSortDirection direction)
{
throw new System.NotImplementedException();


public int Find(PropertyDescriptor property,object key)
{
throw new System.NotImplementedException();
}

public bool IsSorted {get {return false; }}

公共事件ListChangedEventHandler ListChanged;
公共事件NotifyCollectionChangedEventHandler CollectionChanged;
$ b $ public void RemoveIndex(PropertyDescriptor property){}
$ b public void RemoveSort()
{
throw new System.NotImplementedException();
}

public ListSortDirection SortDirection
{
get {return ListSortDirection.Ascending; }
}

public PropertyDescriptor SortProperty
{
get {throw new System.NotImplementedException(); }
}

public bool SupportsChangeNotification {get {return true; }}
public bool SupportsSearching {get {return false; }}
public bool SupportsSorting {get {return false; }}

int IList.Add(object value)
{
int index = innerList.Count;
Add((TBase)值);
回报指数;
}
public void Add(TBase value)
{
innerList.Add((Tactual)value);
}

public void Clear()
{
innerList.Clear();


bool IList.Contains(object value)
{
return Contains((TBase)value);
}
public bool Contains(TBase value)
{
return innerList.Contains((Tactual)value);


int IList.IndexOf(object value)
{
return IndexOf((TBase)value);
}
public int IndexOf(TBase value)
{
return innerList.IndexOf((Tactual)value);
}

void IList.Insert(int index,object value)
{
Insert(index,(TBase)value);
}
public void Insert(int index,TBase value)
{
innerList.Insert(index,(TActual)value);
}

public bool IsFixedSize
{
get {return((IList)innerList).IsFixedSize; }
}

public bool IsReadOnly
{
get {return((IList)innerList).IsReadOnly; }($)


void IList.Remove(object value)
{
删除((TBase)value);
}
public bool删除(TBase值)
{
return innerList.Remove((TActual)value);
}

public void RemoveAt(int index)
{
innerList.RemoveAt(index);
}

对象IList.this [int index]
{
get {return innerList [index]; }
set {innerList [index] =(TActual)value; }
}
public TBase this [int index]
{
get {return innerList [index]; }
set {innerList [index] =(TActual)value; }


void ICollection.CopyTo(System.Array array,int index)
{
((IList)innerList).CopyTo(array,index);
}
public void CopyTo(TBase [] array,int index)
{
innerList.CopyTo((Tactual [])array,index);
}

public int Count {get {return innerList.Count; }}

public bool IsSynchronized
{
get {return((IList)innerList).IsSynchronized; }
}

公共对象SyncRoot
{
get {return((IList)innerList).SyncRoot; }
}

public IEnumerator< TBase> GetEnumerator()
{
return innerList.Cast< TBase>()。GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return innerList.GetEnumerator();
}
}


I have a class called Client, which is a subclass of Configurable.

I have an ObservableCollection<Client> which I need to view as an ObservableCollection<Configurable>. This will allow me to databind to the list from some general layout generation code. It must also allow me to clear the list, and to add items to the list. Of course, when adding items to the list it must do a runtime type check to verify the general item (Configurable) being added is of the appropriate type (Client).

I am imagining a class called something like ObservableSurrogateCollection<T>. T is the general class (Configurable). You would construct it by handing it an ObservableCollection<T2>, where T2 is a subclass of T. You can databind to it, and all collection changed events on the wrapped list are correctly routed (both directions).

Does this exists? Is this not something I should be doing? I think I read that .NET 4.0 will support such a feature at the language level?

I have looked at these options:

  • ReadOnlyObservableCollection<T>. This is really close. However, because it is read-only I can't add or clear the items.
  • A non-generic ObservableCollection. I can't seem to find this, if it exists.

Thanks in advance for any help!

解决方案

No, that doesn't exist AFAIK, but shouldn't be hard to implement; it does, of course, involve the nuances of variance, so your collection must expect casting problems when assigning/adding. Note that arrays (T[]) already act like this (arrays of reference-types have variance support, with typecast checking etc), but you can't add to an array, and it doesn't fire change events.

To implement this would largely be an encapsulation job; object construction (when data-binding to new rows) would be the tricky bit, and may force you to add extra interfaces.

4.0 won't add anything here: What C# 4.0 covariance *doesn't* do

Untested, but:

public class ObservableCollection<TBase, TActual> : IList<TBase>, IBindingList, INotifyCollectionChanged
    where TBase : class
    where TActual : class, TBase
{

    private readonly ObservableCollection<TActual> innerList;

    public ObservableCollection()
        : this((IEnumerable<TActual>)null) {}
    public ObservableCollection(IEnumerable<TBase> data)
        : this(data == null ? null : data.Cast<TActual>()) {}
    public ObservableCollection(IEnumerable<TActual> data)
    {
        innerList = data == null ? new ObservableCollection<TActual>()
            : new ObservableCollection<TActual>(data);
        innerList.CollectionChanged += new NotifyCollectionChangedEventHandler(innerList_CollectionChanged);
    }

    void innerList_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        ListChangedEventHandler handler = ListChanged;
        if(handler != null) {
            ListChangedEventArgs args = null;
            switch (e.Action)
            {
                case NotifyCollectionChangedAction.Add:
                    args = new ListChangedEventArgs(ListChangedType.ItemAdded, e.NewStartingIndex);
                    break;
                case NotifyCollectionChangedAction.Remove:
                    args = new ListChangedEventArgs(ListChangedType.ItemDeleted, e.OldStartingIndex);
                    break;
                case NotifyCollectionChangedAction.Reset:
                    args = new ListChangedEventArgs(ListChangedType.Reset, -1);
                    break;
                case NotifyCollectionChangedAction.Replace:
                    args = new ListChangedEventArgs(ListChangedType.ItemChanged, e.NewStartingIndex);
                    break;
                case NotifyCollectionChangedAction.Move:
                    args = new ListChangedEventArgs(ListChangedType.ItemMoved, e.NewStartingIndex, e.OldStartingIndex);
                    break;
            }
            if(args != null) handler(this, args);
        }
        NotifyCollectionChangedEventHandler handler2 = CollectionChanged;
        if (handler2 != null) handler2(this, e);
    }

    public void AddIndex(PropertyDescriptor property) {}

    public object AddNew()
    {
        TActual obj = (TActual)Activator.CreateInstance(typeof(TActual));
        Add(obj);
        return obj;
    }

    public bool AllowEdit { get { return !IsReadOnly; } }
    public bool AllowNew { get { return !IsFixedSize; } }
    public bool AllowRemove { get { return !IsFixedSize; } }

    public void ApplySort(PropertyDescriptor property, ListSortDirection direction)
    {
        throw new System.NotImplementedException();
    }

    public int Find(PropertyDescriptor property, object key)
    {
        throw new System.NotImplementedException();
    }

    public bool IsSorted { get { return false; } }

    public event ListChangedEventHandler ListChanged;
    public event NotifyCollectionChangedEventHandler CollectionChanged;

    public void RemoveIndex(PropertyDescriptor property) { }

    public void RemoveSort()
    {
        throw new System.NotImplementedException();
    }

    public ListSortDirection SortDirection
    {
        get { return ListSortDirection.Ascending; }
    }

    public PropertyDescriptor SortProperty
    {
        get { throw new System.NotImplementedException(); }
    }

    public bool SupportsChangeNotification { get { return true; } }
    public bool SupportsSearching { get { return false; } }
    public bool SupportsSorting { get { return false; } }

    int IList.Add(object value)
    {
        int index = innerList.Count;
        Add((TBase)value);
        return index;
    }
    public void Add(TBase value)
    {
        innerList.Add((TActual)value);
    }

    public void Clear()
    {
        innerList.Clear();
    }

    bool IList.Contains(object value)
    {
        return Contains((TBase)value);
    }
    public bool Contains(TBase value)
    {
        return innerList.Contains((TActual)value);
    }

    int IList.IndexOf(object value)
    {
        return IndexOf((TBase)value);
    }
    public int IndexOf(TBase value)
    {
        return innerList.IndexOf((TActual)value);
    }

    void IList.Insert(int index, object value)
    {
        Insert(index, (TBase)value);
    }
    public void Insert(int index, TBase value)
    {
        innerList.Insert(index, (TActual)value);
    }

    public bool IsFixedSize
    {
        get { return ((IList)innerList).IsFixedSize; }
    }

    public bool IsReadOnly
    {
        get { return ((IList)innerList).IsReadOnly; }
    }

    void IList.Remove(object value)
    {
        Remove((TBase)value);
    }
    public bool Remove(TBase value)
    {
        return innerList.Remove((TActual)value);
    }

    public void RemoveAt(int index)
    {
        innerList.RemoveAt(index);
    }

    object IList.this[int index]
    {
        get { return innerList[index]; }
        set { innerList[index] = (TActual)value; }
    }
    public TBase this[int index]
    {
        get { return innerList[index]; }
        set { innerList[index] = (TActual)value; }
    }

    void ICollection.CopyTo(System.Array array, int index)
    {
        ((IList)innerList).CopyTo(array, index);
    }
    public void CopyTo(TBase[] array, int index)
    {
        innerList.CopyTo((TActual[])array, index);
    }

    public int Count { get { return innerList.Count; } }

    public bool IsSynchronized
    {
        get { return ((IList)innerList).IsSynchronized; }
    }

    public object SyncRoot
    {
        get { return ((IList)innerList).SyncRoot; }
    }

    public IEnumerator<TBase> GetEnumerator()
    {
        return innerList.Cast<TBase>().GetEnumerator();
    }
    IEnumerator IEnumerable.GetEnumerator()
    {
        return innerList.GetEnumerator();
    }
}

这篇关于ObservableCollection包装器转换为基本类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆