416 字
2 分钟
[.NET/WPF] 设置按钮, 以及其他任何包含边框的控件的圆角
2023-09-02

在 WPF 中, 按钮包含一个 “边框”, 很多时候需要设置按钮的圆角, 但是按钮并没有提供一个属性用来设置边框圆角.

下面以按钮为例, 列举几种常用的设置圆角的方式.

通过附加属性#

定义一个附加属性, 然后在各个地方就能直接方便的使用了, 下面是实际使用方式:

<Button utils.BorderUtils.CornerRadius="3"/>

接下来是具体实现代码, 首先是一些工具方法:

using System.Windows.Media;

namespace System.Windows
{
    public static class CommonUtils
    {
        public static void RunOnFirstLoaded(this FrameworkElement element, EventHandler handler)
        {
            void Once(object? sender, RoutedEventArgs e)
            {
                element.Loaded -= Once;
                handler.Invoke(sender, e);
            }

            if (element.IsLoaded)
                handler.Invoke(element, EventArgs.Empty);
            else
                element.Loaded += Once;
        }

        public static TElement? GetElementFromVisualTree<TElement>(this FrameworkElement control) where TElement : FrameworkElement
        {
            if (control is TElement ele)
                return ele;

            int childrenCount = VisualTreeHelper.GetChildrenCount(control);
            for (int i = 0; i < childrenCount; i++)
            {
                DependencyObject child = VisualTreeHelper.GetChild(control, i);
                if (child is TElement eleChild)
                    return eleChild;
            }

            return null;
        }
    }
}

然后是 BorderUtils 这个类, 在其中定义 CornerRadius 附加属性:

using System;
using System.Windows.Controls;
using System.Windows.Media;

namespace System.Windows
{
    public static class BorderUtils
    {
        [AttachedPropertyBrowsableForType(typeof(FrameworkElement))]
        public static CornerRadius GetCornerRadius(DependencyObject obj)
        {
            return (CornerRadius)obj.GetValue(CornerRadiusProperty);
        }

        public static void SetCornerRadius(DependencyObject obj, CornerRadius value)
        {
            obj.SetValue(CornerRadiusProperty, value);
        }

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

        private static void CornerRadiusChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (d is not FrameworkElement ele)
                return;

            ele.RunOnFirstLoaded((s, _e) =>
            {
                if (CommonUtils.GetElementFromVisualTree<Border>(ele) is not Border border)
                    return;

                border.CornerRadius = (CornerRadius)e.NewValue;
            });
        }
    }
}

通过资源#

直接在 Button 节点下添加一个 Border 的样式资源, 然后 Button 中的 Border 就会应用这个样式.

<Button>
  <Button.Resources>
    <Style TargetType="Border">
      <Setter Property="CornerRadius" Value="3" />
    </Style>
  </Button.Resources>
</Button>

通过模板#

很麻烦的一种方式, 不推荐

<Button>
  <Button.Template>
    <ControlTemplate TargetType="{x:Type Button}" >
      <Border BorderBrush="{TemplateBinding Control.BorderBrush}" BorderThickness="1" CornerRadius="7,7,7,7">
        <Border.Background>#FFDDDDDD</Border.Background>
        <ContentPresenter Content="{TemplateBinding ContentControl.Content}" HorizontalAlignment="Center" VerticalAlignment="Center" ></ContentPresenter>
      </Border>
    </ControlTemplate>
  </Button.Template>
</Button>
[.NET/WPF] 设置按钮, 以及其他任何包含边框的控件的圆角
https://slimenull.com/posts/20230902085924/
作者
SlimeNull
发布于
2023-09-02
许可协议
CC BY-NC-SA 4.0