【问题标题】:How to resolve content presenter not displaying View?如何解决内容演示者不显示视图?
【发布时间】:2016-03-05 11:44:10
【问题描述】:

我在 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];
}

【问题讨论】:

  • 我认为ContentPresenter 需要在ItemTemplate 中,而不是ContentTemplate。试试看。
  • @MikeEason 我认为ItemTemplate 将设置 TabItem 本身的样式,而不是 Content 部分

标签: wpf mvvm datatemplate tabcontrol contentpresenter


【解决方案1】:

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>

【讨论】:

  • 好吧,这是有道理的,是否可以设置选项卡控件绑定,以便如果没有从 CustomerDetailsViewModel 中的数据网格中选择记录。第二个 CustomerOrdersViewModel 选项卡将被禁用或没有显示该选项卡的 UI?或者在这种情况下这是一个好主意还是坏主意?
  • 我将在IPageViewModel 上创建一个IsEnabled 属性,并使用&lt;ItemContainerStyle&gt; 将TabItem 的.IsEnabled 属性绑定到它,例如this。我假设选项卡有某种方式相互交谈以将SelectedCustomer 传递给CustomerOrdersViewModel,因此您可以将IsEnabled 基于CustomerOrdersViewModel 是否为空,或者直接设置它当你想要启用/禁用它。
  • 我尝试实施上述关于启用标签的建议。在条件下仅启用一个选项卡时遇到问题。总之,一旦我在启用第二个选项卡后选择第二个选项卡,我就无法导航回第一个选项卡。如果您有任何意见,我在上面发布了一个问题:stackoverflow.com/questions/34042541/…
  • 我已经成功实现了上述内容。但是我现在在创建与 AppView 分开的对话框时遇到了问题。问题是对 ShowDialog() 的调用会阻止向打开的 VM 发送消息的调用。这导致在关闭对话框之前不会收到消息。如果您对如何解决该问题有任何想法,我已经在这里发布了一个问题:stackoverflow.com/questions/34347091/…
  • @BrianJ 看起来您在我看到它之前已经得到了答案 :) 就我个人而言,我不喜欢 WPF 弹出窗口或对话框控件,所以我使用custom PopupUserControl 来满足我的任何对话框需求。它只是一个漂浮在其他一切之上的 UserControl。
【解决方案2】:

我们通常不会在ControlTemplate 之外使用ContentPresenter,当然也不会像您在DataTemplate 中那样使用...使用ContentPresenter 将使WPF 框架搜索@ 987654325@ 与Content 的类型匹配,因此在您的情况下,您最终将陷入无限循环。相反,您应该将关联的视图放在DataTemplate

<DataTemplate DataType="{x:Type YourDataXamlPrefix:CurrentPageViewModel}">
    <YourUiXamlPrefix:YourView DataContext="{Binding CurrentPageViewModel}" />
</DataTemplate>

这样,当Framework在集合中遇到你的视图模型类时,它会找到这个DataTemplate并渲染相关的视图。

【讨论】:

  • 我不得不不同意第一行,当我想在 VisualTree 中插入一些非 UI 内容时,我一直使用 ContentPresenter。一个常见的例子就像 OP 所拥有的 (&lt;ContentPresenter Content="{Binding CurrentPageViewModel}" /&gt;),尽管通常我的绑定是正确的,我不会像发布的代码那样将它用作 ContentTemplate 中的唯一项目:)
  • 我认为有人可能会这么说(因为我偶尔也会这样使用它们),所以我添加了“一般”,但显然这还不够。我试图保持答案简洁,而不是深入探讨ContentPresenter 的所有可能用途并专注于用户的问题,但感谢 Rachel 强调这一点。
猜你喜欢
  • 2015-07-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-04-27
相关资源
最近更新 更多