绑定到TabControl的SelectedIndex

3

我在页面上有一个标签控件;它的项目绑定回我的ViewModel,这个ViewModel还公开了ActiveTabItemIndex,该属性与我的xaml中SelectedIndex属性进行双向绑定,并实现了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上,当我添加新项时,它会自动选择。这个方法非常有效; 然而,当向空选项卡控件添加第一个项目时,它看起来像这样: Tab contents displayed but tab not selected 选项卡内容被显示,但是选项卡没有被选择。我需要手动单击选项卡来使其正确显示: Tab contents displayed and tab selected 好像选项卡的绘制与其内容的绘制之间存在某种断开。 我知道绑定正在工作,因为后续的选项卡被正确处理,如果我完全删除绑定,则第一页直到手动选择选项卡后才会显示其内容。 如果有人看到了这个问题或可以提供一些信息,那将不胜感激! 谢谢大家 :)

也许与这个问题(在winforms中)的解决方案相同。链接 - Gert Arnold
1个回答

3
只在setter方法中引发属性更改事件;您可以将其视为允许属性本身决定什么是“changed”,从而使其控制事件何时被触发(并使其执行您期望的操作)。
public int ActiveTabItemIndex
{
    get{ return _ActiveTabItemIndex; }
    set
    {
        if(_ActiveTabItemIndex != value)
        {
            _ActiveTabItemIndex = value;
            RaisePropertyChanged("ActiveTabItemIndex");
        }
    }
}

仅仅改变

_ActiveTabItemIndex = _TabItems.IndexOf(...);

to

ActiveTabItemIndex = _TabItems.IndexOf(...);

并且从_TabItems_CollectionChanged中删除RaisePropertyChanged调用

有时候,您需要在属性的setter之外引发属性更改通知,但那是为一个更加复杂的日子保留的 :)

顺便提一下,INotifyPropertyChanged应该在您的BaseViewModel上实现。查看绝对精彩的MVVM Light Toolkit - 它包含了您在使用MVVM的每个项目中必须重复的所有代码。


太棒了!非常感谢humanitas - 这正是我所需要的;而if(_ActiveTabItemIndex != value)部分也证明至关重要。此外,关于将INotifyPropertyChanged实现放在baseviewmodel中的建议很好;我现在已经将它移动到那里了! - Adrian Hand

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接