在生成的字段中的值更改上设置ContentPresenter ContentTemplate

时间:2019-07-10 14:20:30

标签: wpf

我正在尝试建立一个树形视图,其中: 1. TreeViewItems由模型中的列表生成。 2.每个TreeViewItem都包含一个ComboBox和一个动态元素,我想根据其在ComboBox中选择的值更改其模板。

这是我当前的xaml代码。

<Window x:Class="MyTestWPF.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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:MyTestWPF"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Window.Resources>
        <local:NodeTypeToTemplateConverter x:Key="NodeTypeToTemplateConverter"/>
        <DataTemplate x:Key="Template1">
            <TextBlock Text="Template 1" />
        </DataTemplate>
        <DataTemplate x:Key="Template2">
            <TextBlock Text="Template 2" />
        </DataTemplate>
        <Style x:Key="MyNodeTemplate" TargetType="ContentPresenter">
            <Setter Property="ContentTemplate" Value="{StaticResource Template1}"/>
            <Style.Triggers>
                <DataTrigger Binding="{Binding Path=NodeType}">
                    <DataTrigger.Value>
                        <local:NodeTypesEnum>Type1</local:NodeTypesEnum>
                    </DataTrigger.Value>
                    <Setter Property="ContentTemplate" Value="{Binding Converter={StaticResource NodeTypeToTemplateConverter}}"/>
                </DataTrigger>
            </Style.Triggers>
        </Style>
        <HierarchicalDataTemplate DataType="{x:Type local:MyTreeNode}"
                              ItemsSource="{Binding Nodes}">
            <StackPanel Orientation="Horizontal">
                <ComboBox ItemsSource="{Binding Path=GetAvailableNodeType}"
                      SelectedItem="{Binding Path=NodeType}" />
                <ContentPresenter Style="{StaticResource MyNodeTemplate}" Content="{Binding}" />
            </StackPanel>
        </HierarchicalDataTemplate>
    </Window.Resources>
    <TreeView x:Name="MyTree" ItemsSource="{Binding MyTreeModel}" />
</Window>

及其背后的代码:

using System.Windows;
public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        this.DataContext = new
        {
            MyTreeModel = new MyTreeNode[] {
                new MyTreeNode() { Name = "1", Nodes = new MyTreeNode[] { new MyTreeNode() { Name= "2" } } }
            }
        };
    }
}

树节点类型:

namespace MyTestWPF
{
    public class MyTreeNode
    {
        public string Name { get; set; }
        public NodeTypesEnum NodeType { get; set; }
        public MyTreeNode[] Nodes { get; set; }
        public NodeTypesEnum[] GetAvailableNodeType()
        {
            return new NodeTypesEnum[] { NodeTypesEnum.Type1, NodeTypesEnum.Type2 };
        }
    }

    public enum NodeTypesEnum
    {
        Type1 = 0,
        Type2 = 1
    }
}

转换器(NodeTypeToTemplateConverter)接收整个ViewModel,并根据模型中的值返回相关模板的名称。

using System;
using System.Globalization;
using System.Windows.Data;

namespace MyTestWPF
{
    public class NodeTypeToTemplateConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if((value as MyTreeNode).NodeType == NodeTypesEnum.Type1)
            {
                return "Template1";
            } else
            {
                return "Template2";
            }
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
}

问题是上述代码导致堆栈溢出异常。 TreeView中的第一项无休止地调用NodeTypeToTemplateConverter的Convert方法。

我认为这与DataTrigger.Value有关。将其设置为不同于默认值NodeType的值可以使页面加载而不会溢出,但是任何ComboBox设置为NodeType1时,堆栈溢出

我试图简单地删除DataTrigger.Value元素,但这导致从不调用Converter ...

如何根据其相邻的ComboBox选择的值动态构建模板名称?

1 个答案:

答案 0 :(得分:1)

您可能想使用DataTemplateSelector而不是转换器。

default

我还没有完全测试此代码,所以如果您有任何问题,请告诉我。

编辑:

仅当内容更改时才执行模板选择器,因此如果您使用{Binding},则该选择器将不起作用。一种解决方法是将DataTemplate内容绑定到父级的DataContext。

Key

如果此解决方法不可接受,则还有其他方法可以实现。