Mvvm 如何在Windows Universal App 10中将DataTemplate设置为页面资源中的ContentControl?

Mvvm 如何在Windows Universal App 10中将DataTemplate设置为页面资源中的ContentControl?,mvvm,visual-studio-2015,uwp,Mvvm,Visual Studio 2015,Uwp,如何将DataTemplate设置为PageResource中的ContentControl?我想在我的ContentControl中显示一个UserControl,并且我想像使用导航区域一样使用ContentControl。因此,它可以更改用户控件中显示的内容 我有一个Shell.xaml: <Page x:Class="MyProject.Shell" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/present

如何将DataTemplate设置为PageResource中的ContentControl?我想在我的ContentControl中显示一个UserControl,并且我想像使用导航区域一样使用ContentControl。因此,它可以更改用户控件中显示的内容

我有一个Shell.xaml:

<Page
    x:Class="MyProject.Shell"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"    
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"    
    xmlns:local="using:MyProject"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    xmlns:View="using:MyProject.View"
    xmlns:ViewModel="using:MyProject.ViewModel">

    <Page.DataContext>
        <ViewModel:ShellViewModel />
    </Page.DataContext>

    <Page.Resources>
        <DataTemplate>
             <View:MyUserControlViewModel1 />
        </DataTemplate>

        <DataTemplate>
             <View:MyUserControlViewModel2 />
        </DataTemplate>
    </Page.Resources>

    <StackPanel>

        <ItemsControl ItemsSource="{Binding PageViewModels}">
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <Button Content="{Binding Name}"/>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>

        <ContentControl Content="{Binding CurrentPageViewModel}">
        </ContentControl>
    </StackPanel>
</Page>

我的Shell的视图模型是:

namespace MyProject.ShellViewModel
{
    class ShellViewModel : ObservableObject
    {
        #region Fields

        private ICommand _changePageCommand;
        private IPageViewModel _currentPageViewModel;
        private List<IPageViewModel> _pageViewModels;

        #endregion

        #region Properties / Commands

        public List<IPageViewModel> PageViewModels
        {
            get
            {
                if (_pageViewModels == null)
                {
                    _pageViewModels = new List<IPageViewModel>();
                }
                return _pageViewModels;
            }
        }

        public IPageViewModel CurrentPageViewModel
        {
            get { return _currentPageViewModel; }
            set
            {
                if (_currentPageViewModel != value)
                {
                    _currentPageViewModel = value;
                    OnPropertyChanged("CurrentPageViewModel");
                }
            }
        }
        #endregion

        #region Methods

        public ShellViewModel()
        {
            PageViewModels.Add(new MyUserControlViewModel1());
            PageViewModels.Add(new MyUserControlViewModel2());

            CurrentPageViewModel = PageViewModels[0];
        }

        #endregion
    }
}
名称空间MyProject.ShellViewModel
{
类ShellViewModel:ObserveObject
{
#区域字段
专用ICommand _changePageCommand;
私有IPageViewModel\u currentPageViewModel;
私有列表pageViewModels;
#端区
#区域属性/命令
公共列表页面视图模型
{
得到
{
如果(_pageViewModels==null)
{
_pageViewModels=新列表();
}
返回页面视图模型;
}
}
公共IPageViewModel CurrentPageViewModel
{
获取{return\u currentPageViewModel;}
设置
{
如果(_currentPageViewModel!=值)
{
_currentPageViewModel=值;
OnPropertyChanged(“CurrentPageViewModel”);
}
}
}
#端区
#区域方法
公共ShellViewModel()
{
添加(新的MyUserControlViewModel1());
添加(新的MyUserControlViewModel2());
CurrentPageViewModel=PageViewModels[0];
}
#端区
}
}
我尝试设置页面。此链接中的资源如下所示:


但是它们使用另一个名称空间,对我来说不起作用,因为我的应用程序是Windows10通用应用程序,例如DataTemplate没有数据类型属性


我正在尝试使用MVVM模式创建应用程序(如果它显然不是来自代码片段)。

您可以通过创建一个派生自
DataTemplateSelector
的类来实现

在此类中,您可以重写
SelectTemplateCore
方法,该方法将根据数据类型返回所需的
DataTemplate
。为了使这一切更具自动魔力,您可以将每个模板的键设置为与类的名称匹配,然后使用
GetType().name
搜索具有该名称的资源

为了能够在不同的级别上提供特定的实现,您可以使用
VisualTreeHelper.GetParent()
沿着树向上走,直到找到匹配的资源,并使用
Application.Current.Resources[typeName]
作为回退

要使用自定义模板选择器,只需将其设置为
ContentControl
ContentTemplateSelector
属性

示例

下面是一个
AutoDataTemplateSelector

公共类AutoDataTemplateSelector:DataTemplateSelector
{
受保护的覆盖数据模板SelectTemplateCore(对象项)=>GetTemplateForItem(项,空);
受保护的覆盖数据模板SelectTemplateCore(对象项,DependencyObject容器)=>GetTemplateForItem(项,容器);
私有数据模板GetTemplateForItem(对象项,DependencyObject容器)
{
如果(项!=null)
{
var viewModelTypeName=item.GetType().Name;
var dataTemplateInTree=FindResourceKeyUpTree(viewModelTypeName,容器);
//返回或默认为应用程序资源
返回dataTemplateInTree???(DataTemplate)Application.Current.Resources[viewModelTypeName];
}
返回null;
}
/// 
///试图找到树上的资源
/// 
///找到的钥匙
///当前容器
/// 
私有数据模板FindResourceKeyUpTree(字符串resourceKey,DependencyObject容器)
{
var frameworkElement=容器作为frameworkElement;
if(frameworkElement!=null)
{
if(frameworkElement.Resources.ContainsKey(resourceKey))
{
返回frameworkElement.Resources[resourceKey]作为DataTemplate;
}
其他的
{
返回FindResourceKeyUpTree(resourceKey,VisualTreeHelper.GetParent(frameworkElement));
}
}
返回null;
}
}
现在可以将其实例化为资源,并为所使用的每种类型的ViewModel创建资源

<Application.Resources>
    <local:AutoDataTemplateSelector x:Key="AutoDataTemplateSelector" />

    <!-- sample viewmodel data templates -->
    <DataTemplate x:Key="RedViewModel">
        <Rectangle Width="100" Height="100" Fill="Red" />
    </DataTemplate>
    <DataTemplate x:Key="BlueViewModel">
        <Rectangle Width="100" Height="100" Fill="Blue" />
    </DataTemplate>
</Application.Resources>
我已经把

<Application.Resources>
    <local:AutoDataTemplateSelector x:Key="AutoDataTemplateSelector" />

    <!-- sample viewmodel data templates -->
    <DataTemplate x:Key="RedViewModel">
        <Rectangle Width="100" Height="100" Fill="Red" />
    </DataTemplate>
    <DataTemplate x:Key="BlueViewModel">
        <Rectangle Width="100" Height="100" Fill="Blue" />
    </DataTemplate>
</Application.Resources>
<ContentControl ContentTemplateSelector="{StaticResource AutoDataTemplateSelector}"
   Content="{x:Bind CurrentViewModel, Mode=OneWay}" />