2016-08-20 2 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 ]을 대체 번호로 사용할 수 있습니다.

사용자 지정 템플릿 선택기를 사용하려면 의 ContentTemplateSelector 속성으로 설정하면됩니다. 여기에 예

는 이제 자원으로 인스턴스화하고 사용 뷰 모델의 각 유형의 리소스를 생성 할 수있는 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

뒀다
관련 문제