2016-04-13 13 views
1

私はバインドされているオブジェクトのタイプに基づいて、特定のUserControlタイプ(texbox、コンボボックス、カスタムコントロール、または別のビューなど)を表示するために、ViewのDataTemplateを作成しようとしています。バインドされたオブジェクトの型に従ってDataTemplateを動的に変更する方法はありますか。

私は、次のMVVMフレームワークを持っている:

FieldViewFieldPresenterのインスタンスに結ばれ、「ラベル」プロパティ、およびユーザーコントロールまたはタイプに基づいた値(のための別のビューの<Textblock />が表示されるはずですその値はPresenterのValueプロパティに設定されています)。現在、私は第二の部分が働いていません。私は必要なもののためのWPFテンプレートを書く方法を理解できません。

のViewModel:

public class FieldPresenter : Observable<object>, IFieldPresenter, INotifyPropertyChanged 
{ 
    public FieldPresenter() { } 
    public FieldPresenter(object value) 
    { 
     Value = value; 
    } 
    object IFieldPresenter.Value 
    { 
     get 
     { 
      return base.Value; 
     } 

     set 
     { 
      base.Value = value; 
      OnPropertyChanged("Value"); 
     } 
    } 
    private string _label; 
    public virtual string Label 
    { 
     get 
     { 
      return _label; 
     } 
     private set 
     { 
      _label = value; 
      OnPropertyChanged("Label"); 
     } 
    } 
} 

ビュー:

<UserControl x:Class="My.Views.FieldView" 
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
      xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
      xmlns:ViewModels="clr-namespace:My.ViewModels" 
      mc:Ignorable="d" 
      d:DesignHeight="24" d:DesignWidth="100"> 
    <UserControl.DataContext> 
     <ViewModels:FieldPresenter/> 
    </UserControl.DataContext> 
     <UserControl.Template> 
      <ControlTemplate> 
       <Grid Margin="4"> 
        <Grid.ColumnDefinitions> 
         <ColumnDefinition Width="Auto" SharedSizeGroup="Key" /> 
        </Grid.ColumnDefinitions> 
        <StackPanel Margin="0,0,0,0" HorizontalAlignment="Stretch" Width="{Binding RelativeSource={RelativeSource AncestorType=Grid}, Path=ActualWidth}"> 
         <TextBlock Text="{Binding Label}" FontWeight="Bold" Height="32" HorizontalAlignment="Stretch"/> 
         <TextBox Text="{Binding Value}" Height="Auto" HorizontalAlignment="Stretch"/> 
        </StackPanel> 
       </Grid> 
      </ControlTemplate> 
     </UserControl.Template> 
</UserControl> 

私がやろうとしていることも、可能であるならば、私は好奇心が強い、または私はプレゼンターのviewmodelリターンを作ることによって、それを回避することができる場合オブジェクト値ではなくUserControlを使用し、Presenterがオブジェクト型からUserControl Typeを解析するようにしましたが、Presenterがコントロールをインスタンス化する必要はありません(つまり、技術的にはバインドされていないビューです)。私はIViewAs<controlType> { controlType View { get; } }のようなインターフェイスを作っていいですか?

上記のスクリプトの<TextBox Text="{Binding Value}" />を、データバインドされたオブジェクトの型に基づいたUserControlのテンプレートに置き換えるとどうなりますか?

あなたはほぼ確実に ContentTemplateSelectorたい

答えて

1

コード:

using System.Windows; 
using System.Windows.Controls; 

namespace WpfApplication1 
{ 
    public partial class MainWindow : Window 
    { 
     public MainWindow() 
     { 
      InitializeComponent(); 

      Primitive primitive; 

      primitive = new Sphere(); 
      // primitive = new Cube(); 
      DataContext = primitive; 
     } 
    } 

    internal abstract class Primitive 
    { 
     public abstract string Description { get; } 
    } 

    internal class Cube : Primitive 
    { 
     public override string Description 
     { 
      get { return "Cube"; } 
     } 
    } 

    internal class Sphere : Primitive 
    { 
     public override string Description 
     { 
      get { return "Sphere"; } 
     } 
    } 

    public class MyTemplateSelector : DataTemplateSelector 
    { 
     public override DataTemplate SelectTemplate(object item, DependencyObject container) 
     { 
      var frameworkElement = container as FrameworkElement; 
      if (frameworkElement != null && item != null) 
      { 
       if (item is Cube) 
       { 
        return frameworkElement.FindResource("CubeTemplate") as DataTemplate; 
       } 
       if (item is Sphere) 
       { 
        return frameworkElement.FindResource("SphereTemplate") as DataTemplate; 
       } 
      } 

      return base.SelectTemplate(item, container); 
     } 
    } 
} 

XAML:

<Window x:Class="WpfApplication1.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
     xmlns:local="clr-namespace:WpfApplication1" 
     xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
     x:Name="Window" 
     Title="MainWindow" 
     Width="525" 
     Height="350" 
     mc:Ignorable="d"> 

    <Grid> 
     <Grid.Resources> 
      <local:MyTemplateSelector x:Key="myTemplateSelector" /> 
      <DataTemplate x:Key="CubeTemplate" DataType="local:Cube"> 
       <Border BorderBrush="Blue" 
         BorderThickness="1" 
         CornerRadius="5" /> 
      </DataTemplate> 
      <DataTemplate x:Key="SphereTemplate" DataType="local:Sphere"> 
       <Border BorderBrush="Red" 
         BorderThickness="1" 
         CornerRadius="50" /> 
      </DataTemplate> 
     </Grid.Resources> 
     <Grid.RowDefinitions> 
      <RowDefinition Height="Auto" /> 
      <RowDefinition Height="1*" /> 
      <RowDefinition /> 
     </Grid.RowDefinitions> 
     <Label Grid.Row="0" 
       Content="{Binding Description}" 
       d:DataContext="{d:DesignInstance local:Primitive}" /> 
     <ContentControl Grid.Row="1" 
         Content="{Binding}" 
         ContentTemplateSelector="{StaticResource myTemplateSelector}" /> 

    </Grid> 
</Window> 

結果:

enter image description here

を0

enter image description here

は、より多くのドキュメントを参照してください。

https://msdn.microsoft.com/en-us/library/system.windows.controls.datatemplateselector(v=vs.110).aspx

+1

'ContentTemplateSelector'がこの回答に完全に不要である' DataType'バインディングが宣言されていないので、それはここで必要なの唯一の理由があります正しく。リソースブロックから 'ContentTemplateSelector'を削除し、' ContentTemplateSelector = "{StaticResource myTemplateSelector}" 'を削除し、' '' DataTemplate DataType = "{ x:Key = "SphereTemplate" DataType = "local:Sphere">>をに変更します。コードはまったく同じように動作します。 –

+1

あなたは正しいですが、そうすることで常に同じテンプレートを同じタイプに何度も繰り返し割り当てます。たとえば、OPは特定のメカニズムを使って特定のテンプレート名を指定でき、同じテンプレートに対して異なるテンプレートを割り当てることができます(彼はそのようなものが必要です):) – Aybe

+0

今あなたのVMをきれいに保つことができます:) – Aybe

関連する問題