如何根据绑定对象的类型动态更改DataTemplate?

时间:2016-04-13 17:34:19

标签: c# wpf xaml data-binding datatemplate

我尝试为View创建一个DataTemplate,根据绑定的对象类型显示特定的UserControl类型(如texbox,组合框,自定义控件或其他视图)。

我有以下MVVM框架:

FieldViewFieldPresenter的实例相关联,并且应该为&#34;标签&#34;显示<Textblock />属性,UserControl或另一个值的视图(基于值的类型),其数据源设置为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>

我很好奇我能做什么甚至是可能的,或者我是否可以通过让我的Presenter视图模型返回UserControl而不是对象值来解决它,并让Presenter解析UserControl从对象类型中键入,但我不觉得我的Presenter应该实例化控件(或者技术上是什么是未绑定的视图)。我应该创建一个界面,例如IViewAs<controlType> { controlType View { get; } }

如何使用基于数据绑定对象类型的UserControl的某种模板替换上述脚本中的<TextBox Text="{Binding Value}" />

1 个答案:

答案 0 :(得分: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