如何解决content presenter不显示view?
How to resolve content presenter not displaying View?
我已将内容展示器添加到我的 TabControl 的数据模板中,以显示正确的视图。
但是当我加载应用程序时,选项卡显示但没有用户控制内容。
我用 Google 搜索了这个错误并发现了这个 solution,这表明数据上下文有错误,但在我的 AppVM 和下面的 AppView 中设置似乎没问题。
我在 AppView 中引用的 VM 和视图的名称也是正确的。
有人知道这里的设置哪里出了问题吗?
这是包含两个视图的 ApplicationView:
<Window x:Class="MongoDBApp.Views.ApplicationView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:views="clr-namespace:MongoDBApp.Views"
xmlns:vm="clr-namespace:MongoDBApp.ViewModels"
Title="ApplicationView"
Width="800"
Height="500">
<Window.Resources>
<DataTemplate DataType="{x:Type vm:CustomerDetailsViewModel}">
<views:CustomerDetailsView />
</DataTemplate>
<DataTemplate DataType="{x:Type vm:CustomerOrdersViewModel}">
<views:CustomerOrdersView />
</DataTemplate>
</Window.Resources>
<Window.DataContext>
<vm:ApplicationViewModel />
</Window.DataContext>
<TabControl ItemsSource="{Binding PageViewModels}" TabStripPlacement="Top">
<TabControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}" />
</DataTemplate>
</TabControl.ItemTemplate>
<TabControl.ContentTemplate>
<DataTemplate>
<ContentPresenter Content="{Binding CurrentPageViewModel}" />
</DataTemplate>
</TabControl.ContentTemplate>
</TabControl>
</Window>
ApplicationViewModel 构造函数和相关字段:
private ICommand _changePageCommand;
private IPageViewModel _currentPageViewModel;
private List<IPageViewModel> _pageViewModels;
private static ICustomerDataService customerDataService = new CustomerDataService(CustomerRepository.Instance);
#endregion
/// <summary>
/// Initializes a new instance of the <see cref="ApplicationViewModel"/> class.
/// </summary>
public ApplicationViewModel()
{
// Add available pages
PageViewModels.Add(new CustomerDetailsViewModel(customerDataService));
PageViewModels.Add(new CustomerOrdersViewModel());
// Set starting page
CurrentPageViewModel = PageViewModels[0];
}
我们通常不会在 ControlTemplate
之外使用 ContentPresenter
,当然也不会像您在 DataTemplate
中所做的那样...使用 ContentPresenter
将使 WPF 框架搜索与 Content
的类型相匹配的 DataTemplate
,因此在您的情况下,您将以无限循环结束。相反,您应该将关联视图放在 DataTemplate
:
<DataTemplate DataType="{x:Type YourDataXamlPrefix:CurrentPageViewModel}">
<YourUiXamlPrefix:YourView DataContext="{Binding CurrentPageViewModel}" />
</DataTemplate>
这样,当框架在集合中遇到您的视图模型class时,它会找到这个DataTemplate
并渲染相关视图。
ContentTemplate
属性 包装 Content
对象。
例如,在您的代码中,您将 .Content
属性 设置为 CustomerDetailsViewModel
对象,并尝试绑定到该对象的 CurrentPageViewModel
,这不存在。
正在渲染的是:
<TabControl>
<TabItem>
<ContentPresenter Content=CustomerDetailsViewModel>
<ContentPresenter Content="{Binding CurrentPageViewModel}" />
</ContentPresenter>
</TabItem>
<TabItem>
<ContentPresenter Content=CustomerOrdersViewModel>
<ContentPresenter Content="{Binding CurrentPageViewModel}" />
</ContentPresenter>
</TabItem>
</TabControl>
因为 TabControl 会自动生成一个 ContentPresenter
来包装每个 TabItem
的 .Content
,你根本不需要这个模板。
但听起来您真正想要的是绑定 TabControl
的 SelectedItem
属性
<TabControl ItemsSource="{Binding PageViewModels}"
SelectedItem="{Binding CurrentPageViewModel}"
TabStripPlacement="Top">
<TabControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}" />
</DataTemplate>
</TabControl.ItemTemplate>
</TabControl>
我已将内容展示器添加到我的 TabControl 的数据模板中,以显示正确的视图。
但是当我加载应用程序时,选项卡显示但没有用户控制内容。
我用 Google 搜索了这个错误并发现了这个 solution,这表明数据上下文有错误,但在我的 AppVM 和下面的 AppView 中设置似乎没问题。
我在 AppView 中引用的 VM 和视图的名称也是正确的。
有人知道这里的设置哪里出了问题吗?
这是包含两个视图的 ApplicationView:
<Window x:Class="MongoDBApp.Views.ApplicationView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:views="clr-namespace:MongoDBApp.Views"
xmlns:vm="clr-namespace:MongoDBApp.ViewModels"
Title="ApplicationView"
Width="800"
Height="500">
<Window.Resources>
<DataTemplate DataType="{x:Type vm:CustomerDetailsViewModel}">
<views:CustomerDetailsView />
</DataTemplate>
<DataTemplate DataType="{x:Type vm:CustomerOrdersViewModel}">
<views:CustomerOrdersView />
</DataTemplate>
</Window.Resources>
<Window.DataContext>
<vm:ApplicationViewModel />
</Window.DataContext>
<TabControl ItemsSource="{Binding PageViewModels}" TabStripPlacement="Top">
<TabControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}" />
</DataTemplate>
</TabControl.ItemTemplate>
<TabControl.ContentTemplate>
<DataTemplate>
<ContentPresenter Content="{Binding CurrentPageViewModel}" />
</DataTemplate>
</TabControl.ContentTemplate>
</TabControl>
</Window>
ApplicationViewModel 构造函数和相关字段:
private ICommand _changePageCommand;
private IPageViewModel _currentPageViewModel;
private List<IPageViewModel> _pageViewModels;
private static ICustomerDataService customerDataService = new CustomerDataService(CustomerRepository.Instance);
#endregion
/// <summary>
/// Initializes a new instance of the <see cref="ApplicationViewModel"/> class.
/// </summary>
public ApplicationViewModel()
{
// Add available pages
PageViewModels.Add(new CustomerDetailsViewModel(customerDataService));
PageViewModels.Add(new CustomerOrdersViewModel());
// Set starting page
CurrentPageViewModel = PageViewModels[0];
}
我们通常不会在 ControlTemplate
之外使用 ContentPresenter
,当然也不会像您在 DataTemplate
中所做的那样...使用 ContentPresenter
将使 WPF 框架搜索与 Content
的类型相匹配的 DataTemplate
,因此在您的情况下,您将以无限循环结束。相反,您应该将关联视图放在 DataTemplate
:
<DataTemplate DataType="{x:Type YourDataXamlPrefix:CurrentPageViewModel}">
<YourUiXamlPrefix:YourView DataContext="{Binding CurrentPageViewModel}" />
</DataTemplate>
这样,当框架在集合中遇到您的视图模型class时,它会找到这个DataTemplate
并渲染相关视图。
ContentTemplate
属性 包装 Content
对象。
例如,在您的代码中,您将 .Content
属性 设置为 CustomerDetailsViewModel
对象,并尝试绑定到该对象的 CurrentPageViewModel
,这不存在。
正在渲染的是:
<TabControl>
<TabItem>
<ContentPresenter Content=CustomerDetailsViewModel>
<ContentPresenter Content="{Binding CurrentPageViewModel}" />
</ContentPresenter>
</TabItem>
<TabItem>
<ContentPresenter Content=CustomerOrdersViewModel>
<ContentPresenter Content="{Binding CurrentPageViewModel}" />
</ContentPresenter>
</TabItem>
</TabControl>
因为 TabControl 会自动生成一个 ContentPresenter
来包装每个 TabItem
的 .Content
,你根本不需要这个模板。
但听起来您真正想要的是绑定 TabControl
的SelectedItem
属性
<TabControl ItemsSource="{Binding PageViewModels}"
SelectedItem="{Binding CurrentPageViewModel}"
TabStripPlacement="Top">
<TabControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}" />
</DataTemplate>
</TabControl.ItemTemplate>
</TabControl>