【问题标题】:WPF MVVM firing code based on Tab SelectedValue, rather than SelectedIndexWPF MVVM 触发代码基于 Tab SelectedValue,而不是 SelectedIndex
【发布时间】:2014-10-28 01:48:56
【问题描述】:

在带有 MVVM 的 WPF 中,当用户更改选项卡时,很容易触发一些代码。

<TabControl Margin="0 5 5 5" Background="#66F9F9F9" SelectedIndex="{Binding TabIndex}">

然后在 ViewModel 中:

private int _tabIndex;
public int TabIndex
{
    get { return _tabIndex; }
    set
    {
        if(_tabIndex != value)
        {
            _tabIndex = value;
            OnPropertyChanged("TabIndex");

            if(value == 1)
            {
                //do something
            }
        }
    }
}

但我对此感到隐隐不安。如果另一个开发人员稍后发生并在“1”位置添加另一个选项卡怎么办。如果这是对应用程序至关重要的代码(确实如此),那么事情将会非常糟糕。

当然,单元测试可以将危险降到最低。但这让我想知道:这是否被视为不好的做法?有没有一种方法可以让您使用字符串而不是 int 来引用 Tab?我尝试绑定到SelectedValue 属性,但更改选项卡时似乎没有任何反应。

【问题讨论】:

  • 我也会担心这一点。另一个警告标志是在视图模型中有一个选项卡索引,意味着在视图模型中有基于视图的逻辑,这打破了视图和逻辑的分离。更换标签时需要完成什么?
  • @sondergard 初始选项卡允许用户选择多个对象,这些对象需要在切换到使用新数据的第二个选项卡之前创建并保存到数据库中。

标签: c# wpf mvvm


【解决方案1】:

您可以为 TabItem 创建一个行为,侦听 IsSelected 依赖项属性的更改,并在选择选项卡时引发一个命令。这可以扩展到任意数量的选项卡,每个选项卡在视图模型中调用不同的命令。您还可以为任何可选上下文提供命令参数:

class TabSelectedBehavior : Behavior<TabItem>
{
    public static readonly DependencyProperty SelectedCommandProperty = DependencyProperty.Register("SelectedCommand", typeof(ICommand), typeof(TabSelectedBehavior));

    public ICommand SelectedCommand
    {
        get { return (ICommand)GetValue(SelectedCommandProperty); }
        set { SetValue(SelectedCommandProperty, value); }
    }

    private EventHandler _selectedHandler;

    protected override void OnAttached()
    {
        DependencyPropertyDescriptor dpd = DependencyPropertyDescriptor.FromProperty(TabItem.IsSelectedProperty, typeof(TabItem));
        if (dpd != null)
        {
            _selectedHandler = new EventHandler(AssociatedObject_SelectedChanged);
            dpd.AddValueChanged(AssociatedObject, _selectedHandler);
        }

        base.OnAttached();
    }

    protected override void OnDetaching()
    {
        DependencyPropertyDescriptor dpd = DependencyPropertyDescriptor.FromProperty(TabItem.IsSelectedProperty, typeof(TabItem));
        if (dpd != null && _selectedHandler != null)
        {
            dpd.RemoveValueChanged(AssociatedObject, _selectedHandler);
        }

        base.OnDetaching();
    }

    void AssociatedObject_SelectedChanged(object sender, EventArgs e)
    {
        if (AssociatedObject.IsSelected)
        {
            if (SelectedCommand != null)
            {
                SelectedCommand.Execute(null);
            }
        }
    }
}

XAML

<TabControl>
    <TabItem Header="TabItem1">
            <i:Interaction.Behaviors>
                <local:TabSelectedBehavior SelectedCommand="{Binding TabSelectedCommand}"/>
            </i:Interaction.Behaviors>
        </TabItem>
        <TabItem Header="TabItem2">
    </TabItem>
</TabControl>

以类似的方式,您还可以为 TabControl 创建一个行为,将 SelectionChanged 事件转换为命令,并将所选 TabItem 的 Tag 对象作为命令参数传递。

【讨论】:

    【解决方案2】:

    与所有集合控件一样,维护所选项目的最佳方法是使用SelectedItem 属性。如果您将相关数据类型的属性数据绑定到TabControl.SelectedItem property,那么您仍然可以判断选择了哪个选项卡并从视图模型中选择不同的选项卡。

    此方法的唯一问题是您还需要使用TabControl.ItemsSource 属性来设置TabItems:

    <TabControl ItemsSource="{Binding YourDataItems}" SelectedItem="{Binding YourItem}" />
    

    如果你想试试这个,那么你应该知道定义TabItems 可能会有点混乱。请参阅How to bind items of a TabControl to an observable collection in wpf? 问题的答案以获得帮助。

    【讨论】:

      猜你喜欢
      • 2021-09-14
      • 2014-03-30
      • 2010-10-14
      • 1970-01-01
      • 2021-10-11
      • 2015-07-11
      • 2020-10-31
      • 2021-01-26
      • 1970-01-01
      相关资源
      最近更新 更多