如何从DataTemplateSelector中显式刷新DataTemplate?

20
我为所需的ContentControl.DataTemplateSelector 设置了一个模板选择器。
我希望能够通过XAML或代码根据命令或其他方式调用ContentControl,从选择器中重新选择模板。
谢谢。
4个回答

21

虽然晚到了,但我知道这个问题。

在面对此问题时,我发现最简单的方法是明确地设置一个新的TemplateSelector,例如:

MyContentControl.ContentTemplateSelector =
     new MyDataTemplateSelector();

+1 从来不晚!与其他令人沮丧的帖子不同,它们告诉你没有办法做你想做的事情!你的解决方案有效,并给了我一个很好的思路,我会在今天稍后有时间时发布它。 - denis morozov
实际上我所做的是,在我的DataTemplateSelector中将调用SelectTemplate的每个Presenter(作为弱引用)存储起来,并提供一个静态方法来刷新所有这些内容。 - Jens
如果您在绑定到自己的类时引发了属性更改事件,会发生什么? - Monstieur
如果内容类型没有改变,我相信它会使用当前模板进行渲染,而不是再次请求模板选择器。 - Jens
这会使组件完全重新渲染,即使所选模板相同:/ - Bruno Lemos

15
我可能比较晚加入这个话题,但以下的想法或许能帮到一些人......你也可以尝试在ContentControlContentTemplate属性上使用ValueConverter而非DataTemplateSelector
只需在DataContext中绑定一个属性(例如ScreenNumber),然后在ValueConverter中返回与该ScreenNumber相关联的DataTemplate即可。
以下是示例ValueConverter:
public class ValueDataTemplateConverter : IValueConverter
{
    public DataTemplate TemplateA { get; set; }
    public DataTemplate TemplateB { get; set; }

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (value is ValueType valueType)
            switch (valueType)
            {
                case ValueType.TypeA:
                    return TemplateA;
                case ValueType.TypeB:
                    return TemplateB;
             }

        return null;
    }

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

示例 XAML 资源:

<converters:ValueDataTemplateConverter x:Key="ValueDataTemplateConverter">
    <converters:ValueDataTemplateConverter.TemplateA>
        <DataTemplate>
            <TextBox Text="{Binding Value}" />
        </DataTemplate>
    </converters:ValueDataTemplateConverter.TemplateA>
    <converters:ValueDataTemplateConverter.TemplateB>
        <DataTemplate>
            <CheckBox IsChecked="{Binding Value}" />
        </DataTemplate>
    </converters:ValueDataTemplateConverter.TemplateB>
</converters:ValueDataTemplateConverter>

1
谢谢您多年后更新这个。我本来没想到要使用转换器,而这个解决方案也不需要用到代码后台。非常好。 - Seanba

12

我不知道有没有(非笨拙的)方法可以做到这一点:当WPF需要选择模板时,DataTemplateSelector会被调用,而就WPF而言,这是一次性的决策。 (您可以通过让WPF认为内容已更改来欺骗它,例如将内容设置为null,然后再设置回来-我认为这样可以工作,但尚未测试-但这相当丑陋!)如果有一种好的方法来做到这一点,我也很想知道!

但是,还有一种替代方式可以更改内容的显示方式,并且在响应数据更改时进行更新,即通过触发器。您可以在DataTemplate.Triggers集合中使用DataTriggers来根据内容数据显示和隐藏元素。要更改整个显示,您可以例如在Grid中设置两个渲染,并使用触发器控制哪个可见。您甚至可以使您的数据模板成为ContentControl,并使用触发器更改ContentTemplate。当然,这取决于更改模板的标准是否是可绑定属性,这可能并非总是如此。

这里有一些关于选择器与触发器的简要讨论,虽然上下文略有不同。


1
我在使用DataTrigger时遇到了问题,请看一下:https://dev59.com/CkvSa4cB1Zd3GeqPeGiG - Shimmy Weitzhandler

6
与Jens的答案类似,不需要创建新实例,可以使用现有的实例。
var currentSelector = MyContentControl.ContentTemplateSelector;     
MyContentControl.ContentTemplateSelector = null;
MyContentControl.ContentTemplateSelector = currentSelector;

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接