在GroupBy上使用带有ObservableCollection的LINQ [英] Using LINQ on ObservableCollection with GroupBy

查看:141
本文介绍了在GroupBy上使用带有ObservableCollection的LINQ的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

 private ObservableCollection< DtSource> _PieChartDB; 

public ObservableCollection< DtSource> PieChartDB
{
get
{
return _PieChartDB.GroupBy(x => x.Name);
}
设置
{
if(_PieChartDB!= value)
{
_PieChartDB = value;
OnPropertyChanged(PieChartDB);

}
}
}

我收到此错误:

无法隐式转换类型'System.Collections。 Generic.IEnumerable< System.Linq.IGrouping< string,DataSource1.Model.Entity.DtSource>>'to'System.Collections.ObjectModel.ObservableCollection< DataSource1.Model.Entity.DtSource>'。存在显式转换(您是否错过了转换?)

解决方案

错误消息直接告诉您属性的返回值必须是预期的财产类型。这表明你需要另一种策略......如果......



我认为你的意图是:



1.实现DtSource实例的Observable集合,您可以在其中生成有关集合的基本操作的通知,例如:'添加',删除。



2.同时,维护一个更新的数据结构,其中DtSource实例是使用Linq按类名称属性/密钥分组。



此处显示的代码基于这两个假设;如果其中任何一个不正确,请告诉我,我将删除此帖子。

  //  必需 
使用 System.Collections.Generic;
使用 System.Collections.Specialized;

// 在某些NameSpace中使用
public class GroupedObservableCollection< T> :List< T> ;,INotifyCollectionChanged
{
// ctor
public GroupedObservableCollection(){}

private int baseCount = 0 ;

public event NotifyCollectionChangedEventHandler CollectionChanged;

public new void 添加(T项)
{
base .Add(item);

if (CollectionChanged!= null
{
CollectionChanged( this new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add,item, .Count之间));
}

baseCount ++;
}

public new void 删除(T项目)
{
if (!base.Contains(item))返回; // 抛出错误?

int ndx = base .IndexOf(item);

删除(ndx,item);
}

public void 删除( int ndx,T item = default (T))
{
if (ndx > baseCount) return ; // 抛出错误?

.RemoveAt(NDX);

if (CollectionChanged!= null
{
CollectionChanged( this new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove,item,ndx));
}

baseCount--;
}

public new void Clear()
{
if (baseCount == 0 return ; // 抛出错误?

.Clear();

if (CollectionChanged!= null
{
CollectionChanged( this new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}

baseCount = 0 ;
}

public void 移动( int ndx1, int ndx2)
{
if (ndx1 > = baseCount || ndx2 > = baseCount)返回; // 抛出错误?

T temp = [NDX1];
base [ndx1] = base [ndx2];
base [ndx2] = temp;

if (CollectionChanged!= null
{
CollectionChanged( this new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Move, this ,ndx1,ndx2));
}
}

public void 替换( int ndx1,T item)
{
if (ndx1 > = baseCount) return ; // 抛出错误?

base [ndx1] = item;

if (CollectionChanged!= null
{
CollectionChanged( this new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace,item, [NDX1]));
}
}
}

我将此类设为Generic,因此我可以将其与不同类型的对象一起使用。使它成为通用的结果是你不能在其中粘贴一个函数来返回Collection(List)GroupedBy T类型的一些特定属性(Key)(当你可能能够使用Reflection做那个,我会说疯狂)。



所以,策略2是使用这个泛型的一个实例类以一种方式保持GroupedBy集合在生成通知时更新:

  //  需要Linq  
// 在表单或使用Collection的其他代码上下文中:

public GroupedObservableCollection< AnyOldClass> test = new GroupedObservableCollection< AnyOldClass>();

// 按名称分组的集合
public IEnumerable< Igrouping>< string,>> CollectionCurrentGroups;

// 当集合发生变化时调用的事件处理程序:
private void TestOnCollectionChanged( object sender,NotifyCollectionChangedEventArgs e)
{
switch (e.Action)
{
// 设置断点此处并使用'e
中的相应参数验证操作是否已被调用 // 在此处为每种类型的事件添加代码处理程序:

< span class =code-keyword> case NotifyCollectionChangedAction.Add:
UpdateGroupCollection(test);
break ;
case NotifyCollectionChangedAction.Remove:
UpdateGroupCollection(test);
break ;
case NotifyCollectionChangedAction.Move:
// 这里不需要更新?
break ;
case NotifyCollectionChangedAction.Replace:
UpdateGroupCollection(test);
break ;
case NotifyCollectionChangedAction.Reset:
CollectionCurrentGroups = null ;
break ;
}
}

私有 void UpdateGroupCollection( GroupedObservableCollection< AnyOldClass> collection)
{
CollectionCurrentGroups = collection.GroupBy(nm = > nm.Name);
}

// 使用示例:在某些方法中,或在某个方法中表单加载事件等
// 设置断点,检查'CollectionCurrentGroups 的价值
test.CollectionChanged + = TestOnCollectionChanged;
test.Add( new AnyOldClass( 你好));
test.Remove(test [ 0 ]);
test.Clear();
test.Add( new AnyOldClass( 再见));
test.Add( new AnyOldClass( 你好再次));
test.Add( new AnyOldClass( 再见));
test.Add( new AnyOldClass( 你好再次));
test.Move( 0 1 );
test.Replace( 1 new AnyOldClass( what));
test.Clear();
test.Clear();

这里是用于测试的简单类:

  public  < span class =code-keyword> class  AnyOldClass 
{
public string 名称{ set ; get ; }

public AnyOldClass( string name)
{
Name = name;
}
}

警告:与您在此处看到的所有代码示例或StackOverFlow等一样,您有责任确保它们在您使用它们的上下文中工作。像这样的代码应该被视为仅用于教育目的的示例,并且仅在经过广泛,仔细的测试之后才在生产代码中使用!


执行Linq将返回 IGrouping< tkey,dtsource> 项。这不能转换为 ObservableCollection< dtsource>< / dtsource>



如果你想要聚合,那么你将在转换为 ObservableCollection< dtsource>< / dtsource>


private ObservableCollection<DtSource> _PieChartDB;

        public ObservableCollection<DtSource> PieChartDB
        {
            get
            {
                return _PieChartDB.GroupBy(x => x.Name); 
            }
            set
            {
                if (_PieChartDB != value)
                {
                    _PieChartDB = value;
                    OnPropertyChanged("PieChartDB");

                }
            }
        }

I am getting this error:

Cannot implicitly convert type 'System.Collections.Generic.IEnumerable<System.Linq.IGrouping<string,DataSource1.Model.Entity.DtSource>>' to 'System.Collections.ObjectModel.ObservableCollection<DataSource1.Model.Entity.DtSource>'. An explicit conversion exists (are you missing a cast?)	

解决方案

The error message tells you directly that the return value of the Property must be the expected Type of the Property. That indicates to me you need another strategy here ... if ...

I assume that your intention is:

1. to implement an Observable Collection of instances of DtSource, where you generate notifications of basic actions on the Collection like: 'Add, 'Remove.

2. at the same time, to maintain an updated data structure in which the DtSource instances are 'Grouped using Linq by the Class 'Name property/key.

The code shown here is based on those two assumptions; if either is incorrect, let me know, and I will remove this post.

// required
using System.Collections.Generic;
using System.Collections.Specialized;

// use in some NameSpace
public class GroupedObservableCollection<T> : List<T>, INotifyCollectionChanged
{
    // ctor
    public GroupedObservableCollection(){}

    private int baseCount = 0;

    public event NotifyCollectionChangedEventHandler CollectionChanged;

    public new void Add(T item)
    {
        base.Add(item);

        if (CollectionChanged != null)
        {
            CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item, base.Count));
        }

        baseCount++;
    }

    public new void Remove(T item)
    {
        if (!base.Contains(item)) return; // throw error ?

        int ndx = base.IndexOf(item);

        Remove(ndx, item);
    }

    public void Remove(int ndx, T item = default(T))
    {
        if (ndx > baseCount) return; // throw error ?

        base.RemoveAt(ndx);

        if (CollectionChanged != null)
        {
            CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, item, ndx));
        }

        baseCount--;
    }

    public new void Clear()
    {
        if (baseCount == 0) return; // throw error ?

        base.Clear();

        if (CollectionChanged != null)
        {
            CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
        }

        baseCount = 0;
    }

    public void Move(int ndx1, int ndx2)
    {
        if (ndx1 >= baseCount || ndx2 >= baseCount) return;  // throw error ?

        T temp = base[ndx1];
        base[ndx1] = base[ndx2];
        base[ndx2] = temp;

        if (CollectionChanged != null)
        {
            CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Move, this, ndx1, ndx2));
        }
    }

    public void Replace(int ndx1, T item)
    {
        if (ndx1 >= baseCount) return; // throw error ?

        base[ndx1] = item;

        if (CollectionChanged != null)
        {
            CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, item, base[ndx1]));
        }
    }
}

I made this class Generic, so I could re-use it with different Types of Objects. An outcome of making it generic is that you can't stick a function in it to return the Collection (List) GroupedBy some specific property (Key) of the Type of T (while you might be able to do that using Reflection, I'd say that would be crazy).

So, strategy 2 is to use an instance of this generic class in a way that keeps a GroupedBy collection updated as notifications are generated:

// requires Linq
// in a Form, or other code-context where the Collection is used:

public GroupedObservableCollection<AnyOldClass> test = new GroupedObservableCollection<AnyOldClass>();

// collection in grouped by name form
public IEnumerable<Igrouping><string,>> CollectionCurrentGroups;

// event-handler that is called when the Collection changes:
private void TestOnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
    switch (e.Action)
    {
        // set break-points here and verify action is invoked with appropriate parameters in 'e
        // add your code handlers for each type of event here:

        case NotifyCollectionChangedAction.Add:
            UpdateGroupCollection(test);
            break;
        case NotifyCollectionChangedAction.Remove:
            UpdateGroupCollection(test);
            break;
        case NotifyCollectionChangedAction.Move:
            // update not needed here ?
            break;
        case NotifyCollectionChangedAction.Replace:
            UpdateGroupCollection(test);
            break;
        case NotifyCollectionChangedAction.Reset:
            CollectionCurrentGroups = null;
            break;
    }
}

private void UpdateGroupCollection(GroupedObservableCollection<AnyOldClass> collection)
{
    CollectionCurrentGroups = collection.GroupBy(nm => nm.Name);
}

// example of use: in some method, or in a Form Load event, etc.
// set break-points, inspect the value of 'CollectionCurrentGroups
test.CollectionChanged += TestOnCollectionChanged;
test.Add(new AnyOldClass("hello"));
test.Remove(test[0]);
test.Clear();
test.Add(new AnyOldClass("goodbye"));
test.Add(new AnyOldClass("hello again"));
test.Add(new AnyOldClass("goodbye"));
test.Add(new AnyOldClass("hello again"));
test.Move(0,1);
test.Replace(1, new AnyOldClass("what"));
test.Clear();
test.Clear();

Here's the simple Class used for testing here:

public class AnyOldClass
{
    public string Name { set; get; }

    public AnyOldClass(string name)
    {
        Name = name;
    }
}

Caution: as with all code examples you might see here, or on StackOverFlow, etc., it is your responsibility to make sure they work in the context you use them in. Code like this should be regarded as an example for educational purposes only, and used in "production" code only after extensive, careful, testing !


Performing the Linq will return a IGrouping<tkey,dtsource> item. This cannot be cast to ObservableCollection<dtsource></dtsource>

If you want aggregates then you will need to select the results from the IGrouping into a DTSource Type before casting as a ObservableCollection<dtsource></dtsource>.


这篇关于在GroupBy上使用带有ObservableCollection的LINQ的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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