2

ページにタブ コントロールがあります。その項目は ViewModel にバインドされます。これは、xaml の SelectedIndex プロパティに (双方向で) バインドされた ActiveTabItemIndex も公開し、INotifyPropertyChanged を実装して、TabControl がいつ更新するかを認識できるようにします。

これは (私が理解している) MVVM の正しい方法であり、99% 正しく動作します。

class MainWindowViewModel : BaseViewModel, INotifyPropertyChanged
{
    ObservableCollection<TabItemViewModel> _TabItems;
    int _ActiveTabItemIndex;

    public event PropertyChangedEventHandler PropertyChanged;

    protected void RaisePropertyChanged(string name)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
            handler(this, new PropertyChangedEventArgs(name));
    }

    void _TabItems_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
    {
        if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add)
            _ActiveTabItemIndex = _TabItems.IndexOf((TabItemViewModel)e.NewItems[0]);
        RaisePropertyChanged("ActiveTabItemIndex");
    }

    public ObservableCollection<TabItemViewModel> TabItems
    {
        get
        {
            if (_TabItems == null)
            {
                _TabItems = new ObservableCollection<TabItemViewModel>();
                _TabItems.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(_TabItems_CollectionChanged);
            }
            return _TabItems;
        }
    }

    public int ActiveTabItemIndex
    {
        get
        {
            return _ActiveTabItemIndex;
        }
        set
        {
            _ActiveTabItemIndex = value;
        }
    }
}

このようにして、TabItems コレクションに対して行った操作はすべて TabControl に反映され、新しい項目を追加すると、その項目が自動的に選択されます。これはうまくいきます。ただし、最初の項目を空のタブ コントロールに追加すると、次のようになります。

タブの内容は表示されているがタブが選択されていない

タブの内容は表示されますが、タブは選択されていません。タブを正しく表示するには、手動でタブをクリックする必要があります。

タブの内容が表示され、タブが選択されている

タブの描画とその内容の描画の間にある種の断絶があるかのようです。後続のタブが正しく処理され、バインディングを完全に削除すると、タブが手動で選択されるまで最初のページの内容が表示されないため、バインディングが機能していることがわかります。誰かがこれを見た、または光を当てることができれば、それは非常に高く評価されます! 皆さん、ありがとうございました :)

4

1 に答える 1

2

セッターでプロパティ変更イベントのみを発生させます。プロパティ自体が「変更」の意味を決定できるようにし、さらに拡張して、イベントがいつ発生するかを制御できるようにする (そして期待どおりに動作させる) と考えることができます。

public int ActiveTabItemIndex
{
    get{ return _ActiveTabItemIndex; }
    set
    {
        if(_ActiveTabItemIndex != value)
        {
            _ActiveTabItemIndex = value;
            RaisePropertyChanged("ActiveTabItemIndex");
        }
    }
}

変えるだけ

_ActiveTabItemIndex = _TabItems.IndexOf(...);

ActiveTabItemIndex = _TabItems.IndexOf(...);

_TabItems_CollectionChanged から RaisePropertyChanged 呼び出しを削除します

プロパティのセッターの外でプロパティ変更通知を発生させる必要がある場合がありますが、それははるかに複雑な日のためです:)

余談ですが、BaseViewModel に INotifyPropertyChanged を実装する必要があります。絶対に素晴らしいMVVM Light Toolkitをチェックしてください。これには、MVVM を使用するすべてのプロジェクトで複製しなければならないすべてのコードが含まれています。

于 2012-08-28T19:19:20.063 に答える