[英]How do I bind a TabControl to a collection of ViewModels?
基本上我在我的 MainViewModel.cs 中有:
ObservableCollection<TabItem> MyTabs { get; private set; }
但是,我需要以某种方式不仅能够创建标签,而且能够在维护 MVVM 的同时加载标签内容并将其链接到相应的视图模型。
基本上,我怎样才能让用户控件作为 tabitem 的内容加载并让该用户控件连接到适当的视图模型。 使这变得困难的部分是 ViewModel 不应该构造实际的视图项,对吗? 或者可以吗?
基本上,这是否适合 MVVM:
UserControl address = new AddressControl();
NotificationObject vm = new AddressViewModel();
address.DataContext = vm;
MyTabs[0] = new TabItem()
{
Content = address;
}
我只是问,因为好吧,我正在从 ViewModel 中构建一个视图(AddressControl),对我来说这听起来像是 MVVM 禁忌。
这不是 MVVM。 你不应该在你的视图模型中创建 UI 元素。
您应该将选项卡的 ItemsSource 绑定到您的 ObservableCollection,并且该模型应该包含有关应创建的选项卡的信息的模型。
以下是代表标签页的 VM 和模型:
public sealed 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 sealed 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>
<TextBlock
Text="{Binding Content}" />
</DataTemplate>
</TabControl.ContentTemplate>
</TabControl>
</Window>
(注意,如果你想在不同的标签中使用不同的东西,使用DataTemplates
。每个标签的视图模型应该是它自己的类,或者创建一个自定义的DataTemplateSelector
来选择正确的模板。)
数据模板中的 UserControl:
<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>
<MyUserControl xmlns="clr-namespace:WpfApplication12" />
</DataTemplate>
</TabControl.ContentTemplate>
</TabControl>
在 Prism 中,您通常让标签控制一个区域,这样您就不必控制绑定的标签页集合。
<TabControl
x:Name="MainRegionHost"
Regions:RegionManager.RegionName="MainRegion"
/>
现在可以通过将自己注册到区域 MainRegion 来添加视图:
RegionManager.RegisterViewWithRegion( "MainRegion",
( ) => Container.Resolve<IMyViewModel>( ).View );
在这里您可以看到 Prism 的特色。 View 由 ViewModel 实例化。 就我而言,我通过控制反转容器(例如 Unity 或 MEF)解析 ViewModel。 ViewModel 通过构造函数注入获取注入的 View 并将自身设置为 View 的数据上下文。
另一种方法是将视图的类型注册到区域控制器中:
RegionManager.RegisterViewWithRegion( "MainRegion", typeof( MyView ) );
使用这种方法允许您稍后在运行时创建视图,例如通过控制器:
IRegion region = this._regionManager.Regions["MainRegion"];
object mainView = region.GetView( MainViewName );
if ( mainView == null )
{
var view = _container.ResolveSessionRelatedView<MainView>( );
region.Add( view, MainViewName );
}
因为您已经注册了视图的类型,所以视图被放置在正确的区域中。
我有一个转换器来解耦 UI 和 ViewModel,这就是以下几点:
<TabControl.ContentTemplate>
<DataTemplate>
<ContentPresenter Content="{Binding Tab,Converter={StaticResource TabItemConverter}"/>
</DataTemplate>
</TabControl.ContentTemplate>
Tab 是我的 TabItemViewModel 中的枚举,TabItemConverter 将其转换为真实的 UI。
在 TabItemConverter 中,只需获取值并返回您需要的用户控件。
可能是这样:
<UserControl x:Class="Test_002.Views.MainView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Test_002.Views"
xmlns:generalView="clr-namespace:Test_002.Views.General"
xmlns:secVIew="clr-namespace:Test_002.Views.Security"
xmlns:detailsView="clr-namespace:Test_002.Views.Details"
mc:Ignorable="d"
d:DesignHeight="400" d:DesignWidth="650">
<Grid>
<DockPanel>
<StackPanel Orientation="Horizontal" DockPanel.Dock="Bottom" Margin="2,5">
<Button Command="{Binding btnPrev}" Content="Prev"/>
<Button Command="{Binding btnNext}" Content="Next"/>
<Button Command="{Binding btnSelected}" Content="Selected"/>
</StackPanel>
<TabControl>
<TabItem Header="General">
<generalView:GeneralView></generalView:GeneralView>
</TabItem>
<TabItem Header="Security">
<secVIew:SecurityView></secVIew:SecurityView>
</TabItem>
<TabItem Header="Details">
<detailsView:DetailsView></detailsView:DetailsView>
</TabItem>
</TabControl>
</DockPanel>
</Grid>
认为这是最简单的方法。 MVVM 兼容吗?
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.