Как привязать элемент управления TabControl к коллекции ViewModels?
в основном у меня есть в моем MainViewModel.cs:
ObservableCollection<TabItem> MyTabs { get; private set; }
тем не менее, мне нужно каким-то образом иметь возможность не только создавать вкладки, но и загружать содержимое вкладок и связывать их с соответствующими viewmodels при сохранении MVVM.
в принципе, как я могу получить элемент управления UserControl, который будет загружен как содержание tabitem В и пользовательских элементов управления подключен к соответствующей модели представления. Часть, которая делает это трудным, - это 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, и это должно содержать модели с информацией о вкладках, которые должны быть созданы.
вот виртуальная машина и модель, которая представляет собой вкладку:
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 );
и здесь вы можете увидеть специальность "Призма". Представление создается экземпляром 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 ); }
поскольку вы зарегистрировали тип представления, представление помещается в правильную область.
У меня есть конвертер, чтобы отделить UI и ViewModel, вот точка ниже:
<TabControl.ContentTemplate> <DataTemplate> <ContentPresenter Content="{Binding Tab,Converter={StaticResource TabItemConverter}"/> </DataTemplate> </TabControl.ContentTemplate>
вкладка-это перечисление в моем TabItemViewModel, а TabItemConverter преобразует его в реальный пользовательский интерфейс.
в TabItemConverter,просто получить значение и возвращает элемент управления UserControl вам нужно.