MVVM 将视图绑定到 TabControlItems - 视图不显示
MVVM Binding Views to TabControlItems - Views don't display
我想在我的主视图中 TabControlItems
显示不同的视图。
为此,我创建了一个像这样的 class :
public sealed class TabItem
{
public string Header { get; set; }
public ViewModelBase Content { get; set; }
}
我在我的 ViewModel 中调用 List
:
private ObservableCollection<TabItem> _views;
public ObservableCollection<TabItem> Views
{
get { return _views; }
set
{
_views = value;
RaisePropertyChanged(() => Views);
}
}
public IndexMainViewModel()
{
Views = new ObservableCollection<TabItem>();
Views.Add(new TabItem { Header = "Export", Content = new ExportViewModel() });
Views.Add(new TabItem { Header = "Import", Content = new ImportViewModel() });
}
编辑 然后显示在我的视图中:
<window xmlns:views="clr-namespace:EDICOT_Module_Import_Export_Articles.View"
xmlns:vm="clr-namespace:EDICOT_Module_Import_Export_Articles.ViewModel"
xmlns:model="clr-namespace:EDICOT_Module_Import_Export_Articles.Model.Classes"
DataContext="{Binding IndexMainVM, Source={StaticResource Locator}}">
<TabControl ItemsSource="{Binding Views}">
<TabControl.Resources>
<DataTemplate DataType="{x:Type model:TabItem}">
<DataTemplate.Resources>
<DataTemplate DataType="{x:Type vm:ImportViewModel}">
<views:ImportView />
</DataTemplate>
<DataTemplate DataType="{x:Type vm:ExportViewModel}">
<views:ExportView />
</DataTemplate>
</DataTemplate.Resources>
<ContentControl Content="{Binding Content}"/>
</DataTemplate>
</TabControl.Resources>
<TabControl.ItemTemplate >
<DataTemplate >
<TextBlock Text="{Binding Header}"/>
</DataTemplate>
</TabControl.ItemTemplate>
</TabControl>
问题是它只显示 header 但不显示内容(视图),而是显示 TabItem class.
的路径
提供更多信息:我截断了代码以仅保留主题需要的内容,并且我使用 MVVM Light。
我真的不明白我在这里想念什么!感谢您的帮助。
问题是每个选项卡都绑定到 TabItem
的一个实例。您有 vm:ExportViewModel
和 vm:ImportViewModel
的数据模板。你现在看到你的错误了吗?
对此有很多解决方案。最简单的方法是将 Header 文本移动到基础视图模型中,并将该 Tab 控件绑定到 collection ViewModel。
另一种选择是为 TabItem
添加一个 DataTemplate,在其中粘贴一个 ContentControl,然后将 that 绑定到视图模型。这里有一些 xaml-like 伪代码来说明这个想法:
<DataTemplate DataType="{x:Type vm:TabItem}">
<ContentControl Content={Binding Content}" />
</DataTemplate>
您可能必须将视图模型的模板移动到 ContentControl 的资源中,但我认为没有必要。您可能需要调整 TabItem 数据模板,使其也填充选项卡 window。
A third 选项将实现自定义 DataTemplateSelector 并使用 that 在你的 Tab 控件中。在此选择器中,只需打开 TabItem 并查看类型的 Content 属性。您可以浏览默认 DataTemplateSelector 的源代码,了解如何为给定类型获取正确的模板。这种方法让您深入了解 WPF,这是一次有趣的旅行。 去过一次,不想再去了。 其实对于你的需求,这次旅行不会像我的那么糟糕。 默认选择器不执行下蹲操作,因此返回 base.SelectTemplate
毫无价值。我在框架中挖掘了一个应该如何实施的例子。
public class TabItemDataTemplateSelector : DataTemplateSelector
{
public override DataTemplate
SelectTemplate(object item, DependencyObject container)
{
var viewModel = item as TabItem;
if (item == null)
return null;
else
item = viewModel.Content;
FrameworkElement fe = null;
if (container is ContentPresenter)
fe = (container as ContentPresenter)
.TemplatedParent as FrameworkElement;
else
fe = container as FrameworkElement;
var key = new DataTemplateKey(item.GetType());
return fe.TryFindResource(key) as DataTemplate;
}
}
将它的一个实例添加到某处的资源
<derp:TabItemDataTemplateSelector x:Key="tidts"/>
然后将其绑定到 ContentTemplateSelector
<TabControl ItemsSource="{Binding Views}"
ContentTemplateSelector={StaticResource tidts}>
我想在我的主视图中 TabControlItems
显示不同的视图。
为此,我创建了一个像这样的 class :
public sealed class TabItem
{
public string Header { get; set; }
public ViewModelBase Content { get; set; }
}
我在我的 ViewModel 中调用 List
:
private ObservableCollection<TabItem> _views;
public ObservableCollection<TabItem> Views
{
get { return _views; }
set
{
_views = value;
RaisePropertyChanged(() => Views);
}
}
public IndexMainViewModel()
{
Views = new ObservableCollection<TabItem>();
Views.Add(new TabItem { Header = "Export", Content = new ExportViewModel() });
Views.Add(new TabItem { Header = "Import", Content = new ImportViewModel() });
}
编辑 然后显示在我的视图中:
<window xmlns:views="clr-namespace:EDICOT_Module_Import_Export_Articles.View"
xmlns:vm="clr-namespace:EDICOT_Module_Import_Export_Articles.ViewModel"
xmlns:model="clr-namespace:EDICOT_Module_Import_Export_Articles.Model.Classes"
DataContext="{Binding IndexMainVM, Source={StaticResource Locator}}">
<TabControl ItemsSource="{Binding Views}">
<TabControl.Resources>
<DataTemplate DataType="{x:Type model:TabItem}">
<DataTemplate.Resources>
<DataTemplate DataType="{x:Type vm:ImportViewModel}">
<views:ImportView />
</DataTemplate>
<DataTemplate DataType="{x:Type vm:ExportViewModel}">
<views:ExportView />
</DataTemplate>
</DataTemplate.Resources>
<ContentControl Content="{Binding Content}"/>
</DataTemplate>
</TabControl.Resources>
<TabControl.ItemTemplate >
<DataTemplate >
<TextBlock Text="{Binding Header}"/>
</DataTemplate>
</TabControl.ItemTemplate>
</TabControl>
问题是它只显示 header 但不显示内容(视图),而是显示 TabItem class.
的路径提供更多信息:我截断了代码以仅保留主题需要的内容,并且我使用 MVVM Light。
我真的不明白我在这里想念什么!感谢您的帮助。
问题是每个选项卡都绑定到 TabItem
的一个实例。您有 vm:ExportViewModel
和 vm:ImportViewModel
的数据模板。你现在看到你的错误了吗?
对此有很多解决方案。最简单的方法是将 Header 文本移动到基础视图模型中,并将该 Tab 控件绑定到 collection ViewModel。
另一种选择是为 TabItem
添加一个 DataTemplate,在其中粘贴一个 ContentControl,然后将 that 绑定到视图模型。这里有一些 xaml-like 伪代码来说明这个想法:
<DataTemplate DataType="{x:Type vm:TabItem}">
<ContentControl Content={Binding Content}" />
</DataTemplate>
您可能必须将视图模型的模板移动到 ContentControl 的资源中,但我认为没有必要。您可能需要调整 TabItem 数据模板,使其也填充选项卡 window。
A third 选项将实现自定义 DataTemplateSelector 并使用 that 在你的 Tab 控件中。在此选择器中,只需打开 TabItem 并查看类型的 Content 属性。您可以浏览默认 DataTemplateSelector 的源代码,了解如何为给定类型获取正确的模板。这种方法让您深入了解 WPF,这是一次有趣的旅行。 去过一次,不想再去了。 其实对于你的需求,这次旅行不会像我的那么糟糕。 默认选择器不执行下蹲操作,因此返回 base.SelectTemplate
毫无价值。我在框架中挖掘了一个应该如何实施的例子。
public class TabItemDataTemplateSelector : DataTemplateSelector
{
public override DataTemplate
SelectTemplate(object item, DependencyObject container)
{
var viewModel = item as TabItem;
if (item == null)
return null;
else
item = viewModel.Content;
FrameworkElement fe = null;
if (container is ContentPresenter)
fe = (container as ContentPresenter)
.TemplatedParent as FrameworkElement;
else
fe = container as FrameworkElement;
var key = new DataTemplateKey(item.GetType());
return fe.TryFindResource(key) as DataTemplate;
}
}
将它的一个实例添加到某处的资源
<derp:TabItemDataTemplateSelector x:Key="tidts"/>
然后将其绑定到 ContentTemplateSelector
<TabControl ItemsSource="{Binding Views}"
ContentTemplateSelector={StaticResource tidts}>