【问题标题】:Set CornerRadius on button template在按钮模板上设置 CornerRadius
【发布时间】:2013-07-16 15:40:06
【问题描述】:

我想要一个不定义 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>

【问题讨论】:

  • 按钮没有 CornerRadius 属性。在您的 ControlTemplate 中为您的边界控件设置它。
  • 您将需要两种样式的 Button 来实现您正在做的事情或创建一个自定义 Button 以将 CornerRadius 实现为 DependencyProperty,并将其与 ControlTemplate 中的 Border 的 CornerRadius 绑定。

标签: c# wpf silverlight xaml


【解决方案1】:

您不仅限于您正在模板化的控件的依赖属性。在这种情况下,虽然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>

使用这种方法,您不再需要维护控件模板的多个副本。

【讨论】:

  • 惊人的答案!
  • 我知道我们不喜欢 +1 cmets,但这是大多数人在导致他们提出这个问题的情况下应该寻找的真正答案。
  • @Pieter Witvoet:如何绑定 CornerRadius 的值?因为Button没有。
  • @GreenEyedAndy:绑定到附加属性需要静态 SetPropertyName 方法。 CornerRadius 没有这样的方法(它没有被设计为用作附加属性),但您可以提供自己的方法,或创建自己的附加属性。
  • @GreenEyedAndy:不,Set 方法可以位于任何类中。例如,如果您有一个带有public static void SetMyProperty(DependencyObject o, CornerRadius value) 方法的类MyClass,那么您可以将local:MyClass.MyProperty="{Binding ...}" 添加到您的xaml 按钮。让该方法调用 o.SetValue(Border.CornerRadiusProperty, value) 就完成了。
【解决方案2】:

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

<!--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>

【讨论】:

  • 不错且简单的答案,如果您希望按钮拥有自己的属性,这是完美的选择。
  • 我能够使用这个示例并将其加工成一种风格,这很棒,因为接受的答案破坏了所有默认按钮行为。
  • @Chandraprakash 这是一个很好的答案,适用于很多情况,但它不像看起来那么干净。它实际上不仅覆盖了按钮中的边框的样式,而且覆盖了所有可能作为按钮内容放置的边框。
  • @0xBADF00D 就我的使用而言,这是我见过的最干净的代码,并且可以完美运行,因为我也在 window.resources 上使用它,因此我设置此边框的任何其他控件都将应用于wpf 表单中的所有控件。
【解决方案3】:

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

<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>

【讨论】:

  • 功能上工作正常,但按钮失去其默认样式,即“OnMouseOver”、“OnMouseClick”事件不会改变按钮的视觉状态。
  • 每当我有两个只有一点点改动的模板时,我都会遇到这种情况。这种重复的代码真的很困扰我。一定有更好的方法。
  • @Jordan:有,看我的回答。 :)
  • 虽然这行得通,但它一点也不干。除了琐碎的造型之外,这将很快变得难以管理。
  • 如果我想要一个圆形按钮会怎样?我必须使 CornerRadius 至少是按钮大小的一半。我怎样才能确定按钮不会比圆角半径大?
【解决方案4】:

您可以简单地使用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>
    

    【讨论】:

    • 天哪,谢谢你!所有其他解决方案基本上都需要重新实现按钮的所有视觉效果,而这可以让您使用默认值。
    【解决方案6】:

    我会创建自己的自定义按钮类(继承自 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 属性一样。

    【讨论】:

      【解决方案7】:
       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);
                      }
          
          
          
                  }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-08-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-04-05
        • 1970-01-01
        • 2018-10-22
        相关资源
        最近更新 更多