You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为泛型控件应用全局ControlTemplate?

泛型ControlTemplate无法触发OnApplyTemplate的解决方案

问题描述

定义了泛型控件:

public class BarChart<T> : ContentView
{
    protected override void OnApplyTemplate()
    {
        base.OnApplyTemplate();
    }
}

并关联了模板和样式:

<ControlTemplate x:Key="BarChartControlTemplate">
    [...]
</ControlTemplate>
<Style TargetType="{x:Type controls:BarChart`1}">
    <Setter 
        Property="ControlTemplate"
        Value="{StaticResource BarChartControlTemplate}" />
</Style>

但OnApplyTemplate()始终未被调用,特化控件(如public class IntBarChart : ContentView)可正常工作,但不符合泛型需求。尝试让泛型控件继承非泛基类:

public class BarChart : ContentView
{
    protected override void OnApplyTemplate()
    {
        base.OnApplyTemplate();
    }
}

public class BarChart<T> : BarChart
{
    protected override void OnApplyTemplate()
    {
        base.OnApplyTemplate();
    }
}

问题依旧存在,询问是否有可行的全局模板方案。

可行解决方案

方案1:在泛型控件代码中手动加载并应用模板

由于XAML对泛型类型的全局样式支持存在限制,可在泛型控件的构造函数或初始化逻辑中,从资源字典手动获取模板并赋值:

public class BarChart<T> : BarChart
{
    public BarChart()
    {
        if (Application.Current.Resources.TryGetValue("BarChartControlTemplate", out var template))
        {
            ControlTemplate = template as ControlTemplate;
        }
    }

    protected override void OnApplyTemplate()
    {
        base.OnApplyTemplate();
        // 此处可处理模板内元素的逻辑
    }
}

这种方式绕过XAML对泛型类型的识别限制,直接在代码层绑定模板,确保OnApplyTemplate被触发。

方案2:使用附加属性统一应用模板

创建一个附加属性,为任意BarChart泛型实例设置模板,可在XAML中直接对泛型控件实例应用:

public static class BarChartTemplateHelper
{
    public static readonly DependencyProperty ApplyTemplateProperty =
        DependencyProperty.RegisterAttached(
            "ApplyTemplate",
            typeof(bool),
            typeof(BarChartTemplateHelper),
            new PropertyMetadata(false, OnApplyTemplateChanged));

    public static bool GetApplyTemplate(DependencyObject obj)
    {
        return (bool)obj.GetValue(ApplyTemplateProperty);
    }

    public static void SetApplyTemplate(DependencyObject obj, bool value)
    {
        obj.SetValue(ApplyTemplateProperty, value);
    }

    private static void OnApplyTemplateChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        if ((bool)e.NewValue && d is BarChart chart)
        {
            if (Application.Current.Resources.TryGetValue("BarChartControlTemplate", out var template))
            {
                chart.ControlTemplate = template as ControlTemplate;
            }
        }
    }
}

在XAML中使用方式:

<controls:BarChart<int> local:BarChartTemplateHelper.ApplyTemplate="True" />

这种方式既保留泛型灵活性,又能通过附加属性统一管理模板应用。

方案3:确保非泛基类的样式被正确继承

如果采用非泛基类的结构,需确保基类样式被正确应用,且泛型子类未覆盖ControlTemplate属性。先为基类定义样式:

<Style TargetType="{x:Type controls:BarChart}">
    <Setter 
        Property="ControlTemplate"
        Value="{StaticResource BarChartControlTemplate}" />
</Style>

泛型控件无需额外样式,因继承自BarChart会自动应用基类样式。若仍不生效,可在泛型控件构造函数中强制继承基类样式:

public class BarChart<T> : BarChart
{
    public BarChart()
    {
        Style = FindResource(typeof(BarChart)) as Style;
    }
}

内容的提问来源于stack exchange,提问作者Jeremy A.

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 21:25:27