2

我最近向我的一个域实体添加了一个 Disabled 属性。我List<T>在视图模型中有一个这些实体。我只是更改了 getter 以根据 UI 设置过滤列表,以选择性地显示禁用的项目。

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

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

问题是当我现在尝试执行此操作时(在同一视图模型中),该项目不会添加到集合中。

this.CustomVariableGroups.Add(newGroup);

而且我想我知道为什么:newGroup 被添加到 newObservableCollection<T>中,而不是 _customVariableGroups 的支持字段。

如果 LINQ Where() 扩展方法能够返回ObservableCollection<T>(私有支持字段本身的类型)而不是 IEnumerable,我认为我不会遇到这个问题。就目前而言,由于 Where() 返回IEnumerable<T>,我需要将其包装在一个新的ObservableCollection<T>.

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

4

5 回答 5

1

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

编辑:

视图模型:

 //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"); }
    }

xml

    <CheckBox Content="ShowDisabled" IsChecked="{Binding ShowDisabled}"/>
    <ListBox ItemsSource="{Binding MyView}" Grid.Row="1">
        <ListBox.ItemTemplate>
            <DataTemplate>
                <TextBlock Text="{Binding Name}"/>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>

这在我的测试项目中有效

于 2012-07-24T14:10:39.213 回答
1

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

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

public ObservableCollection<CustomVariableGroup> CustomVariableGroups
{ get { return this._customVariableGroups; } }

然后,在视图中,我将过滤器事件添加到我的 CollectionViewSource:

<CollectionViewSource x:Key="SortedGroups" Source="{Binding CustomVariableGroups}" Filter="CollectionViewSource_Filter">

并在每次单击 Show Disabled 复选框时刷新列表:

Command="{Binding RefreshVariableGroupCommand}"

然后,在后面的代码中,我实现了过滤器:

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 并试图避免代码隐藏类。但是,拥有这个比破解视图模型更好。

于 2012-07-24T16:43:09.550 回答
0

我会做类似@Tallmaris 的事情,但不是在MyViewModel_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);
     }

如果这不起作用(取决于 Enumerable.Where 是否使用迭代器块,我认为),你可以这样做:

     foreach(var cvg in Custom VariableGroups.Where( x=> x.Disabled).ToList())
     {
         CustomVariableGroups.Remove(cvg);
     }
于 2012-07-24T13:57:53.977 回答
0

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

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);
于 2012-07-24T13:48:18.020 回答
0

在显示过滤结果时,我在 WinPhone 应用程序中遇到了类似的问题。我的解决方案是绑定到“ShowDisabled”属性更改,并在此事件上简单地Clear()将内容读入主 Observable:在这种情况下为 CustomVariableGroups。像这样的东西:

public bool ShowDisabled
{
    get
    {
        return showDisabled;
    }
    set
    {
        if (showDisabled!= value)
        {
            showDisabled = value;
            NotifyPropertyChanged("ShowDisabled");
        }
    }
}

在构造函数中添加:this.PropertyChanged += new PropertyChangedEventHandler(MyViewModel_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);
         }
     }
 }

绑定到 的组件CustomVariableGroups应该相应地更新。

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

于 2012-07-24T13:49:29.077 回答