c# - 如何根据绑定(bind)对象的类型动态更改DataTemplate?

标签 c# wpf xaml data-binding datatemplate

我正在尝试为 View 创建一个 DataTemplate,以根据绑定(bind)到的对象类型显示特定的 UserControl 类型(如文本框、组合框、自定义控件或其他 View )。

我有以下 MVVM 框架:

FieldView绑定(bind)到 FieldPresenter 的实例,并且应该显示 <Textblock />对于“Label”属性,以及用于值的 UserControl 或另一个 View (基于值的类型),其数据源设置为 Presenter 的 Value 属性。目前,我还没有完成第二部分。我不知道如何编写我需要的 WPF 模板。

View 模型:

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 View 模型返回 UserControl 而不是对象值来解决它,并让 Presenter 从对象中解析 UserControl 类型类型,但我不觉得我的演示者应该实例化控件(或者技术上是未绑定(bind)的 View )。我应该制作一个界面,例如 IViewAs<controlType> { controlType View { get; } }

我还能如何替换 <TextBox Text="{Binding Value}" />在上面的脚本中使用某种基于数据绑定(bind)对象类型的 UserControl 模板?

最佳答案

您几乎肯定需要一个 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

关于c# - 如何根据绑定(bind)对象的类型动态更改DataTemplate?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36605639/

相关文章:

Windows7 上的 WPF 文本框边框

c# - WPF RichTextBox - 获取当前行

c# - ABAddressBook 已弃用,如何使用 ABAddressBook.Create 方法?

c# - 无法使用 MimeKit 解密 p7m

c# - 我的类(class)使用了多少内存实例 - 务实的答案

wpf - 键盘焦点的样式触发器

wpf - WPF 是 WinForms 的替代品吗?

wpf - 按钮内容中的样式 DataTrigger Setter 无效

c# - 是否有任何 html5 .Net 绑定(bind)框架

c# - WPF 命令如何获取所有必要的信息以添加到正确的列表项