WPF开源控件Newbeecoder.UI自定义按钮

92 篇文章 24 订阅
31 篇文章 7 订阅
这篇博客介绍了如何在WPF中创建一个自定义的按钮控件`NbButton`,包括其样式和行为的详细设置。`NbButton`提供了如IsHitTestVisibleInChrome属性来控制非客户区的鼠标响应,以及多个依赖属性用于自定义背景、圆角、禁用时的鼠标样式等。此外,还展示了如何通过样式模板改变按钮在不同状态(如鼠标悬停、按下)下的视觉效果,并给出了实际使用代码示例。
摘要由CSDN通过智能技术生成

程序界面上的按钮多种多样,常用的就这几种:普通按钮、图标按钮、文字按钮、图片文字混合按钮。

一、固定样式的按钮

固定样式的按钮一般在临时使用时或程序的样式比较固定时才会使用,按钮整体样式不需要做大的改动。

1.1 普通按钮-扁平化风格

先看效果:

  Demo下载地址:

 WPF控件库:Newbeecoder.UIicon-default.png?t=M1L8https://share.weiyun.com/py6W1dcK

自定义按钮样式中增加几个依赖属性,IsHitTestVisibleInChrome、非客户区鼠标是否响应事件,CornerRadius、MaskBackground、DisabledCursor、NbData,NbData目前存放图片,该类型是object也可以用于其它类型。

public class NbButton : Button
    {
        #region ctor
        static NbButton()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(NbButton), new FrameworkPropertyMetadata(typeof(NbButton)));
        }

        /// <summary>
        /// 
        /// </summary>
        public NbButton()
        {
            IsHitTestVisibleInChrome = true;
        }
        #endregion

        #region prop
        /// <summary>
        /// 非客户区鼠标/触摸响应
        /// </summary>
        public bool IsHitTestVisibleInChrome
        {
            get { return WindowChrome.GetIsHitTestVisibleInChrome(this); }
            set { WindowChrome.SetIsHitTestVisibleInChrome(this, value); }
        }
        #endregion

        #region dp prop
        /// <summary>
        /// 圆角
        /// </summary>
        public CornerRadius CornerRadius
        {
            get { return (CornerRadius)GetValue(CornerRadiusProperty); }
            set { SetValue(CornerRadiusProperty, value); }
        }

        // Using a DependencyProperty as the backing store for CornerRadius.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty CornerRadiusProperty =
            DependencyProperty.Register("CornerRadius", typeof(CornerRadius), typeof(NbButton), new PropertyMetadata(new CornerRadius(0d)));

        /// <summary>
        /// 遮罩层背景色(用于鼠标移入和点击按钮时背景色变化)
        /// </summary>
        public Brush MaskBackground
        {
            get { return (Brush)GetValue(MaskBackgroundProperty); }
            set { SetValue(MaskBackgroundProperty, value); }
        }

        // Using a DependencyProperty as the backing store for MaskBackground.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty MaskBackgroundProperty =
            DependencyProperty.Register("MaskBackground", typeof(Brush), typeof(NbButton), new PropertyMetadata(Brushes.Transparent));


        /// <summary>
        /// 禁用时鼠标的样式
        /// </summary>
        public Cursor DisabledCursor
        {
            get { return (Cursor)GetValue(DisabledCursorProperty); }
            set { SetValue(DisabledCursorProperty, value); }
        }

        // Using a DependencyProperty as the backing store for DisabledCursor.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty DisabledCursorProperty =
            DependencyProperty.Register("DisabledCursor", typeof(Cursor), typeof(NbButton), new PropertyMetadata(Cursors.No, (d, e) =>
            {
                var ele = (UIElement)d;
                ele.AddAdorner(new DisabledAdorner(ele, (Cursor)e.NewValue));
            }));

        /// <summary>
        /// 备用数据
        /// </summary>
        public object NbData
        {
            get { return (object)GetValue(NbDataProperty); }
            set { SetValue(NbDataProperty, value); }
        }

        // Using a DependencyProperty as the backing store for NbData.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty NbDataProperty =
            DependencyProperty.Register("NbData", typeof(object), typeof(NbButton), new PropertyMetadata(null));

        #endregion

        #region override
        /// <summary>
        /// 
        /// </summary>
        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();
            this.AddAdorner(new DisabledAdorner(this, DisabledCursor));
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="e"></param>
        protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
        {
            base.OnPropertyChanged(e);
            NbAnimationHelper.SetOnPropertyChangedAnimation(this, e);
        }
        #endregion
    }
在NbButton自定义样式代码如下:
<Style TargetType="{x:Type local:NbButton}">
        <Setter Property="DisabledCursor" Value="No"/>
        <Setter Property="MaskBackground" Value="Transparent"/>        
        <Setter Property="FocusVisualStyle" Value="{StaticResource FocusVisualStyle}"/>
        <Setter Property="Background" Value="{Binding Path=Color.Brush_Brand1, Source={x:Static local:NbTheme.Current}}"/>
        <Setter Property="Foreground" Value="{Binding Path=Color.Brush_Base1, Source={x:Static local:NbTheme.Current}}"/>
        <Setter Property="MinWidth" Value="{Binding Path=Size.ButtonWidth, Source={x:Static local:NbTheme.Current}}"/>
        <Setter Property="Height" Value="{Binding Path=Size.ButtonHeight, Source={x:Static local:NbTheme.Current}}"/>
        <Setter Property="CornerRadius" Value="{Binding Path=Size.CornerRadius, Source={x:Static local:NbTheme.Current}}"/>
        <Setter Property="BorderThickness" Value="0"/>
        <Setter Property="HorizontalContentAlignment" Value="Center"/>
        <Setter Property="VerticalContentAlignment" Value="Center"/>
        <Setter Property="Padding" Value="6,0"/>
        <Setter Property="Cursor" Value="Hand"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type local:NbButton}">
                    <Border x:Name="border"
                            BorderBrush="{TemplateBinding BorderBrush}" 
                            BorderThickness="{TemplateBinding BorderThickness}" 
                            Background="{TemplateBinding Background}" 
                            CornerRadius="{TemplateBinding CornerRadius}"
                            Effect="{TemplateBinding Effect}"
                            SnapsToDevicePixels="True">
                        <Border x:Name="innerBorder" 
                                Background="{TemplateBinding MaskBackground}" 
                                CornerRadius="{TemplateBinding CornerRadius}" 
                                SnapsToDevicePixels="True">
                            <ContentPresenter x:Name="contentPresenter" 
                                              ContentTemplate="{TemplateBinding ContentTemplate}" 
                                              Content="{TemplateBinding Content}" 
                                              ContentStringFormat="{TemplateBinding ContentStringFormat}" 
                                              Focusable="False" 
                                              HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" 
                                              Margin="{TemplateBinding Padding}" 
                                              RecognizesAccessKey="True" 
                                              SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" 
                                              VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
                        </Border>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
        <Style.Triggers>
            <Trigger Property="IsEnabled" Value="False">
                <Setter Property="Opacity" Value="0.6"/>
            </Trigger>
            <Trigger Property="IsMouseOver" Value="True">
                <Setter Property="MaskBackground" Value="{Binding Path=Color.Brush_Base1_OP3, Source={x:Static local:NbTheme.Current}}"/>
            </Trigger>
            <Trigger Property="IsPressed" Value="True">
                <Setter Property="MaskBackground" Value="{Binding Path=Color.Brush_Base2_OP1, Source={x:Static local:NbTheme.Current}}"/>
            </Trigger>
        </Style.Triggers>
    </Style>

设置禁用时鼠标的样式

<Setter Property="DisabledCursor" Value="No"/>

设置遮罩层背景色透明,其实就是不设置遮罩层背景色

<Setter Property="MaskBackground" Value="Transparent"/> 

设置焦点样式:

<Setter Property="FocusVisualStyle" Value="{StaticResource FocusVisualStyle}"/>

设置外层边框样式,包括边框颜色,边框厚度,背景色,圆角,阴影等属性。

 <Border x:Name="border"
                            BorderBrush="{TemplateBinding BorderBrush}" 
                            BorderThickness="{TemplateBinding BorderThickness}" 
                            Background="{TemplateBinding Background}" 
                            CornerRadius="{TemplateBinding CornerRadius}"
                            Effect="{TemplateBinding Effect}"
                            SnapsToDevicePixels="True">

内层边框各种属性都差不多,只是把遮罩层背景色变成背景色

Background="{TemplateBinding MaskBackground}"

当鼠标IsMouseOver和IsPressed时,分别改变遮罩层颜色。

<Trigger Property="IsMouseOver" Value="True">
                <Setter Property="MaskBackground" Value="{Binding Path=Color.Brush_Base1_OP3, Source={x:Static local:NbTheme.Current}}"/>
            </Trigger>
            <Trigger Property="IsPressed" Value="True">
                <Setter Property="MaskBackground" Value="{Binding Path=Color.Brush_Base2_OP1, Source={x:Static local:NbTheme.Current}}"/>
            </Trigger>

最后使用自定义按钮代码如下:

  <NbButton Style="{DynamicResource NormalButtonStyle}" Margin="5" Content="一般按钮"/>
                    <NbButton Style="{DynamicResource DefaultButtonStyle}" Margin="5" Content="默认按钮"/>
                    <NbButton Style="{DynamicResource SuccessButtonStyle}" Margin="5" Content="成功按钮"/>
                    <NbButton Style="{DynamicResource InfoButtonStyle}" Margin="5" Content="信息按钮"/>
                    <NbButton Style="{DynamicResource WarningButtonStyle}" Margin="5" Content="警告按钮"/>
                    <NbButton Style="{DynamicResource DangerButtonStyle}" Margin="5" Content="危险按钮"/>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值