2016-04-13 119 views
1

我想創建一個視圖的DataTemplate,以顯示一個特定的UserControl類型(如texbox,組合框,自定義控件或另一個視圖)基於它綁定到的對象的類型。如何根據綁定對象的類型動態更改DataTemplate?

我有以下MVVM框架:

FieldView是聯繫在一起的FieldPresenter一個實例,應爲「標籤」屬性顯示<Textblock />,和用戶控件或其他信息查看值(基於類型的值),將其DataSource設置爲Presenter的Value屬性。目前,我沒有第二部分工作。我無法弄清楚如何根據需要編寫WPF模板。

視圖模型:

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> 

我很好奇,如果我想要做的,甚至有可能,或者,如果我可以讓我的演示視圖模型迴歸變通辦法一個UserControl而不是一個對象值,並讓Presenter從對象類型中解析UserControl類型,但是我不覺得我的Presenter應該實例化Controls(或者技術上是一個未綁定的視圖)。我應該製作一個界面,如IViewAs<controlType> { controlType View { get; } }

在基於數據綁定對象類型的UserControl的某種模板的上述腳本中,我還將如何替換<TextBox Text="{Binding Value}" />

回答

1

幾乎可以確定你想要一個ContentTemplateSelector

代碼:

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

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}」',將' DataType =「local:Cube」>「'DataTemplate DataType =」{ x:Type local:Cube}「>'並將 DataType =」local:Sphere「>''更改爲':local local:Sphere}>>。代碼將完全相同。 –

+1

你是對的,但這樣做總是會爲同一類型反覆地分配相同的模板,例如OP可以通過某種機制指定特定的模板名稱,他可以保持對同一模板分配不同模板的控制權鍵入(他是否需要這樣的東西):) – Aybe

+0

現在你可以保持你的VM清潔:) – Aybe

相關問題