C# 如何添加到ObservableCollection<;T>;Getter中具有LINQ Where()的项?

C# 如何添加到ObservableCollection<;T>;Getter中具有LINQ Where()的项?,c#,linq,mvvm,C#,Linq,Mvvm,我最近在我的一个域实体中添加了一个禁用的属性。我有一个视图模型中这些实体的列表。我刚刚更改了getter,根据UI设置筛选列表,以选择性地显示禁用的项 public ObservableCollection<CustomVariableGroup> CustomVariableGroups { get { if (this.ShowDisabled) { return this._customVariableGroups; } ret

我最近在我的一个域实体中添加了一个禁用的属性。我有一个视图模型中这些实体的
列表。我刚刚更改了getter,根据UI设置筛选列表,以选择性地显示禁用的项

public ObservableCollection<CustomVariableGroup> CustomVariableGroups
{
    get
    {
        if (this.ShowDisabled) { return this._customVariableGroups; }

        return new ObservableCollection<CustomVariableGroup>(this._customVariableGroups.Where(x => x.Disabled == false));
    }
}
我想我知道为什么了:newGroup被添加到了新的
ObservableCollection
,而不是customVariableGroups的backing字段

如果LINQ Where()扩展方法能够返回
ObservableCollection
(私有支持字段本身的类型)而不是IEnumerable,我想我不会有这个问题。现在,由于Where()返回
IEnumerable
,因此我需要将其包装在一个新的
ObservableCollection


在同一视图模型中添加新项的正确/最佳方法是什么?我是否需要将其直接添加到私人支持字段?我不想这样做,因为我不想记住不要使用属性本身。

我会维护您的支持列表,然后为您的ObservableCollection提出更改的属性

this.CustomVariableGroups.Add(newGroup);
public ObservableCollection<CustomVariableGroup> CustomVariableGroups
{
    get
    {
        if (this.ShowDisabled) { return this._customVariableGroups; }

        return new ObservableCollection<CustomVariableGroup>  (this._customVariableGroups.Where(x => x.Disabled == false));
    }
}

// adds to the backing list but raises on property to rebuild and
// return the ObservableCollection
public void AddCustomVariableGroup(CustomVariableGroup newGroup)
{    
    this._customVariableGroups.Add(newGroup);
    OnPropertyChanged("CustomVariableGroups");
}

//Example invocation
AddCustomVariableGroup(newGroup);
PublicObservableCollection CustomVariableGroup
{
得到
{
如果(this.ShowDisabled){返回此。_customVariableGroups;}
返回新的observeCollection(this._customVariableGroups.Where(x=>x.Disabled==false));
}
}
//添加到支持列表,但在要重建的属性上引发
//返回ObservableCollection
public void AddCustomVariableGroup(CustomVariableGroup newGroup)
{    
此.\u customVariableGroups.Add(新组);
OnPropertyChanged(“CustomVariableGroup”);
}
//示例调用
AddCustomVariableGroup(新组);

我在WinPhone应用程序中显示过滤结果时遇到了类似的问题。我的解决方案是绑定到“ShowDisabled”属性更改,在这个事件中,只需
Clear()
,并将内容读入主要可观察对象:本例中的CustomVariableGroup。大概是这样的:

public bool ShowDisabled
{
    get
    {
        return showDisabled;
    }
    set
    {
        if (showDisabled!= value)
        {
            showDisabled = value;
            NotifyPropertyChanged("ShowDisabled");
        }
    }
}
在构造函数中添加以下内容:
this.PropertyChanged+=newpropertychangedventhandler(MyViewModel\u PropertyChanged)

在事件处理程序中:

 void MyViewModel_PropertyChanged(object sender, PropertyChangedEventArgs e)
 {
     if (e.PropertyName == "ShowDisabled")
     {
         CustomVariableGroups.Clear();
         foreach (var cvg in AllVariableGroups.Where(x => !x.Disabled))
         {
             CustomVariableGroups.Add(cvg);
         }
     }
 }
绑定到
CustomVariableGroup
的组件应相应更新


免责声明:当然,这会对性能产生影响,您需要确定它是否可以忽略。

我会做一些类似@Tallmaris的事情,但在
MyViewModel\u PropertyChanged中没有这样做:

     CustomVariableGroups.Clear();
     foreach (var cvg in CustomVariableGroups.Where(x => !x.Disabled))
     {
         CustomVariableGroups.Add(cvg);
     }
这样做:

     foreach(var cvg in CustomVariableGroups.Where( x => x.Disabled))
     {
         CustomVariableGroups.Remove(cvg);
     }
如果这不起作用(取决于是否可枚举。我认为哪里使用迭代器块),您可以这样做:

     foreach(var cvg in Custom VariableGroups.Where( x=> x.Disabled).ToList())
     {
         CustomVariableGroups.Remove(cvg);
     }

您可以绑定到ICollectionView并在禁用的属性中设置筛选器,而不是直接绑定到集合。无需更改源集合

this.CustomVariableGroups.Add(newGroup);
public ObservableCollection<CustomVariableGroup> CustomVariableGroups
{
    get
    {
        if (this.ShowDisabled) { return this._customVariableGroups; }

        return new ObservableCollection<CustomVariableGroup>  (this._customVariableGroups.Where(x => x.Disabled == false));
    }
}

// adds to the backing list but raises on property to rebuild and
// return the ObservableCollection
public void AddCustomVariableGroup(CustomVariableGroup newGroup)
{    
    this._customVariableGroups.Add(newGroup);
    OnPropertyChanged("CustomVariableGroups");
}

//Example invocation
AddCustomVariableGroup(newGroup);
编辑:

视图模型:

 //this collection just init once - eg. in ctor, use add, remove, clear to alter
 public ObservableCollection<CustomVariableGroup> CustomVariableGroups {get; private set; }
 //create just once in ctor
 public ICollectionView MyView {get; private set;}

 //ctor
 this.CustomVariableGroups = new ObservableCollection<CustomVariableGroup>();
 this.MyView = CollectionViewSource.GetDefaultView(this.CustomVariableGroups);

 //in your disabled property set the filter
    public bool ShowDisabled
    {
        get { return _showDisabled; }
        set { 
            _showDisabled = value;

            if (_showDisabled)
                //show just disabled
                this.MyView.Filter = (item) =>
                                         {
                                             var myitem = (CustomVariableGroup) item;
                                             return myitem.Disabled;
                                         };
            else
            {
                //show all
                this.MyView.Filter = (item) => { return true; };
            }


            this.NotifyPropertyChanged("ShowDisabled"); }
    }
//此集合只初始化一次-例如,在ctor中,使用add、remove、clear to alter
public ObservableCollection CustomVariableGroups{get;private set;}
//在ctor中只创建一次
公共ICollectionView MyView{get;private set;}
//执行器
this.CustomVariableGroups=新的ObservableCollection();
this.MyView=CollectionViewSource.GetDefaultView(this.CustomVariableGroups);
//在禁用的属性中,设置过滤器
公共图书馆
{
获取{return\u showDisabled;}
集合{
_showDisabled=值;
如果(_showDisabled)
//显示刚刚被禁用
this.MyView.Filter=(项目)=>
{
var myitem=(CustomVariableGroup)项;
返回myitem.Disabled;
};
其他的
{
//全部展示
this.MyView.Filter=(项)=>{return true;};
}
this.NotifyPropertyChanged(“ShowDisabled”);}
}
xaml



这在我的测试项目中起作用

正如评论中提到的,解决这一问题的正确方法是在视图中,而不是在视图模型中。这只是一个视图问题。我想我应该发布我是如何处理的,以防万一这对其他人有帮助

首先,getter(视图模型)每次都应该返回完整列表:

public ObservableCollection<CustomVariableGroup> CustomVariableGroups
{ get { return this._customVariableGroups; } }
然后,在代码隐藏中,我实现了过滤器:

private void CollectionViewSource_Filter(object sender, FilterEventArgs e)
{
    CustomVariableGroup customVariableGroup = e.Item as CustomVariableGroup;

    if (customVariableGroup == null) { return; }

    if ((bool)chkShowDisabled.IsChecked)
    {
        // Show everything
        e.Accepted = true;
        return;
    }

    // We are not showing disabled items, so set disabled items e.Accepted to false.
    if (customVariableGroup.Disabled == true)
    {
        e.Accepted = false;
        return;
    }

    e.Accepted = true;
}

关于这一点,我唯一不喜欢的是,我正在使用MVVM并试图避免类背后的代码。但是,拥有它比破解视图模型要好。

这就是我寻求帮助的原因,巴德。与其说它是坏的,你能建议如何使它正确吗?每次你调用你的属性时,都会创建一个新的可观察集合……在更高的级别上,代码
this.CustomVariableGroups.Add(newGroup)在哪里定位?您应该创建一次可观察的集合,并以某种方式同步这两个列表。CustomVariableGroup的类型是什么?您不能简单地创建一个集合源,并对该属性进行筛选吗?该代码位于同一视图模型类中,当用户想要添加新组时,会调用它。CustomVariableGroups的类型为
ObservableCollection
,如上面的代码所示。@SteveB我认为您给出了正确的答案:使用此属性上的筛选器创建一个集合源。视图模型代码不应根据视图想要过滤的内容进行更改。如果是视图问题,则应在视图中处理。这不起作用。通过在执行Linq查询之前清除集合,您正在查询一个空集合。哎哟,对不起,我只是从现有代码复制和粘贴并更改名称。当然,他需要从始终包含所有元素的支持属性进行查询,或者在清除集合之前进行查询,然后添加。我编辑了答案。@Tallmaris谢谢,但这看起来更像是
private void CollectionViewSource_Filter(object sender, FilterEventArgs e)
{
    CustomVariableGroup customVariableGroup = e.Item as CustomVariableGroup;

    if (customVariableGroup == null) { return; }

    if ((bool)chkShowDisabled.IsChecked)
    {
        // Show everything
        e.Accepted = true;
        return;
    }

    // We are not showing disabled items, so set disabled items e.Accepted to false.
    if (customVariableGroup.Disabled == true)
    {
        e.Accepted = false;
        return;
    }

    e.Accepted = true;
}