2

最近、ドメインエンティティの1つにDisabledプロパティを追加しました。ビューモデルにList<T>これらのエンティティが1つあります。無効になっているアイテムを選択的に表示するように、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);

そして、私はその理由を知っていると思います。_customVariableGroupsObservableCollection<T>のバッキングフィールドではなく、newGroupがnewに追加されています。

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

xaml

    <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

コメントで述べたように、これを解決する正しい方法は、ビューモデルではなく、ビューにあります。これはビューに関する問題のみです。これが他の誰かを助ける場合に備えて、私はそれをどのように処理したかを投稿すると思いました。

まず、ゲッター(ビューモデル)は毎回完全なリストを返す必要があります。

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

次に、ビューで、CollectionViewSourceにフィルターイベントを追加しました。

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

また、[無効にする]チェックボックスをクリックするたびにリストを更新するには、次のようにします。

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

私はあなたのバッキングリストを維持し、次にあなたの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 に答える
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 に答える