Загрузить UserControl в TabItem
У меня есть Usercontrol (TabUserControl), который содержит TabControl. Viewmodel этого UserControl загружает ab Наблюдаемый набор TabItems. Один из этих элементов - это другой пользовательский элемент управления. Когда я просто загружаю текст в tabcontrol, нет никаких проблем, но как я могу загрузить другой пользовательский элемент управления в tabitem TabUserControl.
Я использую MVVM.
Здесь мой код:
public class TabItem
{
public string Header { get; set; }
public object Content { get; set; } // object to allow all sort of items??
}
Модель ViewModel TabUserControl
public class TabViewModel
{
public ObservableCollection<TabItem> Tabs {get;set;}
public TabViewModel()
{
Tabs = new ObservableCollection<TabItem>();
//Tabs.Add(new TabItem { Header = "Overview", Content = new OverviewViewModel() }); How to load a usercontrol here if it in the ItemCollection?
Tabs.Add(new TabItem { Header = "Overview", Content = "Bla bla bla" });
Tabs.Add(new TabItem { Header = "Two", Content = "Two content" });
}
}
И затем TabControl XAML:
<TabControl x:Name="_tabControl"
ItemsSource="{Binding Tabs}">
<TabControl.ItemContainerStyle>
<Style TargetType="TabItem">
<Setter Property="Header"
Value="{Binding Header}" />
<Setter Property="Content"
Value="{Binding Content}" />
</Style>
</TabControl.ItemContainerStyle>
</TabControl>
Он работает до тех пор, пока я не загружаю viewmodel usercontrol в коллекции tabItems. как я могу настроить загрузку UserTabControl на TabItem?
Цель состоит в том, что каждый tabitem будет содержать usercontrol. Каждый пользовательский контроль делает свою собственную вещь.
Надеюсь, кто-то может мне помочь, поскольку я начинаю WPF.
спасибо!
Ответы
Ответ 1
В идеале, TabControl.ItemsSource
должен быть установлен в набор ViewModels
, а DataTemplates
должен использоваться, чтобы сообщить WPF рисовать каждый ViewModel
с помощью определенного UserControl
.
Это не зависит от вашей бизнес-логики (ViewModels
) полностью от вашего пользовательского интерфейса (Views
)
Например,
<TabControl x:Name="MyTabControl"
ItemsSource="{Binding TabViewModels}"
SelectedItem="{Binding SelectedTabViewModel}">
<TabControl.Resources>
<DataTemplate DataType="{x:Type my:ViewModelA}">
<my:ViewAUserControl />
</DataTemplate>
<DataTemplate DataType="{x:Type my:ViewModelB}">
<my:ViewBUserControl />
</DataTemplate>
<DataTemplate DataType="{x:Type my:ViewModelC}">
<my:ViewCUserControl />
</DataTemplate>
</TabControl.Resources>
<TabControl.ItemContainerStyle>
<Style TargetType="TabItem">
<Setter Property="Header" Value="{Binding Header}" />
</Style>
</TabControl.ItemContainerStyle>
</TabControl>
ViewModel, содержащий TabControl DataContext:
TabViewModels = new ObservableCollection<ITabViewModel>();
TabViewModels.Add(new ViewModelA { Header = "Tab A" });
TabViewModels.Add(new ViewModelB { Header = "Tab B" });
TabViewModels.Add(new ViewModelC { Header = "Tab C" });
SelectedTabViewModel = TabViewModels[0];
Ответ 2
Спасибо Рэйчел за ваш ответ. Но он принудительно объявляет DataContext во время самого компиляции. Как и вы, связав каждый из представлений с их соответствующими ViewModels в DataTemplate TabControl. Мы можем достичь динамического соединения View-ViewModel, когда переместим его в ViewModel. Вот как:
XAML:
<TabControl.ItemContainerStyle>
<Style TargetType="TabItem">
<Setter Property="Header" Value="{Binding Header}" />
<Setter Property="Content" Value="{Binding Content}" />
</Style>
<TabControl.ItemContainerStyle>
VM:
public ObservableCollection<TabItem> TabItems { get; set; }
public MainWindowViewModel()
{
TabItems = new ObservableCollection<TabItem>
{
new TabItem{Content = new TabAView() {DataContext = new TabAViewModel()}, Header = "Tab A"},
new TabItem{Content = new TabBView(), Header = "Tab B"}
};
}
Мы можем даже использовать делегаты Action для задержки и вызывать инициализацию TabItems только после Tab SelectionChangedEvent. Это позволяет экономить много памяти, если в UserControl Views много элементов пользовательского интерфейса.