WPF MVVM:如何将不同的ViewModel绑定到每个TabItem?

24

我有一个主窗口,其中包含两个选项卡tabItem

Main Window

我目前有一个ViewModel来处理Tab1和Tab2的服务。 这个ViewModel由于模糊SOC而变得有点臃肿。 我想将逻辑拆分成2个视图模型:ViewModel1和ViewModel2。我的理解是,您可以将主窗口DataContext设置为一个包含ViewModel集合的基础ViewModel,然后可以将每个TabItem分配给不同的ViewModel。

我看到的这些基本ViewModel示例会公开ObservableCollection,如下所示:

private ObservableCollection<ViewModel1> _viewModelCollection
Public Observable Collection<ViewModel1> ViewModelCollection
{
   get { return _viewModelCollection; }
   set
     {
        _viewModelCollection = value;
        OnPropertyChanged("ViewModelCollection");
     }
}

public BaseViewModel()
{
  ViewModelCollection = new ObservableCollection<ViewModel1>();
  ViewModelCollection.Add(new ViewModel1(Tab1);
  ViewModelCollection.Add(new ViewModel1(Tab2);
}

但是我该如何为每个选项卡指定不同的ViewModel?我希望Tab1 = ViewModel1,Tab2 = ViewModel2。


我不确定这方面是否有明确的最佳实践。将TabControl的ItemsSource绑定到ViewModelCollection并没有什么用处,因为没有通用的“模板”(每个选项卡都有自己的视图)。如果你有固定数量的选项卡,我会简单地将每个选项卡的DataContext绑定到相应的视图模型,并将每个选项卡的内容设置为适当的视图。如果选项卡是动态的,事情就变得更加棘手。 - Mike Strobel
你试过搜索吗?[1](https://dev59.com/W2zXa4cB1Zd3GeqPTW70),[2](http://stackoverflow.com/q/12432062/1997232),[3](https://dev59.com/pXXYa4cB1Zd3GeqP2BWD)... - Sinatr
1
@Sinatr 是的,我已经阅读了那些问题。我想要绑定到不同的ViewModel,而不是同一个ViewModel的不同实例集合... - Hardgraf
5个回答

39

您确实可以将选项卡的视图模型添加到主视图模型中。然后,您可以在选项卡的XAML中绑定到子视图模型。

假设您有三个视图模型:MainViewModelTab1ViewModelTab2ViewModel。在您的MainViewModel上,您保留您的选项卡视图模型的集合:

class MainViewModel
{
    ObservableCollection<object> _children;

    public MainViewModel()
    {
        _children = new ObservableCollection<object>();
        _children.Add(new Tab1ViewModel());
        _children.Add(new Tab2ViewModel());
    }

    public ObservableCollection<object> Children { get { return _children; } }
}

将您的主窗口的DataContext设置为MainViewModel后,您可以通过引用Children属性绑定标签页的DataContext

<TabControl>
    <TabItem DataContext="{Binding Children[0]}" x:Name="Tab1" Header="Tab1" >
      <!-- Tab content -->
    </TabItem>
    <TabItem DataContext="{Binding Children[1]}" x:Name="Tab2" Header="Tab2" >
      <!-- Tab content -->
    </TabItem>
</TabControl>

3
太棒了!正是我需要的,我也喜欢在OC中将索引绑定到这个内容 :) - Hardgraf

8
class MainViewModel
{
    ObservableCollection<object> _children;

    public MainViewModel()
    {
        _children = new ObservableCollection<object>();
        _children.Add(new Tab1ViewModel());
        _children.Add(new Tab2ViewModel());
    }

    public ObservableCollection<object> Children { get { return _children; } }
}

现在在 XAML 中将 Children 绑定到 ItemsSource。它会为我们添加到可观察集合中的每个视图模型生成一个选项卡。
    <TabControl ItemsSource="{Binding Children}"/>

这段代码片段是 Jakob 上面的精确副本。 - darkstar3d
2
这可能是Jakob代码的副本,但这个答案更完整。它是强类型的(不使用objectChildren[x]),并且实际上向OP展示了如何做他想做的事情。在我看来,这应该是被接受的答案。 - Yann Duran

4

我使用像Prism这样的框架,它允许您定义区域并使用RegionManager。然后,您可以将ContentControl定义为TabItem的UI。

接下来,您可以使用RegionManager.RequestNavigate来填充命名区域,并使用特定视图(我们的视图导入视图模型并设置其数据上下文)。


是的,我已经尝试过Prism了。不过这个应用程序相当简单,我认为没有必要为此设置引导程序等等。 - Hardgraf
我想我可以尝试使用ObservableCollection<object>作为基本模型。将我的不同ViewModel的实例添加到其中,然后将选项卡项目绑定到集合中相应的ViewModel实例? - Hardgraf
1
你可以将选项卡控件的项源绑定到一个 TabViewModels 列表,这些列表将显示在 UI 中。TabVMs 可以从 BaseTabVM 继承,其中包含所有共同的内容,并最终在项目资源中为每个选项卡视图模型创建数据模板,以便它们可以单独自定义。绑定将进入每个单独的 tabVM,在主窗口视图模型中有一个 BaseTabVMs 列表可供绑定,所有项都可以独立使用。 - Olimpiu Datcu

1

如果有人在寻找如何在WPF中使用MVVM模式与选项卡控件和选项卡内容互动的问题,我找到了一个YouTube视频:WPF MVVM - Working with tab controls and tab content,这个视频是由DCOM Engineering, LLC的一位工程师制作的。

视频详细讲解了“如何针对每个选项卡绑定不同的ViewModel”,并提供了具体步骤和可下载代码。

“学习如何使用MVVM模式在WPF中有效地创建、打开和关闭选项卡。这将有助于单元测试。”


1

不确定为什么所选答案建议使用ObservableCollection并创建一个选项卡集合,然后通过索引引用它们。

我认为这样做更清晰:

MainViewModel tab1 = ConfigViewModel Tab2 = UserProfileViewModel

在MainViewModel中:

private ConfigViewModels _configVM;
public ConfigViewModels ConfigVM { get { return _configVM; } }

private UserProfileViewModel _userProfileVM;
public UserProfileViewModel UserProfileVM { get { return _userProfileVM; } }

public MainViewModel(){

_configVM = new ConfigViewModels();
_userProfileVM = new UserProfileViewModel ();
}

在XAML文件中:

<TabControl>
<TabItem DataContext="{Binding ConfigVM }" >
<TabItem DataContext="{Binding UserProfileVM }" >

我不确定通过可观察的集合来做这件事情有什么好处。


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