WinUI中如何根据枚举Type属性为Shimmer控件匹配对应样式?
问题描述
我在WinUI中为自定义Shimmer控件编写了7个Style,所有Style的TargetType均为local:Shimmer。该控件拥有一个枚举类型的Type依赖属性,期望在MainWindow.xaml中指定Type属性值(如Feed)时,控件自动应用对应类型的样式。
现有代码示例
Style 示例(以Feed、Video、Profile为例)
<!-- ShimmerFeedStyle --> <Style x:Key="ShimmerFeedStyle" TargetType="local:Shimmer"> <Setter Property="HorizontalAlignment" Value="Center"/> <Setter Property="VerticalAlignment" Value="Center"/> <Setter Property="Fill" Value="{ThemeResource ShimmerFillColor}"/> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="local:Shimmer"> <StackPanel> <Grid x:Name="Grid1"> <Grid.RowDefinitions> <RowDefinition Height="Auto" /> <RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition Width="Auto" /> </Grid.ColumnDefinitions> <Ellipse Grid.Column="0" Grid.Row="0" Height="100" Width="100" Fill="{TemplateBinding Fill}" HorizontalAlignment="Left" /> <Rectangle x:Name="rect1" Margin="120,0,0,40" Grid.Row="0" Grid.Column="0" Height="30" Width="500" Fill="{TemplateBinding Fill}" HorizontalAlignment="Left"/> <Rectangle x:Name="rect2" Margin="120,50,0,0" Grid.Row="0" Grid.Column="0" Height="30" Width="300" Fill="{TemplateBinding Fill}" HorizontalAlignment="Left"/> <Rectangle Grid.Row="1" Grid.Column="0" Fill="{TemplateBinding Fill}" Margin="0,30,0,0" Height="200" Width="625" HorizontalAlignment="Left"/> <Rectangle Grid.Row="2" Grid.Column="0" Fill="{TemplateBinding Fill}" Margin="0,20,0,0" Height="20" Width="625" HorizontalAlignment="Left"/> <Rectangle Grid.Row="3" Grid.Column="0" Fill="{TemplateBinding Fill}" Margin="0,20,0,0" Height="20" Width="625" HorizontalAlignment="Left"/> </Grid> <Grid x:Name="Grid2"> <ContentControl> <ContentPresenter Content="{TemplateBinding Content}"/> </ContentControl> </Grid> </StackPanel> </ControlTemplate> </Setter.Value> </Setter> </Style> <!-- ShimmerVideoStyle --> <Style x:Key="ShimmerVideoStyle" TargetType="local:Shimmer"> <Setter Property="HorizontalAlignment" Value="Center"/> <Setter Property="VerticalAlignment" Value="Center"/> <Setter Property="Fill" Value="{ThemeResource ShimmerFillColor}"/> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="local:Shimmer"> <StackPanel> <Grid x:Name="Grid1"> <Grid.RowDefinitions> <RowDefinition Height="auto"/> <RowDefinition Height="auto"/> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition Width="auto"/> </Grid.ColumnDefinitions> <Rectangle Grid.Row="0" Grid.Column="0" Fill="{TemplateBinding Fill}" Margin="0,20,0,0" Height="250" Width="625" HorizontalAlignment="Left"/> <Ellipse Grid.Row="1" Grid.Column="0" Height="100" Width="100" Margin="0,40,0,0" Fill="{TemplateBinding Fill}" HorizontalAlignment="Left"/> <Rectangle Margin="130,30,0,30" Grid.Row="1" Grid.Column="0" Height="28" Width="400" Fill="{TemplateBinding Fill}" HorizontalAlignment="Left"/> <Rectangle Margin="130,80,0,0" Grid.Row="1" Grid.Column="0" Height="28" Width="400" Fill="{TemplateBinding Fill}" HorizontalAlignment="Left"/> </Grid> <Grid x:Name="Grid2"> <ContentControl> <ContentPresenter Content="{TemplateBinding Content}"/> </ContentControl> </Grid> </StackPanel> </ControlTemplate> </Setter.Value> </Setter> </Style> <!-- ShimmerProfileStyle --> <Style x:Key="ShimmerProfileStyle" TargetType="local:Shimmer"> <Setter Property="HorizontalAlignment" Value="Center"/> <Setter Property="VerticalAlignment" Value="Center"/> <Setter Property="Fill" Value="{ThemeResource ShimmerFillColor}"/> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="local:Shimmer"> <StackPanel> <Grid x:Name="Grid1"> <Grid.RowDefinitions> <RowDefinition Height="auto"/> <RowDefinition Height="auto"/> <RowDefinition Height="auto"/> <RowDefinition Height="auto"/> <RowDefinition Height="auto"/> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition Width="auto"/> </Grid.ColumnDefinitions> <Ellipse Grid.Row="0" Grid.Column="0" Height="100" Width="100" Fill="{TemplateBinding Fill}" HorizontalAlignment="Center" VerticalAlignment="Center"/> <Rectangle Grid.Row="1" Grid.Column="0" Height="30" Width="150" Margin="0,45,0,0" Fill="{TemplateBinding Fill}" HorizontalAlignment="Center"/> <Rectangle Grid.Row="2" Grid.Column="0" Height="30" Width="300" Margin="0,15,0,0" Fill="{TemplateBinding Fill}" HorizontalAlignment="Center"/> <Rectangle Grid.Row="3" Grid.Column="0" Height="25" Width="500" Margin="0,40,0,0" Fill="{TemplateBinding Fill}" HorizontalAlignment="Center"/> <Rectangle Grid.Row="4" Grid.Column="0" Height="25" Width="500" Margin="0,20,0,0" Fill="{TemplateBinding Fill}" HorizontalAlignment="Center"/> </Grid> <Grid x:Name="Grid2"> <ContentControl> <ContentPresenter Content="{TemplateBinding Content}"/> </ContentControl> </Grid> </StackPanel> </ControlTemplate> </Setter.Value> </Setter> </Style>
MainWindow.xaml 代码
<shim:Shimmer x:Name="shimmer" IsActive="True" Type="Feed"> <shim:Shimmer.Content> <Grid> <Image Height="100" Width="100" Source="D:\WinUI-3 Shimmer control\Syncfusion.Shimmer.WinUI\Shimmer\download.jfif"/> <TextBlock Text="Content is Loaded!" /> </Grid> </shim:Shimmer.Content> </shim:Shimmer>
Shimmer 类代码
public class Shimmer : Control { public Shimmer() { this.DefaultStyleKey = typeof(Shimmer); } public ShimmerType Type { get { return (ShimmerType)GetValue(TypeProperty); } set { SetValue(TypeProperty, value); } } // 使用依赖属性作为Type的后备存储,支持动画、样式、绑定等 public static readonly DependencyProperty TypeProperty = DependencyProperty.Register("Type", typeof(ShimmerType), typeof(SfShimmer), new PropertyMetadata(null, OnTypePropertyChanged)); }
解决方案
首先修正Shimmer类中的两处错误:
- 依赖属性的所有者类型应为
Shimmer,而非SfShimmer - 枚举类型的依赖属性默认值不能为
null,需设置枚举的默认值(比如ShimmerType.Feed)
修正后的Shimmer类基础代码:
public enum ShimmerType { Feed, Video, Profile // 其他枚举值... } public class Shimmer : Control { public Shimmer() { this.DefaultStyleKey = typeof(Shimmer); } public ShimmerType Type { get { return (ShimmerType)GetValue(TypeProperty); } set { SetValue(TypeProperty, value); } } public static readonly DependencyProperty TypeProperty = DependencyProperty.Register("Type", typeof(ShimmerType), typeof(Shimmer), new PropertyMetadata(ShimmerType.Feed, OnTypePropertyChanged)); private static void OnTypePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { var shimmer = d as Shimmer; shimmer?.UpdateStyle(); } }
下面提供两种可行的自动切换样式方案:
方案1:代码逻辑切换样式
在Type属性变更时,根据枚举值拼接对应的Style Key,从资源中获取并应用样式。
在Shimmer类中添加UpdateStyle方法:
private void UpdateStyle() { string styleKey = $"Shimmer{Type}Style"; if (Application.Current.Resources.TryGetValue(styleKey, out object resource) && resource is Style style) { this.Style = style; } }
- 确保所有Style都在全局资源字典中(如App.xaml),或控件所在上下文的资源字典中
方案2:XAML DataTrigger切换模板
定义一个默认的Shimmer样式,通过DataTrigger绑定Type属性,根据不同枚举值切换对应的ControlTemplate,完全通过XAML实现,无需额外代码逻辑。
步骤1:提取ControlTemplate为独立资源
<!-- 提取各类型的ControlTemplate作为全局资源 --> <ControlTemplate x:Key="ShimmerFeedTemplate" TargetType="local:Shimmer"> <!-- 原ShimmerFeedStyle中的ControlTemplate内容 --> </ControlTemplate> <ControlTemplate x:Key="ShimmerVideoTemplate" TargetType="local:Shimmer"> <!-- 原ShimmerVideoStyle中的ControlTemplate内容 --> </ControlTemplate> <ControlTemplate x:Key="ShimmerProfileTemplate" TargetType="local:Shimmer"> <!-- 原ShimmerProfileStyle中的ControlTemplate内容 --> </ControlTemplate>
步骤2:定义默认Style并添加DataTrigger
<Style TargetType="local:Shimmer"> <Setter Property="HorizontalAlignment" Value="Center"/> <Setter Property="VerticalAlignment" Value="Center"/> <Setter Property="Fill" Value="{ThemeResource ShimmerFillColor}"/> <Setter Property="Template" Value="{StaticResource ShimmerFeedTemplate}"/> <!-- 默认模板 --> <Style.Triggers> <DataTrigger Binding="{Binding Type, RelativeSource={RelativeSource Self}}" Value="Video"> <Setter Property="Template" Value="{StaticResource ShimmerVideoTemplate}"/> </DataTrigger> <DataTrigger Binding="{Binding Type, RelativeSource={RelativeSource Self}}" Value="Profile"> <Setter Property="Template" Value="{StaticResource ShimmerProfileTemplate}"/> </DataTrigger> <!-- 为其他枚举值添加对应的DataTrigger --> </Style.Triggers> </Style>
内容的提问来源于stack exchange,提问作者Budding developer
相关产品推荐
相关产品推荐

