2016-08-20 6 views
2

DataTemplateをPageResource内のContentControlに設定するにはどうすればよいですか?私はContentControlにUserControlを表示したいと思います。私はContentControlをナビゲーション領域のように使いたいと思います。したがって、UserControlsに表示される内容を変更することができます。 DataTemplateをWindows Universal App 10のPageResourceの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> 

私のシェルのビューモデルは次のとおりです。

私は、このリンクから、以下のようなPage.Resourceを設定してみました
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 
    } 
} 

Window vs Page vs UserControl for WPF navigation?

<Window.Resources> 
     <DataTemplate DataType="{x:Type local:HomeViewModel}"> 
     <local:HomeView /> <!-- This is a UserControl --> 
     </DataTemplate> 
     <DataTemplate DataType="{x:Type local:ProductsViewModel}"> 
     <local:ProductsView /> <!-- This is a UserControl --> 
     </DataTemplate> 
    </Window.Resources> 

しかし、これらは別の名前空間を使用しています。私のアプリはWindows 10 Universal App DataTemplateのDataType属性はありません。

MVVMパターンを使用してアプリケーションを作成しようとしています(コードスニペットから辛いものではない場合)。

答えて

2

DataTemplateSelectorから派生したクラスを作成すると、それを実行できます。

このクラスでは、SelectTemplateCoreメソッドをオーバーライドして、データ型に基づいて必要なDataTemplateを返します。これをもっと自動化するには、各テンプレートのキーをクラスの名前に合わせて設定し、GetType().Nameを使って取得したその名前のリソースを検索します。

異なるレベルで特定の実装を提供できるようにするには、一致するリソースが見つかるまでVisualTreeHelper.GetParent()を使用してツリーを歩き回り、Application.Current.Resources[ typeName ]をフォールバックとして使用します。

カスタムテンプレートセレクタを使用するには、ContentControlのプロパティをContentTemplateSelectorに設定するだけです。ここでは例

は、あなたが今、リソースとしてそれをインスタンス化し、使用のViewModelの種類ごとにリソースを作成することができますAutoDataTemplateSelector

public class AutoDataTemplateSelector : DataTemplateSelector 
{ 
    protected override DataTemplate SelectTemplateCore(object item) => GetTemplateForItem(item, null); 

    protected override DataTemplate SelectTemplateCore(object item, DependencyObject container) => GetTemplateForItem(item, container); 

    private DataTemplate GetTemplateForItem(object item, DependencyObject container) 
    { 
     if (item != null) 
     { 
      var viewModelTypeName = item.GetType().Name; 
      var dataTemplateInTree = FindResourceKeyUpTree(viewModelTypeName, container); 
      //return or default to Application resource 
      return dataTemplateInTree ?? (DataTemplate)Application.Current.Resources[ viewModelTypeName ]; 
     } 
     return null; 
    } 

    /// <summary> 
    /// Tries to find the resources up the tree 
    /// </summary> 
    /// <param name="resourceKey">Key to find</param> 
    /// <param name="container">Current container</param> 
    /// <returns></returns> 
    private DataTemplate FindResourceKeyUpTree(string resourceKey, DependencyObject container) 
    { 
     var frameworkElement = container as FrameworkElement; 
     if (frameworkElement != null) 
     { 
      if (frameworkElement.Resources.ContainsKey(resourceKey)) 
      { 
       return frameworkElement.Resources[ resourceKey ] as DataTemplate; 
      } 
      else 
      { 
       return FindResourceKeyUpTree(resourceKey, VisualTreeHelper.GetParent(frameworkElement)); 
      } 
     } 
     return null; 
    } 
} 

のサンプル実装です

<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と一緒に使用できます:

<ContentControl ContentTemplateSelector="{StaticResource AutoDataTemplateSelector}" 
    Content="{x:Bind CurrentViewModel, Mode=OneWay}" /> 

私はsample solution on GitHub

を入れています
関連する問題