WPF自定义控件 按钮 (二)

上一篇介绍了如何使用阿里巴巴图标和制作带图标的按钮,前面的做法只是简单介绍,要真正能够运用到项目中,还有一段路要走,这里继续介绍如何完善之前的自定义按钮,使之能够合理的运用到以后的项目中。

就拿上一个测试代码来说:

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApplication1"
        xmlns:controls="clr-namespace:WpfCustomControlLibrary.Controls;assembly=WpfCustomControlLibrary"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition></RowDefinition>
            <RowDefinition></RowDefinition>
            <RowDefinition></RowDefinition>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition></ColumnDefinition>
            <ColumnDefinition></ColumnDefinition>
        </Grid.ColumnDefinitions>
        <Button Grid.Row="0" Grid.Column="0" Content="Default Button" Width="100" Height="50"></Button>
        <controls:MyButton1  Grid.Row="0" Grid.Column="1" Width="100" Height="50" Content="MyButton1" Background="Orange" />
        <TextBlock Grid.Row="1" Grid.Column="0" Text="&#xe6f0;" FontSize="50" Foreground="Green" Style="{StaticResource MyIcon}" ></TextBlock>

    </Grid>
</Window>


一个真正的项目中,可能会需要几十种按钮图标,如果遇到这样的情况,在上面的代码中,只能改改 Content 这些现成的属性值,是没法在前台直接去改掉微信图标的;有人想到可以多建一些button模板,可以是可以的,就是太不人性化了;


接下来介绍一种方式,能够在前台设置各种Icon,就是使用 附加属性:

1.修改 MyButton1.cs 代码为:

    public class MyButton1 : Button
    {
        static MyButton1()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(MyButton1), new FrameworkPropertyMetadata(typeof(MyButton1)));
        }

        public static readonly DependencyProperty MyIconProperty =
    DependencyProperty.Register("MyIcon", typeof(string), typeof(MyButton1), new PropertyMetadata("\ue6f0"));
        /// <summary>
        /// 按钮字体图标编码
        /// </summary>
        public string MyIcon
        {
            get { return (string)GetValue(MyIconProperty); }
            set { SetValue(MyIconProperty, value); }
        }
    }

2.修改 MyButton1.xaml 样式代码为:

扫描二维码关注公众号,回复: 1532736 查看本文章
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:local="clr-namespace:WpfCustomControlLibrary.Controls">

    <ResourceDictionary.MergedDictionaries>
        <ResourceDictionary Source="pack://application:,,,/WpfCustomControlLibrary;component/Controls/MyIcon.xaml" />
    </ResourceDictionary.MergedDictionaries>


    <ControlTemplate x:Key="MyButton1_Template" TargetType="{x:Type local:MyButton1}">
        <Border x:Name="border" Background="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path= Background}" 
                                    Height="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path=Height}" 
                                    CornerRadius="2" 
                                    BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}"
                                    Width="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path=Width}">
            <!--Icon/Text-->
            <StackPanel Orientation="Horizontal" VerticalAlignment="Center" 
                        Margin="{TemplateBinding Padding}"
                        HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}">
                <TextBlock x:Name="icon"  Margin="3" 
                           RenderTransformOrigin="0.5,0.5" Style="{StaticResource MyIcon}"
                           Text="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path= MyIcon}"
                           FontSize="30" 
                           Foreground="Green">
                    <TextBlock.RenderTransform>
                        <RotateTransform x:Name="transIcon" Angle="0"/>
                    </TextBlock.RenderTransform>
                </TextBlock>

                <TextBlock VerticalAlignment="Center"  x:Name="txt" 
                           TextDecorations="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path=ContentDecorations}" 
                                               Text="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path=Content}" />
            </StackPanel>
        </Border>
    </ControlTemplate>

    <Style TargetType="{x:Type local:MyButton1}">
        <Setter Property="Template" Value="{StaticResource MyButton1_Template}"/>
    </Style>
    
</ResourceDictionary>

实际上就改了一行代码:

Text="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path= MyIcon}"

3.修改测试程序前端代码:

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApplication1"
        xmlns:controls="clr-namespace:WpfCustomControlLibrary.Controls;assembly=WpfCustomControlLibrary"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition></RowDefinition>
            <RowDefinition></RowDefinition>
            <RowDefinition></RowDefinition>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition></ColumnDefinition>
            <ColumnDefinition></ColumnDefinition>
        </Grid.ColumnDefinitions>
        <Button Grid.Row="0" Grid.Column="0" Content="Default Button" Width="100" Height="50"></Button>
        <controls:MyButton1  Grid.Row="0" Grid.Column="1" Width="100" Height="50" Content="MyButton1" MyIcon="&#xe7d6;" Background="Orange" />
        <TextBlock Grid.Row="1" Grid.Column="0" Text="&#xe6f0;" FontSize="50" Foreground="Green" Style="{StaticResource MyIcon}" ></TextBlock>
        <controls:MyButton1  Grid.Row="1" Grid.Column="1" Width="100" Height="50" Content="MyButton1" MyIcon="&#xe6ea;" Background="Orange" />

    </Grid>
</Window>

这样就能在前台修改任意的icon了:



当然,仅仅能够修改icon还是远远不够的,;还有icon大小,颜色,边距等都要能够在前台自由设置,所以需要添加的附加依赖属性还有很多,这就要看具体要求了,这里继续为它添加几个附加属性,包括:icon大小,边距 这2个;(颜色属性一般可以直接使用Button自带的 Foreground 即可)

1.修改 MyButton1.cs 代码:

public class MyButton1 : Button
    {
        static MyButton1()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(MyButton1), new FrameworkPropertyMetadata(typeof(MyButton1)));
        }

        public static readonly DependencyProperty MyIconProperty =
    DependencyProperty.Register("MyIcon", typeof(string), typeof(MyButton1), new PropertyMetadata("\ue6f0"));
        /// <summary>
        /// 按钮字体图标编码
        /// </summary>
        public string MyIcon
        {
            get { return (string)GetValue(MyIconProperty); }
            set { SetValue(MyIconProperty, value); }
        }

        public static readonly DependencyProperty MyIconSizeProperty =
           DependencyProperty.Register("MyIconSize", typeof(int), typeof(MyButton1), new PropertyMetadata(20));
        /// <summary>
        /// 按钮字体图标大小
        /// </summary>
        public int MyIconSize
        {
            get { return (int)GetValue(MyIconSizeProperty); }
            set { SetValue(MyIconSizeProperty, value); }
        }

        public static readonly DependencyProperty MyIconMarginProperty = DependencyProperty.Register(
            "MyIconMargin", typeof(Thickness), typeof(MyButton1), new PropertyMetadata(new Thickness(0, 1, 3, 1)));
        /// <summary>
        /// 字体图标间距
        /// </summary>
        public Thickness MyIconMargin
        {
            get { return (Thickness)GetValue(MyIconMarginProperty); }
            set { SetValue(MyIconMarginProperty, value); }
        }
    }

2.修改 MyButton1.xaml 代码:

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:local="clr-namespace:WpfCustomControlLibrary.Controls">

    <ResourceDictionary.MergedDictionaries>
        <ResourceDictionary Source="pack://application:,,,/WpfCustomControlLibrary;component/Controls/MyIcon.xaml" />
    </ResourceDictionary.MergedDictionaries>


    <ControlTemplate x:Key="MyButton1_Template" TargetType="{x:Type local:MyButton1}">
        <Border x:Name="border" Background="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path= Background}" 
                                    Height="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path=Height}" 
                                    CornerRadius="2" 
                                    BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}"
                                    Width="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path=Width}">
            <!--Icon/Text-->
            <StackPanel Orientation="Horizontal" VerticalAlignment="Center" 
                        Margin="{TemplateBinding Padding}"
                        HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}">
                <TextBlock x:Name="icon"  
                           Margin="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path=MyIconMargin}" 
                           FontSize="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path= MyIconSize}" 
                           Foreground="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path= Foreground}"
                           RenderTransformOrigin="0.5,0.5" Style="{StaticResource MyIcon}"
                           Text="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path= MyIcon}"
                          >
                    <TextBlock.RenderTransform>
                        <RotateTransform x:Name="transIcon" Angle="0"/>
                    </TextBlock.RenderTransform>
                </TextBlock>

                <TextBlock VerticalAlignment="Center"  x:Name="txt" 
                           TextDecorations="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path=ContentDecorations}" 
                                               Text="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path=Content}" />
            </StackPanel>
        </Border>
    </ControlTemplate>

    <Style TargetType="{x:Type local:MyButton1}">
        <Setter Property="Template" Value="{StaticResource MyButton1_Template}"/>
    </Style>
    
</ResourceDictionary>

3.测试代码:

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApplication1"
        xmlns:controls="clr-namespace:WpfCustomControlLibrary.Controls;assembly=WpfCustomControlLibrary"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition></RowDefinition>
            <RowDefinition></RowDefinition>
            <RowDefinition></RowDefinition>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition></ColumnDefinition>
            <ColumnDefinition></ColumnDefinition>
        </Grid.ColumnDefinitions>
        <Button Grid.Row="0" Grid.Column="0" Content="Default Button" Width="100" Height="50"></Button>
        <controls:MyButton1  Grid.Row="0" Grid.Column="1" Width="100" Height="50" Content="MyButton1" MyIcon="&#xe7d6;" MyIconMargin="3" MyIconSize="25" Foreground="Green"  Background="Orange" />
        <TextBlock Grid.Row="1" Grid.Column="0" Text="&#xe6f0;" FontSize="50" Foreground="Green" Style="{StaticResource MyIcon}" ></TextBlock>
        <controls:MyButton1  Grid.Row="1" Grid.Column="1" Width="100" Height="50" Content="MyButton1" MyIcon="&#xe6ea;" MyIconMargin="4" MyIconSize="30" Foreground="White" Background="Orange" />

    </Grid>
</Window>

效果如下:



有了这两个附加属性之后,还可以结合 WPF自定义控件 按钮 (一)中的圆形按钮,做成带图标的圆形按钮,只需要:

1)在 MyButton1.xaml 中新增一个 key 为 RoundButton 的 Style :

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:local="clr-namespace:WpfCustomControlLibrary.Controls">

    <ResourceDictionary.MergedDictionaries>
        <ResourceDictionary Source="pack://application:,,,/WpfCustomControlLibrary;component/Controls/MyIcon.xaml" />
    </ResourceDictionary.MergedDictionaries>


    <ControlTemplate x:Key="MyButton1_Template" TargetType="{x:Type local:MyButton1}">
        <Border x:Name="border" Background="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path= Background}" 
                                    Height="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path=Height}" 
                                    CornerRadius="2" 
                                    BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}"
                                    Width="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path=Width}">
            <!--Icon/Text-->
            <StackPanel Orientation="Horizontal" VerticalAlignment="Center" 
                        Margin="{TemplateBinding Padding}"
                        HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}">
                <TextBlock x:Name="icon"  
                           Margin="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path=MyIconMargin}" 
                           FontSize="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path= MyIconSize}" 
                           Foreground="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path= Foreground}"
                           RenderTransformOrigin="0.5,0.5" Style="{StaticResource MyIcon}"
                           Text="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path= MyIcon}"
                          >
                    <TextBlock.RenderTransform>
                        <RotateTransform x:Name="transIcon" Angle="0"/>
                    </TextBlock.RenderTransform>
                </TextBlock>

                <TextBlock VerticalAlignment="Center"  x:Name="txt" 
                           TextDecorations="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path=ContentDecorations}" 
                                               Text="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path=Content}" />
            </StackPanel>
        </Border>
    </ControlTemplate>

    <ControlTemplate x:Key="MyButton1_RountTemplate" TargetType="{x:Type local:MyButton1}">
        <Grid>
            <VisualStateManager.VisualStateGroups>
                <VisualStateGroup x:Name="CommonStates">
                    <VisualStateGroup.Transitions>
                        <VisualTransition From="Normal" GeneratedDuration="0:0:0.3" To="MouseOver"/>
                        <VisualTransition From="MouseOver" GeneratedDuration="0:0:0.3" To="Normal"/>
                        <VisualTransition From="Pressed" GeneratedDuration="0:0:0.2" To="Normal"/>
                    </VisualStateGroup.Transitions>
                    <VisualState x:Name="Normal"/>
                    <VisualState x:Name="MouseOver">
                        <Storyboard>
                            <ColorAnimationUsingKeyFrames Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[1].(GradientStop.Color)" Storyboard.TargetName="ellipse">
                                <EasingColorKeyFrame KeyTime="0" Value="#FFEFE9F0"/>
                            </ColorAnimationUsingKeyFrames>
                        </Storyboard>
                    </VisualState>
                    <VisualState x:Name="Pressed">
                        <Storyboard>
                            <ColorAnimationUsingKeyFrames Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[1].(GradientStop.Color)" Storyboard.TargetName="ellipse">
                                <EasingColorKeyFrame KeyTime="0" Value="#FF650A6E"/>
                            </ColorAnimationUsingKeyFrames>
                        </Storyboard>
                    </VisualState>
                    <VisualState x:Name="Disabled"/>
                </VisualStateGroup>
            </VisualStateManager.VisualStateGroups>
            <Ellipse x:Name="ellipse" Stroke="Black">
                <Ellipse.Fill>
                    <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                        <GradientStop Color="Black" Offset="0"/>
                        <GradientStop Color="#FFF376FF" Offset="0.566"/>
                    </LinearGradientBrush>
                </Ellipse.Fill>
            </Ellipse>
            <!--Icon/Text-->
            <Canvas VerticalAlignment="Center" 
                        Margin="{TemplateBinding Padding}"
                        HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}">
                <TextBlock x:Name="icon"  
                           Margin="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path=MyIconMargin}" 
                           FontSize="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path= MyIconSize}" 
                           Foreground="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path= Foreground}"
                           RenderTransformOrigin="0.5,0.5" Style="{StaticResource MyIcon}"
                           Text="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path= MyIcon}"
                          >
                    <TextBlock.RenderTransform>
                        <RotateTransform x:Name="transIcon" Angle="0"/>
                    </TextBlock.RenderTransform>
                </TextBlock>

                <TextBlock VerticalAlignment="Center"  x:Name="txt" 
                           TextDecorations="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path=ContentDecorations}" 
                                               Text="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path=Content}" />
            </Canvas>
        </Grid>
        <ControlTemplate.Triggers>
            <Trigger Property="IsFocused" Value="True"/>
            <Trigger Property="IsDefaulted" Value="True"/>
            <Trigger Property="IsMouseOver" Value="True"/>
            <Trigger Property="IsPressed" Value="True"/>
            <Trigger Property="IsEnabled" Value="False"/>
        </ControlTemplate.Triggers>
    </ControlTemplate>

    <Style TargetType="{x:Type local:MyButton1}">
        <Setter Property="Template" Value="{StaticResource MyButton1_Template}"/>
    </Style>

    <Style x:Key="RoundButton" TargetType="{x:Type local:MyButton1}">
        <Setter Property="Template" Value="{StaticResource MyButton1_RountTemplate}"/>
    </Style>

</ResourceDictionary>

2.在测试项目 App.xaml 中增加 MyButton1.xaml 的引用:

<Application x:Class="WpfApplication1.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:local="clr-namespace:WpfApplication1"
             StartupUri="MainWindow.xaml">
    <Application.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="pack://application:,,,/WpfCustomControlLibrary;component/Controls/MyIcon.xaml"/>
                <ResourceDictionary Source="pack://application:,,,/WpfCustomControlLibrary;component/Controls/MyButton1.xaml"/>
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Application.Resources>

</Application>

3.修改测试代码:

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApplication1"
        xmlns:controls="clr-namespace:WpfCustomControlLibrary.Controls;assembly=WpfCustomControlLibrary"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition></RowDefinition>
            <RowDefinition></RowDefinition>
            <RowDefinition></RowDefinition>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition></ColumnDefinition>
            <ColumnDefinition></ColumnDefinition>
        </Grid.ColumnDefinitions>
        <Button Grid.Row="0" Grid.Column="0" Content="Default Button" Width="100" Height="50"></Button>
        <controls:MyButton1  Grid.Row="0" Grid.Column="1" Width="100" Height="50" Content="MyButton1" MyIcon="&#xe7d6;" MyIconMargin="3" MyIconSize="25" Foreground="Green"  Background="Orange" />
        <TextBlock Grid.Row="1" Grid.Column="0" Text="&#xe6f0;" FontSize="50" Foreground="Green" Style="{StaticResource MyIcon}" ></TextBlock>
        <controls:MyButton1  Grid.Row="1" Grid.Column="1" Width="100" Height="50" Content="MyButton1" MyIcon="&#xe6ea;" MyIconMargin="4" MyIconSize="30" Foreground="White" Background="Orange" />
        <controls:MyButton1  Grid.Row="2" Grid.Column="0" Style="{StaticResource RoundButton}" Width="80" MyIcon="&#xe6f0;" Height="80" MyIconMargin="25,-15,0,0" MyIconSize="30" Foreground="White"  />

    </Grid>
</Window>


效果如下:


以上仅仅介绍了附加属性+样式模板的使用,鼠标经过+鼠标点击等效果还没有做,下一篇介绍如何制作鼠标经过+点击效果动画。

猜你喜欢

转载自blog.csdn.net/sudazf/article/details/78029816