Как привязать TabControl к коллекции ViewModels?
в основном у меня есть в моей MainViewModel.cs:
ObservableCollection<TabItem> MyTabs { get; private set; }
однако мне нужно как-то уметь не только создавать вкладки, но и загружать содержимое вкладок и связывать их с соответствующими viewmodels при сохранении MVVM.
в принципе, как я могу получить usercontrol для загрузки в качестве содержимого tabitem и подключить этот usercontrol к соответствующей viewmodel. Часть, которая затрудняет это, - ViewModel не должна создавать фактические элементы просмотра, верно? Или может?
в принципе, это будет MVVM подходит:
UserControl address = new AddressControl();
NotificationObject vm = new AddressViewModel();
address.DataContext = vm;
MyTabs[0] = new TabItem()
{
Content = address;
}
Я спрашиваю только потому, что хорошо, я создаю представление (AddressControl) из ViewModel, которое для меня звучит как MVVM no-no.
3 ответов
Это не MVVM. Не следует создавать элементы пользовательского интерфейса в модели представления.
вы должны привязать 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 вы обычно делаете tab control областью, так что вам не нужно контролировать коллекцию связанных вкладок.
<TabControl
x:Name="MainRegionHost"
Regions:RegionManager.RegionName="MainRegion"
/>
теперь представления могут быть добавлены путем регистрации себя в регионе MainRegion:
RegionManager.RegisterViewWithRegion( "MainRegion",
( ) => Container.Resolve<IMyViewModel>( ).View );
и здесь вы можете увидеть специальность Prism. Вид instanciated купить в ViewModel. В моем случае я разрешаю ViewModel через инверсию контейнера управления (например, Unity или MEF). В ViewModel получает вид вводят через инъекция конструктора и устанавливает себя в качестве контекста данных представления.
альтернативой является регистрация типа представления в контроллере региона:
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 );
}
поскольку вы зарегистрировали тип представления, представление помещается в правильную область.
У меня есть конвертер для развязки пользовательского интерфейса и ViewModel, вот точка ниже:
<TabControl.ContentTemplate>
<DataTemplate>
<ContentPresenter Content="{Binding Tab,Converter={StaticResource TabItemConverter}"/>
</DataTemplate>
</TabControl.ContentTemplate>
вкладка-это enum в моем TabItemViewModel и TabItemConverter преобразовать его в реальный UI.
в TabItemConverter, просто получить значение и вернуть usercontrol вам нужно.