我的 WPF Windows 包含一个 TabControl,它在不同的选项卡上显示内容。单击下面的按钮通过 ICommand 接口/绑定执行方法。被调用的方法生成文本,该文本旨在显示在第二个选项卡中。
如何在不违反 MVVM 模式的情况下切换到按钮单击的第二个选项卡?
我试图将 TabItem.IsSelected 属性绑定到我的 ViewModel 中的某个东西,但我也想使用其他选项卡 (tab1)。
有什么想法吗?
我的 WPF Windows 包含一个 TabControl,它在不同的选项卡上显示内容。单击下面的按钮通过 ICommand 接口/绑定执行方法。被调用的方法生成文本,该文本旨在显示在第二个选项卡中。
如何在不违反 MVVM 模式的情况下切换到按钮单击的第二个选项卡?
我试图将 TabItem.IsSelected 属性绑定到我的 ViewModel 中的某个东西,但我也想使用其他选项卡 (tab1)。
有什么想法吗?
我自己发现的。
关键是双向绑定。单击按钮时,它将属性设置为DisplayXamlTab
true。该IsSelected
属性绑定到此变量。如果单击另一个选项卡,则绑定会将 DisplayXamlTab 属性设置为 false。
注意:UpdateSourceTrigger=PropertyChanged
也很重要
代码如下:
XAML:
<TabItem Header="XAML" IsSelected="{Binding DisplayXamlTab, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
<Grid Background="#FFE5E5E5">
<TextBox x:Name="TxtXamlOutput" IsReadOnly="True" Text="{Binding XamlText, Mode=TwoWay, NotifyOnTargetUpdated=True, NotifyOnSourceUpdated=True, UpdateSourceTrigger=PropertyChanged}" AcceptsReturn="True" TextWrapping="Wrap" VerticalScrollBarVisibility="Visible"/>
</Grid>
</TabItem>
C# 属性:
private bool displayXamlTab;
public bool DisplayXamlTab
{
get { return this.displayXamlTab; }
set
{
this.displayXamlTab = value;
this.RaisePropertyChanged("DisplayXamlTab");
}
}
如果您采用 MVVM 方式,您将在后面的代码中创建两个依赖属性:
ObservableCollection<ItemType> Items;
ItemType MySelectedItem;
然后,将 TabControl ItemsSource 属性绑定到Items并将 SelectedItem 属性绑定到MySelectedItem
<TabControl ItemsSource="{Binding Items}"
SelectedItem="{Binding MySelectedItem, Mode=TwoWay}">
<TabControl.ItemTemplate>
<DataTemplate>
<... here goes the UI to display ItemType ... >
</DataTemplate>
</TabControl.ItemTemplate>
</TabControl>
当您想要更改选定的选项卡时,只需更新 MySelectedItem 依赖属性
尽管这个问题已经相当老了并且已经得到了很好的回答,但我想我会添加这个额外的答案来演示另一种TabItem
更改TabControl
. 如果每个 都有一个视图模型TabItem
,那么在其中有一个IsSelected
属性来确定它是否被选中会很有帮助。可以使用以下属性将此IsSelected
属性与属性数据绑定:TabItem.IsSelected
ItemContainerStyle
<TabControl ItemsSource="{Binding MenuItems}" TabStripPlacement="Top">
<TabControl.ItemTemplate>
<DataTemplate DataType="{x:Type ControlViewModels:MenuItemViewModel}">
<StackPanel Orientation="Horizontal">
<Image Source="{Binding ImageSource}" Margin="0,0,10,0" />
<TextBlock Text="{Binding HeaderText}" FontSize="16" />
</StackPanel>
</DataTemplate>
</TabControl.ItemTemplate>
<TabControl.ContentTemplate>
<DataTemplate DataType="{x:Type ControlViewModels:MenuItemViewModel}">
<ContentControl Content="{Binding ViewModel}" />
</DataTemplate>
</TabControl.ContentTemplate>
<TabControl.ItemContainerStyle>
<Style TargetType="{x:Type TabItem}">
<Setter Property="IsSelected" Value="{Binding IsSelected}" />
</Style>
</TabControl.ItemContainerStyle>
</TabControl>
您现在可以TabItem
像这样更改从父视图模型中选择的内容:
MenuItems[0].IsSelected = true;
请注意,由于此属性是绑定到该TabItem.IsSelected
属性的数据,因此调用此...:
MenuItems[1].IsSelected = true;
...实际上还会自动将MenuItems[0].IsSelected
属性设置为false
. 因此,如果您正在使用的视图模型的IsSelected
属性设置为 true,那么您可以确保在TabControl
.
您可以在视图模型和属性之间创建绑定TabControl.SelectedIndex
- 即,0 选择第一个TabItem
,1 选择第二个,等等。
<TabControl DataContext="..." SelectedIndex="{Binding SomeVmProperty}" ...
(或者,根据您的设置方式,您可以绑定SelectedItem
...)
您可能希望使用某种“事件聚合器”模式(即 MVVM Light 中的Messenger类)来广播某种“导航”消息。您的视图 - TabControl - 可以侦听特定消息,并在收到消息时导航到 Tab2。
或者,您可以将 TabControl 的“ SelectedItem ”属性绑定到您的 ViewModel,然后简单地CurrentTab = MySecondTabViewModel
从您的 VM 中调用。这是@HighPoint 在对 OP 的评论中推荐的方法,但我不是粉丝;见下文。这种方法的另一个警告是您需要熟悉DataTemplates,因为您需要将视图映射到您显示的每个 ViewModel。
我个人喜欢第一种方法,因为我不认为它是 ViewModel 处理选项卡导航的“职责”。如果您只是在 ViewModel 中的数据更改时提醒您的 View,您可以让 View 决定是否要更改选项卡。