【问题标题】:Get the selected tab in the view model (wpf)获取视图模型中的选定选项卡(wpf)
【发布时间】:2015-01-31 12:28:50
【问题描述】:

我有一个带有选项卡控件的主视图。当一个选项卡被选中时,它会调用适当的视图来显示。我在视图模型中有一个函数,它必须知道选择了哪个选项卡来执行操作。我如何实现这一目标?视图模型如何知道选择了哪个选项卡?

【问题讨论】:

  • 我认为您可以将选项卡控件的选定属性绑定到视图模型中的属性并在那里访问它。它会知道选择了什么,因为......这就是模型绑定的作用:)
  • 谢谢。会试试的。
  • 我在下面提供了一个示例。
  • SelectedIndex 在某些情况下是一种糟糕的处理方式。如果您有一个表示选项卡的模型(这些模型的集合绑定到选项卡控件的 ItemsSource),那么只需将 SelectedItem 绑定到您的 ViewModel。通过 SelectedIndex 来回翻译是浪费时间。

标签: c# wpf mvvm tabs viewmodel


【解决方案1】:

很简单:

<Window x:Class="WpfApplication2.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WpfApplication2"
        Title="MainWindow" Height="350" Width="525">
    <Window.Resources>
        <local:TestViewModel x:Key="MainViewModel"/>
    </Window.Resources>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="*"/>
            <RowDefinition Height="50"/>
        </Grid.RowDefinitions>
        <TabControl DataContext="{StaticResource MainViewModel}" 
                    SelectedIndex="{Binding Selected}" 
                    Grid.Row="0" 
                    x:Name="TestTabs">
            <TabItem Header="Section 1"/>
            <TabItem Header="Section 2"/>
            <TabItem Header="Section 3"/>
        </TabControl>
        <Button Content="Check 
                Selected Index" 
                Grid.Row="1" 
                x:Name="TestButton" 
                Click="TestButton_OnClick"/>
    </Grid>
</Window>

模型在此处以声明方式定义为数据上下文。 selectedindex 属性绑定到模型,所以每当它发生变化时,它映射到视图模型上的属性也会发生变化

class TestViewModel : INotifyPropertyChanged
{
    private int _selected;
    public int Selected
    {
        get { return _selected; }
        set
        {
            _selected = value;
            OnPropertyChanged("Selected");
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    public void OnPropertyChanged(string property)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(property));
        }
    }
}

这实现了 INotifyPropertyChanged,因此视图将向它注册。在此处的处理程序中,我输出 Selected 的值以在您更改它们时显示。

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }

    private void TestButton_OnClick(object sender, RoutedEventArgs e)
    {
        var vm = TestTabs.DataContext as TestViewModel;
        MessageBox.Show(string.Format("You selected tab {0}", vm.Selected));
    }
}

这会获取视图模型,然后向我们显示属性实际上已更新。

【讨论】:

  • 我的要求略有不同,但这个解决方案正是医生要求的,都一样。不错!
【解决方案2】:

在 View 中,您将 SelectedIndex 属性放在 TabControl 上:

xmlns:cal="http://www.caliburnproject.org"

<TabControl cal:Message.Attach="[SelectionChanged] = [OnTabSelectionChanged()]"
                    SelectedIndex="{Binding SelectedIndexTab}">
            <TabItem Header="Tab 1"/>
            <TabItem Header="Tab 2"/>
</TabControl>

在 ViewModel 中,您声明一个公共属性名称 SelectedIndexTabOnTabSelectionChanged() 方法来操作。

public int SelectedIndexTab { get; set; }

在这个例子中,我使用 Caliburn 来捕捉 TabControl 的 SelectionChange 事件。

【讨论】:

  • 嗨@apo,我正在使用这个解决方案,但我不知道为什么,在选择最后一个选项卡事件时 OnTabSelectionChanged() 被无限调用。
【解决方案3】:

您可以使用 Selector 基类提供的 SelectionChanged 事件。 SelectionChangedEventArgs 将包含新选择(和取消选择)的项目。或者,您可以将 Selector Base 类的 SelectedItem 绑定到 ViewModel 中的属性,然后在 setter 中执行一些逻辑。

一般来说,将特定于视图的对象传递给您的 ViewModel 会被视为违反 MVVM - 它将 UI 框架(在本例中为 WPF)与更通用的 ViewModel 逻辑紧密耦合。更好的方法是将事件处理程序放在 UI 代码隐藏中,然后适当地作用于视图模型,但不将视图对象作为参数传递。

【讨论】:

  • 这是正确的 - 在该处理程序中收集您需要的信息,然后将其传递给 DataContext (VM) 上的方法
  • 谢谢。几天前我开始使用 mvvm,但仍在苦苦挣扎。
  • 欢迎您! MVVM 肯定需要一些时间来适应 - 数据属于哪里的细节并非易事。
【解决方案4】:

这是一个简单的例子。

您应该将选项卡的 ItemsSource 绑定到您的 ObservableCollection,这应该包含包含有关应创建的选项卡信息的模型。

这是代表标签页的VM和模型:

public class ViewModel
{
    public ObservableCollection<TabItem> Tabs { get; set; }
    public ViewModel()
    {
        Tabs = new ObservableCollection<TabItem>();
        Tabs.Add(new TabItem { Header = "One", Content = "One's content" });
        Tabs.Add(new TabItem { Header = "Two", Content = "Two's content" });
    }
}
public class TabItem
{
    public string Header { get; set; }
    public string Content { get; set; }
}

这是视图和虚拟机的绑定

<Window x:Class="WpfApplication12.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
    <ViewModel
        xmlns="clr-namespace:WpfApplication12" />
</Window.DataContext>
<TabControl
ItemsSource="{Binding Tabs}">
<TabControl.ItemTemplate>
    <!-- this is the header template-->
    <DataTemplate>
        <TextBlock
            Text="{Binding Header}" />
    </DataTemplate>
</TabControl.ItemTemplate>
<TabControl.ContentTemplate>
    <!-- this is the body of the TabItem template-->
    <DataTemplate>
        <----- usercontrol namespace goes here--->
    </DataTemplate>
</TabControl.ContentTemplate>

来源:link

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-07-28
    • 1970-01-01
    相关资源
    最近更新 更多