[英]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.