【问题标题】:How to create/make rounded corner buttons in WPF?如何在 WPF 中创建/制作圆角按钮?
【发布时间】:2011-10-08 09:48:09
【问题描述】:

我需要在 WPF 中创建一个圆角光泽按钮。谁能解释一下需要哪些步骤?

【问题讨论】:

  • 圆角的基础是使用 Border 或 Rectangle 类,以及 Radius 属性
  • @KierenJohnstone 当然,但 Button 类没有这些属性。那么如何为 Button 做到这一点呢?

标签: .net wpf button styles wpf-controls


【解决方案1】:

我知道这篇文章已经很老了,但我有一个答案令人惊讶地从上面遗漏了,而且比大多数人都简单得多。

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

由于 Button 控件的默认 ControlTemplate 使用 Border 元素,因此将 Border 样式添加到 Button 的资源会将该样式应用于该 Border。这使您无需制作自己的 ControlTemplate 也无需任何代码即可添加圆角。它也适用于所有种类的 Button(例如 ToggleButton 和 RepeatButton)。

【讨论】:

  • 这个解决方案非常简单优雅。我不太明白它是如何工作的,因为 Button 对象没有边框,但我还是喜欢它。
  • @Rod 之所以有效,是因为按钮 确实 有边框。 Button 的 ControlTemplate 包含一个 Border 控件并显示其中的所有其他内容。
  • 哦,好的@KeithStein,我对 Button 控件有误解。谢谢!
  • 令人惊讶的是,它在 Windows Embedded 7 上不起作用。我正在尝试为按钮找到默认的 ControlTemplate
【解决方案2】:

您必须为按钮创建自己的 ControlTemplate。看看样本就知道了

创建了一个名为 RoundCorner 的样式,在其中我进行了更改,而是创建了自己的带有边框 (CornerRadius=8) 的新控件模板,用于圆角以及一些背景和其他触发效果。如果您拥有或了解 Expression Blend,则可以非常轻松地完成。

<Style x:Key="RoundCorner" TargetType="{x:Type Button}">
    <Setter Property="HorizontalContentAlignment" Value="Center"/>
    <Setter Property="VerticalContentAlignment" Value="Center"/>
    <Setter Property="Padding" Value="1"/>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type Button}">
                <Grid x:Name="grid">
                    <Border x:Name="border" CornerRadius="8" BorderBrush="Black" BorderThickness="2">
                        <Border.Background>
                            <RadialGradientBrush GradientOrigin="0.496,1.052">
                                <RadialGradientBrush.RelativeTransform>
                                    <TransformGroup>
                                        <ScaleTransform CenterX="0.5" CenterY="0.5" 
                                                        ScaleX="1.5" ScaleY="1.5"/>
                                        <TranslateTransform X="0.02" Y="0.3"/>
                                    </TransformGroup>
                                </RadialGradientBrush.RelativeTransform>
                                <GradientStop Offset="1" Color="#00000000"/>
                                <GradientStop Offset="0.3" Color="#FFFFFFFF"/>
                            </RadialGradientBrush>
                        </Border.Background>
                        <ContentPresenter HorizontalAlignment="Center"
                                          VerticalAlignment="Center"
                                          TextElement.FontWeight="Bold">
                        </ContentPresenter>
                    </Border>

                </Grid>
                <ControlTemplate.Triggers>
                    <Trigger Property="IsPressed" Value="True">
                        <Setter Property="Background" TargetName="border">
                            <Setter.Value>
                                <RadialGradientBrush GradientOrigin="0.496,1.052">
                                    <RadialGradientBrush.RelativeTransform>
                                        <TransformGroup>
                                            <ScaleTransform CenterX="0.5" CenterY="0.5" ScaleX="1.5" ScaleY="1.5"/>
                                            <TranslateTransform X="0.02" Y="0.3"/>
                                        </TransformGroup>
                                    </RadialGradientBrush.RelativeTransform>
                                    <GradientStop Color="#00000000" Offset="1"/>
                                    <GradientStop Color="#FF303030" Offset="0.3"/>
                                </RadialGradientBrush>
                            </Setter.Value>
                        </Setter>
                    </Trigger>
                    <Trigger Property="IsMouseOver" Value="True">
                        <Setter Property="BorderBrush" TargetName="border" Value="#FF33962B"/>
                    </Trigger>
                    <Trigger Property="IsEnabled" Value="False">
                        <Setter Property="Opacity" TargetName="grid" Value="0.25"/>
                    </Trigger>

                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

使用

<Button Style="{DynamicResource RoundCorner}" 
        Height="25" 
        VerticalAlignment="Top" 
        Content="Show" 
        Width="100" 
        Margin="5" />

【讨论】:

  • 天哪。所有这些只是为了获得圆角?
  • 另外,它会使我的按钮变得很暗,并且无法为它们提供圆角。 (使用 WPF 4.0):(
  • @BrianSlugs83 这就是让 WPF 工作如此愉快的原因。
  • @BrainSlugs83 我不认为这是全部需要的。回复器让他很容易,并从使用 Blend 自动生成的代码中复制了这种暴行。这就是为什么他得到了所有神圣的粪便,这就是为什么它的格式如此糟糕。在我看来,答复应该被接受,但绝对不能被赞成。但是,请随意简化圆度的基础知识(省略着色、悬停等)并自己发布。我肯定会为此给你 +1。
  • 删除 WPF 表单 => 插入 WebView => 边框半径:8px => Presto
【解决方案3】:

这更像是一个获得圆角按钮的最小控制模板,但是您不会有任何悬停或单击视觉效果。但是您可以根据需要将这些添加到控件模板中。我正在使用深色背景,因此使用白色背景。

<Style x:Key="RoundedButtonStyle" TargetType="{x:Type Button}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="Button">
                <Border CornerRadius="15" Background="White" BorderThickness="1" Padding="2">
                    <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
                </Border>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

我使用以下博客文章中的控件模板作为起点: http://shihac-sharp.blogspot.com.au/2012/05/button-with-rounded-corners-in-wpf.html

【讨论】:

    【解决方案4】:

    不改变默认样式最简单的解决方案是:

    <Style TargetType="Button" x:Key="RoundButton">
        <Style.Resources>
            <Style TargetType="Border">
                <Setter Property="CornerRadius" Value="5" />
            </Style>
        </Style.Resources>
    </Style>
    

    然后像这样定义你的按钮:

    <Button Style="{DynamicResource RoundButton}" />
    

    【讨论】:

      【解决方案5】:

      你可以试试这个............

       <Border BorderBrush="Black" Name="MyBorder"  
                  Height="78" 
                  Background="Red" 
                  Width="74" 
                  CornerRadius="3">
              <Button Width="{Binding MyBorder.Width}" 
                      Height="{Binding MyBorder.Height}" 
                      Content="Hi" Background="Red"/>
          </Border>
      

      【讨论】:

      • 更容易实现。
      • 这可行,但按钮的背景必须是透明的
      • 某种作品。按钮的点击测试会导致您失去圆度。
      • 嗯。我会为此找到解决方案。感谢您的信息
      【解决方案6】:

      尽管事实已经过去多年,但我觉得考虑不同的方法来处理它很有趣。

      重新创建所有按钮模板的方法是一个很好的方法,如果您想更改所有内容但它会让初学者士气低落,或者如果您只想圆角按钮。的确,你不必改变一切,但至少你必须改变事件......

      在 button.resources 中修改“边框”设计的方法也很棒,如果你是初学者,但如果你想通过更多参数来提升你的设计,那么更改所有按钮可能会很无聊。

      两个阵营都有一个解决方案:

      将此代码放在窗口/页面资源中:

      <Style TargetType="Border" x:Key="RoundMe">
          <Setter Property="CornerRadius" Value="4"/>
      </Style>
      

      然后是按钮:

        <Button.Resources>
              <Style TargetType="Border" BasedOn="{StaticResource RoundMe}"/>
          </Button.Resources>
      

      【讨论】:

        【解决方案7】:

        作为替代方案,您可以编写如下代码:

            <Border 
                    x:Name="borderBtnAdd"
                    BorderThickness="1" 
                    BorderBrush="DarkGray" 
                    CornerRadius="360" 
                    Height="30" 
                    Margin="0,10,10,0" 
                    VerticalAlignment="Top" HorizontalAlignment="Right" Width="30">
                <Image x:Name="btnAdd"
                       Source="Recursos/Images/ic_add_circle_outline_black_24dp_2x.png"
                       Width="{Binding borderBtnAdd.Width}" Height="{Binding borderBtnAdd.Height}"/>
            </Border>
        

        “按钮”看起来像这样:

        您可以设置任何其他内容而不是图像。

        【讨论】:

          【解决方案8】:

          这是@Kishore Kumar 答案的改编版本,更简单,更接近默认按钮样式和颜色。它还解决了他的“IsPressed”触发器顺序错误并且永远不会执行的问题,因为“MouseOver”将优先:

          <Setter Property="Template">
                      <Setter.Value>
                          <ControlTemplate TargetType="{x:Type Button}">
                              <Grid x:Name="grid">
                                  <Border x:Name="border" CornerRadius="2" BorderBrush="#707070" BorderThickness="1" Background="LightGray">
                                      <ContentPresenter HorizontalAlignment="Center"
                                                VerticalAlignment="Center"
                                                TextElement.FontWeight="Normal">
                                      </ContentPresenter>
                                  </Border>
                              </Grid>
                              <ControlTemplate.Triggers>
                                  <Trigger Property="IsMouseOver" Value="True">
                                      <Setter Property="Background" TargetName="border" Value="#BEE6FD"/>
                                      <Setter Property="BorderBrush" TargetName="border" Value="#3C7FB1"/>
                                  </Trigger>
                                  <Trigger Property="IsPressed" Value="True">
                                      <Setter Property="BorderBrush" TargetName="border" Value="#2C628B"/>
                                  </Trigger>
                                  <Trigger Property="IsEnabled" Value="False">
                                      <Setter Property="Opacity" TargetName="grid" Value="0.25"/>
                                  </Trigger>
                              </ControlTemplate.Triggers>
                          </ControlTemplate>
                      </Setter.Value>
                  </Setter>
          

          【讨论】:

            【解决方案9】:

            最简单的方法是

            <Button Content="OK"
                        Background="#D73C46"
                        Foreground="White"
                        BorderThickness="0"
                        Margin="10,25,10,5"
                        Width="275"
                        Height="34"
                        FontSize="12"
                        Click="CloseWindow"
                        HorizontalAlignment="Center">
                    <Button.Resources>
                        <Style TargetType="{x:Type Border}">
                            <Setter Property="CornerRadius" Value="3"/>
                        </Style>
                    </Button.Resources>
                </Button>
            

            【讨论】:

              【解决方案10】:

              您可以使用附加属性来设置按钮边框半径(同样适用于文本框)。

              为附加属性创建类

              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;
                      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="10">Click me!</Button>
              <Button local:CornerRadiusSetter.CornerRadius="5, 0, 0, 5">Click me!</Button>
              <Button local:CornerRadiusSetter.CornerRadius="3, 20, 8, 15">Click me!</Button>
              

              【讨论】:

                【解决方案11】:

                在您的 app.xaml 中添加这部分样式:

                   <Application.Resources>
                     <Style TargetType="FrameworkElement" x:Key="VisibleAnimation">
                  <Setter Property="Visibility" Value="Collapsed"/>
                  <Setter Property="Opacity" Value="10"/>
                  <Setter Property="Height" Value="700"></Setter>
                  <Style.Triggers>
                    <Trigger Property="Visibility" Value="Visible">
                      <Trigger.EnterActions>
                    <BeginStoryboard>
                      <Storyboard>
                        <DoubleAnimation Storyboard.TargetProperty="Opacity"
                                         From="0.0" To="1.0" Duration="0:0:0.5"/>
                       </Storyboard>
                     </BeginStoryboard>
                   </Trigger.EnterActions>
                   </Trigger>
                 </Style.Triggers>
                </Style>
                
                    <Style TargetType="Button" x:Key="BTNCORNER">
                        <Setter Property="Background" Value="White" />
                        <Setter Property="TextBlock.TextAlignment" Value="Center" />
                        <Setter Property="Template">
                            <Setter.Value>
                                <ControlTemplate TargetType="Button">
                                    <Border CornerRadius="7,7,7,7" Background="White"    BorderBrush="#ccc" BorderThickness="1,1,1,1" >
                                        <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>
                
                    </Application.Resources>
                

                按钮

                 <Button x:Name="loginButton"  
                         Style="{StaticResource BTNCORNER}"   
                         Margin="50,20,20,20"  
                         Click="loginButton_Click" 
                         FontSize="20" Width="93" Height="42"  />
                

                【讨论】:

                  【解决方案12】:

                  使用标准动画快速获得圆角的最佳方法是使用 Blend 创建控件模板的副本。 获得副本后,在 Grid 标签上设置圆角半径,您应该能够拥有具有完整动画功能的控件并适用于任何按钮控件。看看这是代码:

                  <ControlTemplate x:Key="ButtonControlTemplate" TargetType="Button">        
                      <Grid x:Name="RootGrid" Background="{TemplateBinding Background}"
                            CornerRadius="8,8,8,8">
                          <VisualStateManager.VisualStateGroups>
                              <VisualStateGroup x:Name="CommonStates">
                                  <VisualState x:Name="Normal">
                                      <Storyboard>
                                          <PointerUpThemeAnimation Storyboard.TargetName="RootGrid" />
                                      </Storyboard>
                                  </VisualState>
                                  <VisualState x:Name="PointerOver">
                                      <Storyboard>
                                          <ObjectAnimationUsingKeyFrames Storyboard.TargetName="RootGrid" Storyboard.TargetProperty="Background">
                                              <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ButtonBackgroundPointerOver}" />
                                          </ObjectAnimationUsingKeyFrames>
                                          <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="BorderBrush">
                                              <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ButtonBorderBrushPressed}" />
                                          </ObjectAnimationUsingKeyFrames>
                                          <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Foreground">
                                              <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ButtonForegroundPointerOver}" />
                                          </ObjectAnimationUsingKeyFrames>
                                          <PointerUpThemeAnimation Storyboard.TargetName="RootGrid" />
                                      </Storyboard>
                                  </VisualState>
                                  <VisualState x:Name="Pressed">
                                      <Storyboard>
                                          <ObjectAnimationUsingKeyFrames Storyboard.TargetName="RootGrid" Storyboard.TargetProperty="Background">
                                              <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ButtonBackgroundPressed}" />
                                          </ObjectAnimationUsingKeyFrames>
                                          <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="BorderBrush">
                                              <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ButtonBorderBrushPressed}" />
                                          </ObjectAnimationUsingKeyFrames>
                                          <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Foreground">
                                              <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ButtonForegroundPressed}" />
                                          </ObjectAnimationUsingKeyFrames>
                                          <PointerDownThemeAnimation Storyboard.TargetName="RootGrid" />
                                      </Storyboard>
                                  </VisualState>
                                  <VisualState x:Name="Disabled">
                                      <Storyboard>
                                          <ObjectAnimationUsingKeyFrames Storyboard.TargetName="RootGrid" Storyboard.TargetProperty="Background">
                                              <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ButtonBackgroundDisabled}" />
                                          </ObjectAnimationUsingKeyFrames>
                                          <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="BorderBrush">
                                              <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ButtonBorderBrushDisabled}" />
                                          </ObjectAnimationUsingKeyFrames>
                                          <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Foreground">
                                              <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ButtonForegroundDisabled}" />
                                          </ObjectAnimationUsingKeyFrames>
                                      </Storyboard>
                                  </VisualState>
                              </VisualStateGroup>
                          </VisualStateManager.VisualStateGroups>
                          <!--<Border CornerRadius="8,8,8,8"
                                          Background="#002060"
                                          BorderBrush="Red"
                                          BorderThickness="2">-->
                              <ContentPresenter x:Name="ContentPresenter"
                                                BorderBrush="{TemplateBinding BorderBrush}"
                                                BorderThickness="{TemplateBinding BorderThickness}"
                                                Content="{TemplateBinding Content}"
                                                ContentTransitions="{TemplateBinding ContentTransitions}"
                                                ContentTemplate="{TemplateBinding ContentTemplate}"
                                                Padding="{TemplateBinding Padding}"
                                                HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
                                                VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
                                                AutomationProperties.AccessibilityView="Raw"/>
                          <!--</Border>-->
                      </Grid>        
                  </ControlTemplate>
                  

                  我还专门在 Storyboard.TargetName="BorderBrush" 中编辑了 VisualState="PointerOver",因为只要 PointerOver 触发,它的 ThemeResource 就会变成方形角。

                  那么您应该可以将它应用到您的控件样式中,如下所示:

                  <Style TargetType="ContentControl" x:Key="ButtonLoginStyle"
                         BasedOn="{StaticResource CommonLoginStyleMobile}">
                      <Setter Property="FontWeight" Value="Bold"/>
                      <Setter Property="Background" Value="#002060"/>
                      <Setter Property="Template" Value="{StaticResource ButtonControlTemplate}"/>        
                  </Style>
                  

                  因此您可以将您的样式应用到任何 Button。

                  【讨论】:

                  • 这是如何工作的 - &lt;Grid&gt; 没有 CornerRadius 属性?这是指 WPF Windows 应用程序,而不是通用 Windows 应用程序 - 它们是不同的。
                  • 是的,你说得对,我说的是 UWP。但无论如何,您仍然可以将该概念应用于 WPF。只需编辑 blend 创建的控件模板并编辑其属性以满足您的需求,这样您就不需要从 0 开始。
                  【解决方案13】:

                  尽管这个问题早已得到解答,但我使用了另一种方法,人们可能会发现这种方法比这些解决方案中的任何一种都更简单(甚至是 Keith Stein 的出色答案)。所以我发布它以防它可能对任何人有所帮助。

                  您可以在按钮上实现圆角,而无需编写任何 XAML(样式除外,一次),也无需替换模板或设置/更改任何其他属性。只需在您的样式中为按钮的“已加载”事件使用 EventSetter 并在代码隐藏中更改它。

                  (如果您的样式位于单独的资源字典 XAML 文件中,那么您可以将事件代码放在 code-behind file for your resource dictionary 中。)

                  我是这样做的:

                  Xaml 样式:

                  <Style x:Key="ButtonStyle" TargetType="{x:Type Button}" BasedOn="{StaticResource {x:Type Button}}">
                      <EventSetter Event="Loaded"                   Handler="ButtonLoaded"/>
                  </Style>
                  

                  代码隐藏:

                  public partial class ButtonStyles
                  {
                      private void ButtonLoaded(object sender, RoutedEventArgs e)
                      {
                          if (!(sender is Button b))
                              return;
                  
                          // Find the first top-level border we can.
                  
                          Border border = default;
                          for (var i = 0; null == border && i < VisualTreeHelper.GetChildrenCount(b); ++i)
                              border = VisualTreeHelper.GetChild(b, i) as Border;
                  
                          // If we found it, set its corner radius how we want.  
                  
                          if (border != null)
                              border.CornerRadius = new CornerRadius(3);
                      }
                  }
                  

                  如果您必须将代码隐藏文件添加到现有资源字典 xaml 文件中,您甚至可以让代码隐藏文件自动出现在 Visual Studio 解决方案中的该 XAML 文件下方。在 .NET Core 项目中,只需为其提供适当的相应名称(例如,如果资源 Dictionary 是“MyDictionary.xaml”,则将代码隐藏文件命名为“MyDictionary.xaml.cs”)。在.NET Framework项目中,需要edit the .csproj file in XML mode

                  【讨论】:

                    【解决方案14】:

                    我知道这是一个老问题,但如果你想在 c# 上而不是 xaml 上制作按钮,你可以设置 CornerRadius 来环绕你的按钮。

                    Button buttonRouded = new Button
                    {
                       CornerRadius = 10,
                    };
                    

                    【讨论】:

                      【解决方案15】:
                      <Button x:Name="btnBack" Grid.Row="2" Width="300"
                                              Click="btnBack_Click">
                                      <Button.Template>
                                          <ControlTemplate>
                                              <Border CornerRadius="10" Background="#463190">
                                                  <TextBlock Text="Retry" Foreground="White" 
                                                             HorizontalAlignment="Center"                                           
                                                             Margin="0,5,0,0"
                                                             Height="40"
                                                             FontSize="20"></TextBlock>
                                              </Border>
                                          </ControlTemplate>
                                      </Button.Template>
                                  </Button>
                      

                      这对我来说很好。

                      【讨论】:

                      • ContentPresenter怎么了?
                      猜你喜欢
                      • 2015-10-04
                      • 2015-10-14
                      • 2021-04-23
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 2010-10-13
                      • 2010-09-12
                      • 1970-01-01
                      相关资源
                      最近更新 更多