我的WPF Windows包含一个TabControl,它显示不同选项卡上的内容。单击下面的按钮可通过ICommand接口/ Binding执行方法。被调用的方法生成要在第二个选项卡中显示的文本。
如何在不违反MVVM模式的情况下切换到按钮单击时的第二个选项卡?
我尝试将TabItem.IsSelected属性绑定到我的ViewModel中的某些内容,但我也想使用其他标签(tab1)。
有什么想法吗?
答案 0 :(得分:13)
我自己发现了。
关键是双向绑定。单击该按钮时,它将属性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");
}
}
答案 1 :(得分:12)
如果您要使用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依赖属性
即可答案 2 :(得分:2)
虽然这个问题相当陈旧且已经得到很好的解答,但我想我会添加这个额外的答案来演示更改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
中选择了其相关视图。
答案 3 :(得分:1)
您可以在视图模型和TabControl.SelectedIndex
属性之间创建绑定 - 即,0选择第一个TabItem
,1选择第二个,等等。
<TabControl DataContext="..." SelectedIndex="{Binding SomeVmProperty}" ...
(或者,根据您设置的方式,您可以绑定SelectedItem
...)
答案 4 :(得分:0)
您可能希望使用某种“Event Aggregator”模式(即MVVM Light中的Messenger类)来广播某种“导航”消息。您的视图 - TabControl - 可以侦听特定消息,并在收到消息时导航到Tab2。
或者,您可以将TabControl的“SelectedItem”属性绑定到ViewModel,只需从VM中调用CurrentTab = MySecondTabViewModel
即可。这是@HighPoint在对OP的评论中推荐的approach,但我不是粉丝;见下文。此方法的另一个警告是您需要熟悉DataTemplates,因为您需要将视图映射到您显示的每个ViewModel。
我个人喜欢第一种方法,因为我不认为它是ViewModel处理标签导航的“责任”。如果您只是在ViewModel中更改数据时提醒View,则允许View决定是否要更改标签。