为了让我们WPF控件样式能够重复利用和解耦,我们可以通过附加属性来给我们的样式添加扩展。今天就带大家看看如果使用扩展属性来定制样式!

假设一种应用场景:我们需要做一个状态按钮控件,但鼠标按下去的时候,呈现一种图片,弹起来的时候呈现一种图片。所以我们给他加两个附加属性:PressedIcon,ReleasedIcon.

先定义两个附加属性:

    public class UIHelper
    {
        /// <summary>
        /// 默认图标附加属性
        /// </summary>
        public readonly static DependencyProperty PressedIconProperty = DependencyProperty.RegisterAttached("PressedIcon", typeof(ImageSource), typeof(UIHelper));

        /// <summary>
        /// 
        /// </summary>
        /// <param name="frameworkElement"></param>
        /// <returns></returns>
        public static ImageSource GetPressedIcon(FrameworkElement frameworkElement)
        {
            return (ImageSource)frameworkElement.GetValue(PressedIconProperty);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="frameworkElement"></param>
        /// <param name="value"></param>
        public static void SetPressedIcon(FrameworkElement frameworkElement, ImageSource value)
        {
            frameworkElement.SetValue(PressedIconProperty, value);
        }

        public readonly static DependencyProperty ReleasedIconProperty = DependencyProperty.RegisterAttached("ReleasedIcon", typeof(ImageSource), typeof(UIHelper));

        /// <summary>
        /// 
        /// </summary>
        /// <param name="frameworkElement"></param>
        /// <returns></returns>
        public static ImageSource GetReleasedIcon(FrameworkElement frameworkElement)
        {
            return (ImageSource)frameworkElement.GetValue(ReleasedIconProperty);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="frameworkElement"></param>
        /// <param name="value"></param>
        public static void SetReleasedIcon(FrameworkElement frameworkElement, ImageSource value)
        {
            frameworkElement.SetValue(ReleasedIconProperty, value);
        }
    

附加属性定义好后,我们只需要在Xaml代码中引用他们,并给予赋值。

RadioButton示例样式:

    <Style x:Key="RadioButtonStyle" TargetType="{x:Type RadioButton}">
        <Setter Property="FocusVisualStyle" Value="{x:Null}"/>
        <Setter Property="Background" Value="Transparent"/>
        <Setter Property="BorderBrush" Value="Transparent"/>
        <Setter Property="Foreground" Value="Transparent"/>
        <Setter Property="BorderThickness" Value="0"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type RadioButton}">
                    <Grid x:Name="markGrid" Background="Transparent">
                        <Ellipse x:Name="optionMark" Fill="Transparent" Width="{Binding ActualHeight, RelativeSource={RelativeSource Mode=Self}}"/>
                        <Image x:Name="img" Margin="{Binding ActualHeight,RelativeSource={RelativeSource Mode=TemplatedParent},Converter={StaticResource EllipseMarginConverter}}" Source="{Binding Path=(helper:UIHelper.ReleasedIcon),RelativeSource={ RelativeSource Mode=TemplatedParent}}"/>
                    </Grid>
                    <ControlTemplate.Triggers>
                        <Trigger Property="IsMouseOver" Value="true">
                            <Setter Property="Fill" TargetName="optionMark" Value="{StaticResource RadioButton.MouseOver.Glyph}"/>
                        </Trigger>
                        <Trigger Property="IsPressed" Value="true">
                            <Setter Property="Fill" TargetName="optionMark" Value="{StaticResource RadioButton.Pressed.Glyph}"/>
                        </Trigger>
                        <Trigger Property="IsChecked" Value="true">
                            <Setter Property="Source" TargetName="img" Value="{Binding Path=(helper:UIHelper.PressedIcon),RelativeSource={RelativeSource Mode=TemplatedParent}}"/>
                            <Setter Property="Fill" Value="{StaticResource RadioButton.MouseOver.Glyph}" TargetName="optionMark"/>
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

在我们控件中使用他们:


<UserControl x:Class="Hilk.InkMarker.UserControl1"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:helper="clr-namespace:test.XamlUI"
             mc:Ignorable="d" 
             d:DesignHeight="450" d:DesignWidth="800">

    <!--此处省略静态资源字典的引入,包含:PressedIcon和ReleasedIcon-->

    <Grid>
        <RadioButton Style="{StaticResource  RadioButtonStyle}" helper:UIHelper.PressedIcon="{StaticResource PressedIcon}" helper:UIHelper.ReleasedIcon="{StaticResource ReleasedIcon}"/>
    </Grid>
</UserControl> 

这样就可以通过附加属性,给我们的控件定制化样式了。


本文会经常更新,请阅读原文: https://huchengv5.gitee.io//post/WPF%E9%80%9A%E8%BF%87%E9%99%84%E5%8A%A0%E5%B1%9E%E6%80%A7%E7%BB%99%E6%8E%A7%E4%BB%B6%E4%BF%AE%E6%94%B9%E6%A0%B7%E5%BC%8F.html ,以避免陈旧错误知识的误导,同时有更好的阅读体验。

知识共享许可协议 本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。欢迎转载、使用、重新发布,但务必保留文章署名胡承(包含链接: https://huchengv5.gitee.io/ ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请 与我联系