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

WinUI中如何根据Type枚举属性切换ContentPresenter的DataTemplate?

WinUI中根据枚举属性切换Shimmer控件的DataTemplate

问题背景

定义了ShimmerType枚举对应7种Shimmer样式,给Shimmer控件添加了Type依赖属性,在XAML中编写了对应枚举值的DataTemplate,但尝试用代码切换模板未生效,需要实现根据Type值自动切换ContentPresenter的ContentTemplate。

现有核心代码片段

枚举定义

public enum ShimmerType 
{
    CirclePersona,
    SquarePersona,
    Profile,
    Article,
    Video,
    Feed,
    Shopping,
}

控件依赖属性

public ShimmerType Type
{
    get { return (ShimmerType)GetValue(TypeProperty); }
    set { SetValue(TypeProperty, value); }
}

public static readonly DependencyProperty TypeProperty = 
    DependencyProperty.Register("Type", typeof(ShimmerType), typeof(SfShimmer), 
        new PropertyMetadata(ShimmerType.CirclePersona, OnTypePropertyChangedMethod));

XAML中的DataTemplate

<DataTemplate x:Key="ShimmerFeedTemplate">
    <!-- 模板内容 -->
</DataTemplate>
<DataTemplate x:Key="ShimmerCirclePersonaTemplate">
    <!-- 模板内容 -->
</DataTemplate>
<DataTemplate x:Key="ShimmerArticleStyle">
    <!-- 模板内容 -->
</DataTemplate>
<DataTemplate x:Key="ShimmerProfileTemplate">
    <!-- 模板内容 -->
</DataTemplate>
<DataTemplate x:Key="ShimmerShoppingTemplate">
    <!-- 模板内容 -->
</DataTemplate>
<DataTemplate x:Key="ShimmerVideoTemplate">
    <!-- 模板内容 -->
</DataTemplate>

控件样式

<Style x:Key="ShimmerStyle" TargetType="local:SfShimmer">
    <Setter Property="HorizontalAlignment" Value="Center"/>
    <Setter Property="VerticalAlignment" Value="Center"/>
    <Setter Property="Fill" Value="{ThemeResource ShimmerFillColor}"/>
    <Setter Property="Template"> 
        <Setter.Value>
            <ControlTemplate TargetType="local:SfShimmer">
                <StackPanel>
                    <ContentControl x:Name="Grid1">
                        <ContentPresenter x:Name="presenters" ContentTemplate="{StaticResource ShimmerCirclePersonaTemplate}" />
                    </ContentControl>
                    <Grid x:Name="Grid2">
                        <ContentControl>
                            <ContentPresenter Content="{TemplateBinding Content}"/>
                        </ContentControl>
                    </Grid>
                </StackPanel>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

现有代码的问题

  1. 模板Key不匹配:代码中查找的ShimmerFeedControlTemplate和XAML定义的ShimmerFeedTemplate名字不一致;
  2. 资源查找范围错误:仅从控件自身Resources查找,可能找不到定义在控件样式资源字典里的模板;
  3. 时机问题:OnTypePropertyChanged执行时,控件模板可能还未应用,导致Presenter为null;
  4. 枚举值覆盖不全:缺少SquarePersona和Article的模板切换逻辑。

正确实现方案

1. 统一DataTemplate命名

把XAML中的ShimmerArticleStyle改为ShimmerArticleTemplate,新增ShimmerSquarePersonaTemplate,确保枚举值和模板Key遵循Shimmer{枚举值}Template的规则:

<DataTemplate x:Key="ShimmerFeedTemplate">
    <!-- 模板内容 -->
</DataTemplate>
<DataTemplate x:Key="ShimmerCirclePersonaTemplate">
    <!-- 模板内容 -->
</DataTemplate>
<DataTemplate x:Key="ShimmerArticleTemplate">
    <!-- 模板内容 -->
</DataTemplate>
<DataTemplate x:Key="ShimmerProfileTemplate">
    <!-- 模板内容 -->
</DataTemplate>
<DataTemplate x:Key="ShimmerShoppingTemplate">
    <!-- 模板内容 -->
</DataTemplate>
<DataTemplate x:Key="ShimmerVideoTemplate">
    <!-- 模板内容 -->
</DataTemplate>
<DataTemplate x:Key="ShimmerSquarePersonaTemplate">
    <!-- 模板内容 -->
</DataTemplate>

2. 修正控件C#代码

封装模板更新方法,确保在模板应用和属性变更时都能正确切换模板:

public class SfShimmer : Control
{
    public SfShimmer()
    {
        DefaultStyleKey = typeof(SfShimmer);
    }

    private ContentPresenter _presenter;

    public ShimmerType Type
    {
        get { return (ShimmerType)GetValue(TypeProperty); }
        set { SetValue(TypeProperty, value); }
    }

    public static readonly DependencyProperty TypeProperty =
        DependencyProperty.Register(nameof(Type), typeof(ShimmerType), typeof(SfShimmer), 
            new PropertyMetadata(ShimmerType.CirclePersona, OnTypePropertyChanged));

    protected override void OnApplyTemplate()
    {
        base.OnApplyTemplate();
        // 获取模板中的ContentPresenter
        _presenter = GetTemplateChild("presenters") as ContentPresenter;
        // 模板应用后立即更新对应模板
        UpdateShimmerTemplate();
    }

    private static void OnTypePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        if (d is SfShimmer shimmer)
        {
            shimmer.UpdateShimmerTemplate();
        }
    }

    private void UpdateShimmerTemplate()
    {
        if (_presenter == null) return;

        DataTemplate template = null;
        // 根据枚举值自动拼接模板Key
        string templateKey = $"Shimmer{Type}Template";
        
        // 优先从控件资源查找,找不到再从应用全局资源查找
        if (Resources.ContainsKey(templateKey))
        {
            template = Resources[templateKey] as DataTemplate;
        }
        else if (Application.Current.Resources.ContainsKey(templateKey))
        {
            template = Application.Current.Resources[templateKey] as DataTemplate;
        }

        // 兜底逻辑:找不到对应模板时用默认的CirclePersona模板
        if (template == null)
        {
            template = Resources["ShimmerCirclePersonaTemplate"] as DataTemplate 
                ?? Application.Current.Resources["ShimmerCirclePersonaTemplate"] as DataTemplate;
        }

        _presenter.ContentTemplate = template;
    }
}

3. 调整控件样式

去掉ContentPresenter的硬编码默认模板,让代码逻辑控制模板切换:

<Style x:Key="ShimmerStyle" TargetType="local:SfShimmer">
    <Setter Property="HorizontalAlignment" Value="Center"/>
    <Setter Property="VerticalAlignment" Value="Center"/>
    <Setter Property="Fill" Value="{ThemeResource ShimmerFillColor}"/>
    <Setter Property="Template"> 
        <Setter.Value>
            <ControlTemplate TargetType="local:SfShimmer">
                <StackPanel>
                    <ContentControl x:Name="Grid1">
                        <ContentPresenter x:Name="presenters" />
                    </ContentControl>
                    <Grid x:Name="Grid2">
                        <ContentControl>
                            <ContentPresenter Content="{TemplateBinding Content}"/>
                        </ContentControl>
                    </Grid>
                </StackPanel>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

4. MainWindow用法保持不变

<shim:Shimmer x:Name="shimmer" Type="Profile" />

内容的提问来源于stack exchange,提问作者Budding bro

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 23:47:03