在按钮模板中设置圆角半径

58

我希望有一个按钮没有定义CornerRadius,而另外两个按钮有定义。如何实现?

<Style TargetType="Button" x:Key="TabButton">
    <Setter Property="Background" Value="White" />
    <Setter Property="TextBlock.TextAlignment" Value="Center" />
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="Button">
                <Border CornerRadius="0" Background="White" BorderBrush="#ccc" BorderThickness="0,1,1,0" >
                    <ContentPresenter x:Name="contentPresenter" ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
                </Border>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

<Style TargetType="Button" x:Key="TabButtonFirst" BasedOn="{StaticResource TabButton}">
    <Setter Property="CornerRadius" Value="3,0,0,0" />
</Style>

<Style TargetType="Button" x:Key="TabButtonLast" BasedOn="{StaticResource TabButton}">
    <Setter Property="CornerRadius" Value="0,0,0,3" />
</Style>

2
按钮没有 CornerRadius 属性。在 Border 控件的 ControlTemplate 中设置它。 - Nitesh
4
为实现你正在进行的操作,你需要为按钮准备两种样式,或者创建一个自定义按钮,通过 DependencyProperty 实现 CornerRadius,并将其与 ControlTemplate 中 Border 的 CornerRadius 进行绑定。 - Nitesh
8个回答

65

您并不局限于正在进行模板化的控件的依赖属性。在这种情况下,虽然 Button 没有 CornerRadius 属性,但 Border 有,因此您可以使用 Border.CornerRadius

<Style TargetType="Button" x:Key="TabButton">
    <Setter Property="Background" Value="White" />
    <Setter Property="TextBlock.TextAlignment" Value="Center" />
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="Button">
                <Border CornerRadius="{TemplateBinding Border.CornerRadius}" 
                        Background="White" BorderBrush="#ccc" 
                        BorderThickness="0,1,1,0" >
                    <ContentPresenter x:Name="contentPresenter" 
                                      ContentTemplate="{TemplateBinding ContentTemplate}" 
                                      Content="{TemplateBinding Content}" 
                                      HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                                      Margin="{TemplateBinding Padding}" 
                                      VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
                </Border>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

<Style TargetType="Button" x:Key="TabButtonFirst" BasedOn="{StaticResource TabButton}">
    <Setter Property="Border.CornerRadius" Value="3,0,0,0" />
</Style>

<Style TargetType="Button" x:Key="TabButtonLast" BasedOn="{StaticResource TabButton}">
    <Setter Property="Border.CornerRadius" Value="0,0,0,3" />
</Style>
使用这种方法,您不再需要维护多个控件模板的副本。

惊人的答案! - mattyb
4
我知道我们不喜欢+1评论,但这是大多数人在遇到导致他们提出此问题的情况时应该寻找的真正答案。 - MojoFilter
@Pieter Witvoet:我该如何绑定 CornerRadius 的值?因为按钮没有这个属性。 - GreenEyedAndy
@GreenEyedAndy:绑定到附加属性需要一个静态的SetPropertyName方法。对于CornerRadius,没有这样的方法(它不是设计为用作附加属性),但您可以提供自己的方法或创建自己的附加属性。 - Pieter Witvoet
@Pieter Witvoet:但是那样我必须子类化按钮,对吗? - GreenEyedAndy
1
@GreenEyedAndy:不,那个Set方法可以在任何类中找到。例如,如果你有一个名为MyClass的类,其中包含一个public static void SetMyProperty(DependencyObject o, CornerRadius value)方法,那么你可以在你的XAML按钮中添加local:MyClass.MyProperty="{Binding ...}"。让该方法调用o.SetValue(Border.CornerRadiusProperty, value),然后你就完成了。 - Pieter Witvoet

53

只需像这样创建一个新按钮:

<!--Button-->
            <Button  
               Name="myButton"
               Content="OK"
               FontFamily="Century Gothic"
               Foreground="white"
               Background="CornflowerBlue"
               BorderThickness="0"
               Padding="10"
               Margin="10,5">

                <Button.Resources>
                    <Style TargetType="{x:Type Border}">
                        <Setter Property="CornerRadius" Value="7"/>
                    </Style>
                </Button.Resources>

            </Button>

3
简洁明了的回答,如果你想让一个按钮拥有自己的属性,那么它非常完美。 - Andrea Antonangeli
1
我能够使用这个例子,并将其转化为一种风格,这很棒,因为被接受的答案会破坏所有默认按钮行为。 - John
1
@Chandraprakash 给出了一个很好的答案,适用于许多情况,但实际上并不像看起来那么干净。它实际上不仅覆盖了按钮中边框的样式,还覆盖了可能放置在按钮内容中的所有边框的样式。 - 0xBADF00D
2
@0xBADF00D 对于我的使用情况来说,这是我见过的最干净的代码,而且完美地运行。因为我还在 window.resources 上使用它,所以无论是其他控件中的按钮还是其他控件,这个边框都会应用到 WPF 表单中的所有控件上。 - Chandraprakash

39

正如Nitesh所说,您在Button上没有CornerRadius属性,它是Border的属性,就像您在第一个样式中显示的那样,只需复制您的第一个样式并更改CornerRadius,然后将其分配给相应Button的样式。

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Window.Resources>
        <Style TargetType="Button" x:Key="TabButton">
            <Setter Property="Background" Value="White" />
            <Setter Property="TextBlock.TextAlignment" Value="Center" />
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="Button">
                        <Border CornerRadius="0" Background="White" BorderBrush="#ccc" BorderThickness="0,1,1,0" >
                            <ContentPresenter x:Name="contentPresenter" ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
                        </Border>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
        <Style TargetType="Button" x:Key="TabButtonFirst">
            <Setter Property="Background" Value="White" />
            <Setter Property="TextBlock.TextAlignment" Value="Center" />
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="Button">
                        <Border CornerRadius="3,0,0,0" Background="White" BorderBrush="#ccc" BorderThickness="0,1,1,0" >
                            <ContentPresenter x:Name="contentPresenter" ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
                        </Border>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
         </Style>
         <Style TargetType="Button" x:Key="TabButtonLast">
            <Setter Property="Background" Value="White" />
            <Setter Property="TextBlock.TextAlignment" Value="Center" />
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="Button">
                        <Border CornerRadius="0,0,0,3" Background="White" BorderBrush="#ccc" BorderThickness="0,1,1,0" >
                            <ContentPresenter x:Name="contentPresenter" ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
                        </Border>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
      </Window.Resources>
        <Grid Background="Black">
        <Button Style="{StaticResource TabButton}" Content="Button" Height="23" HorizontalAlignment="Left" Margin="12,72,0,0" Name="button1" VerticalAlignment="Top" Width="75" />
        <Button Style="{StaticResource TabButtonFirst}" Content="Button" Height="23" HorizontalAlignment="Left" Margin="10,43,0,0" Name="button2" VerticalAlignment="Top" Width="75" />
        <Button Style="{StaticResource TabButtonLast}" Content="Button" Height="23" HorizontalAlignment="Left" Margin="12,101,0,0" Name="button3" VerticalAlignment="Top" Width="75" />
    </Grid>
</Window>

在这里输入图片描述


2
功能上运行良好,但按钮失去了其默认样式,即“OnMouseOver”、“OnMouseClick”事件不会改变按钮的视觉状态。 - monstr
2
每当我有两个模板只有一个微小的更改时,我就会遇到这个问题。这种重复的代码真的让我很烦恼。一定有更好的方法。 - Jordan
5
@Jordan:有的,看我的回答。 :) - Pieter Witvoet
3
虽然这样做可以起作用,但它并不遵循“不重复原则(DRY)”。对于任何不是微不足道的样式,这种方法很快就会变得难以管理。 - Josh Noe
如果我想要一个圆形按钮会发生什么?我必须将CornerRadius设置为至少按钮大小的一半。如何确保按钮不会变得比角半径更大? - El Mac
@ElMac 我可能会看一下这个SO问题和答案 - Mark Hall

17

您可以使用 Style.Resources 并将其定位到边框,而不是使用 ControlTemplate

<Style TargetType="Button" x:Key="TabButton">
  <Setter Property="Background" Value="White" />
  <Setter Property="TextBlock.TextAlignment" Value="Center" />
  <Style.Resources>
    <Style TargetType="Border">
      <Setter Property="CornerRadius" Value="3,0,0,0" />
    </Style>
  </Style.Resources>
</Style>

5

您可以使用附加属性来设置按钮和文本框的边框半径。

为附加属性创建类。

public class CornerRadiusSetter
{
    public static CornerRadius GetCornerRadius(DependencyObject obj) => (CornerRadius)obj.GetValue(CornerRadiusProperty);

    public static void SetCornerRadius(DependencyObject obj, CornerRadius value) => obj.SetValue(CornerRadiusProperty, value);

    public static readonly DependencyProperty CornerRadiusProperty =
        DependencyProperty.RegisterAttached(nameof(Border.CornerRadius), typeof(CornerRadius),
            typeof(CornerRadiusSetter), new UIPropertyMetadata(new CornerRadius(), CornerRadiusChangedCallback));

    public static void CornerRadiusChangedCallback(object sender, DependencyPropertyChangedEventArgs e)
    {
        Control control = sender as Control;

        if (control == null) return;

        control.Loaded += Control_Loaded;
    }

    private static void Control_Loaded(object sender, EventArgs e)
    {
        Control control = sender as Control;

        if (control == null || control.Template == null) return;

        control.ApplyTemplate();

        Border border = control.Template.FindName("border", control) as Border;

        if (border == null) return;

        border.CornerRadius = GetCornerRadius(control);
    }
}

然后,您可以使用附加属性语法来为多个按钮设置样式,而无需重复编写样式:
<Button local:CornerRadiusSetter.CornerRadius="3,0,0,0">Click me!</Button>

<Button local:CornerRadiusSetter.CornerRadius="0,0,0,3">Click me!</Button>

1
天哪,感谢您!所有其他解决方案基本上都需要重新实现按钮的所有视觉效果,而这个解决方案让您可以使用默认设置。 - Mike Caron

1
我会创建一个自定义按钮类(从Button继承),其中包括一个CornerRadius依赖属性。然后您的样式目标类型变成这个新类,您可以使用模板绑定来设置圆角半径。
采用这种方法不仅无需维护多个控件模板副本,而且您无需为每次修改圆角半径创建新样式。您只需直接设置或绑定到CornerRadius依赖属性即可。
因此,您的控件代码可能如下所示:
public class MyCustomButton : Button
{
    public static readonly DependencyProperty CornerRadiusProperty =
        DependencyProperty.Register("CornerRadius", typeof(CornerRadius), typeof(MyCustomButton), new FrameworkPropertyMetadata(new CornerRadius(0)));

    public CornerRadius CornerRadius
    {
        get { return (CornerRadius)GetValue(CornerRadiusProperty); }
        set { SetValue(CornerRadiusProperty, value); }
    }
}

并且 XAML 代码如下:

<Style TargetType="MyCustomButton" x:Key="TabButton">
    <Setter Property="Background" Value="White" />
    <Setter Property="TextBlock.TextAlignment" Value="Center" />
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="MyCustomButton">
                <Border CornerRadius="{TemplateBinding CornerRadius}" Background="White" BorderBrush="#ccc" BorderThickness="0,1,1,0" >
                    <ContentPresenter x:Name="contentPresenter" ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
                </Border>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

所以对于不需要圆角的按钮,由于依赖属性默认为0,您不需要做任何事情。对于具有圆角的按钮,您只需像正常边框的CornerRadius属性一样将依赖属性设置为适当的值即可。


1

我在想把这个放在哪里,然后我把它放在了我的 <Button Content=".. 下面。

<Button.Resources>
 <Style TargetType="{x:Type Border}">
  <Setter Property="CornerRadius" Value="15"/>
 </Style>
</Button.Resources>

并且高于 <Button.RenderTransform>

对我起作用


0
 private Button [] Buttonsd() // Select all buttons on page
        {

            /// casting the content into panel
            Panel mainContainer = (Panel)this.Content;

            /// GetAll UIElement
            UIElementCollection element = mainContainer.Children;
         
            /// casting the UIElementCollection into List
            /// 
            List<DependencyObject> lstElement = element.Cast<DependencyObject>().ToList();

            /// Geting all Control from list
            /// 
            Button [] btns =  lstElement.OfType<Button>().ToArray();





            return btns;

            //maingrid.Children.Add(new Button() { Content = "HELLOMOTO" }); added new controls


           



        }     


private void RadiusButtons(int radiusvalue,Button btn)
            {
                ControlTemplate template = btn.Template;
                Border Border = (Border)template.FindName("border", btn);
                CornerRadius radius = new CornerRadius(radiusvalue);
                Border.CornerRadius = radius;
    
              }
    
                private void AllButtonsSettings()
            {
                Button[] buttons = Buttonsd(); // create buttons collection 
    
                foreach(Button btn in Buttonsd())
                {
                    RadiusButtons(21, btn);
                }
    
    
    
            }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接