如何以通用方式更改按钮的圆度
Posted
技术标签:
【中文标题】如何以通用方式更改按钮的圆度【英文标题】:How to change the roundness of a button in a generic way 【发布时间】:2021-05-28 15:10:22 【问题描述】:我目前正在努力使我的 WPF 应用程序更通用一点。 到目前为止,对于我想创建的每个按钮,我都使用了不同的样式来修改圆度(这会创建很多无用的代码)。
使用以下代码我设法创建了一个可以从 XAML 文件更改的变量,但我无法将它链接到圆度本身。
谁能告诉我我做错了什么?我已经查看了很多论坛,但似乎没有人知道除了“不要以通用方式做”之外的答案。
我可以确定所有内容都在编译,并且样式已正确应用于按钮(不存在 xaml 链接问题)。
我使用的风格:
<Style x:Key="AwakeButton" TargetType="x:Type customcontrols:AwakeButton" BasedOn="StaticResource x:Type Button"
xmlns:extensions="Awake.Services.Properties:Extensions">
<Setter Property="customcontrols:AwakeButton.BorderRoundness" Value="4.0"/>
<Style.Resources>
<Style TargetType="Border">
<Setter Property="CornerRadius" Value="Binding Path=BorderRoundness" />
<!--<Setter Property="CornerRadius" Value="10" />-->
</Style>
</Style.Resources>
</Style>
我为此创建的按钮超载:
public class AwakeButton : Button
public AwakeButton()
public static DependencyProperty BorderRoundnessProperty =
DependencyProperty.RegisterAttached("BorderRoundness", typeof(double), typeof(AwakeButton));
public static void SetBorderRoundness(UIElement element, double value)
element.SetValue(BorderRoundnessProperty, value);
public static double GetBorderRoundness(UIElement element)
return (double)element.GetValue(BorderRoundnessProperty);
我如何在页面中使用它:
<customcontrols:AwakeButton Style="StaticResource AwakeButton" Margin="142,115,0,0" Width="136" Height="167" BorderRoundness="5">
【问题讨论】:
this my answer 展示了如何使用附加的 DP。如果您创建派生按钮类,您可以使用常规 DP,但仍需要更改模板 我已经看到了那个答案,但是到那时我无法让它工作(命名空间问题),而且我认为现在使用自定义类更容易(即使我没有真的需要一个) 【参考方案1】:您必须将BorderRoundness
绑定到父AwakeButton
,否则使用当前的DataContext
进行解析,该DataContext
不包含此属性。此外,如果您从Button
派生,则不必附加依赖属性,您可以使用Register(...)
方法注册一个普通属性。还要让 DPs static
和 readonly
。
<Setter Property="CornerRadius" Value="Binding BorderRoundness, RelativeSource=RelativeSource AncestorType=x:Type local:AwakeButton" />
如果您不更改按钮的任何特殊内容,您还可以创建附加属性而不是仅用于公开BorderRoundness
属性的专用子类型。
public static class ButtonProperties
public static readonly DependencyProperty BorderRoundnessProperty =
DependencyProperty.RegisterAttached("BorderRoundness", typeof(double), typeof(ButtonProperties));
public static void SetBorderRoundness(UIElement element, double value)
element.SetValue(BorderRoundnessProperty, value);
public static double GetBorderRoundness(UIElement element)
return (double)element.GetValue(BorderRoundnessProperty);
您可以使用附加的属性绑定语法(括号)引用BorderRoundness
。
<Style x:Key="AwakeButton" TargetType="x:Type Button" BasedOn="StaticResource x:Type Button">
<Setter Property="local:ButtonProperties.BorderRoundness" Value="4.0"/>
<Style.Resources>
<Style TargetType="Border">
<Setter Property="CornerRadius" Value="Binding (local:ButtonProperties.BorderRoundness), RelativeSource=RelativeSource AncestorType=x:Type Button" />
</Style>
</Style.Resources>
</Style>
您现在使用带有新创建的附加边框圆度属性的常规按钮。
<Button Grid.Row="0" Style="StaticResource AwakeButton" Margin="142,115,0,0" Width="136" Height="167" local:ButtonProperties.BorderRoundness="5"/>
【讨论】:
谢谢,这正是我错过的 x) 现在完美运行【参考方案2】:圆度作为 CornerRadius 应用于按钮的边框。 Border 是在 Button 的 ControlTemplate 中定义的。 ControlTemplate 定义控件的外观。 换句话说,您需要将属性值委托给 ControlTemplate 中的相关元素。
要将值委托给 ControlTemplate,您必须覆盖此模板并将模板化的父属性绑定到模板元素:
在您的 AwakeButton 中将 BorderRoundness
属性定义为简单的 DependencyProperty(未附加)并覆盖默认样式定义,以便 AwakeButton 将使用其自己的默认样式。这样,Button 就可以重复使用,而不必在每次使用时都重新定义 Style,这在您将项目发布为库时尤其重要:
AwakeButton.cs
public class AwakeButton : Button
public static readonly DependencyProperty BorderRoundnessProperty = DependencyProperty.Register(
"BorderRoundness",
typeof(Thickness),
typeof(AwakeButton),
new PropertyMetadata(default(Thickness)));
public Thickness DestinationPath
get => (Thickness) GetValue(AwakeButton.BorderRoundnessProperty);
set => SetValue(AwakeButton.BorderRoundnessProperty, value);
static AwakeButton()
DefaultStyleKeyProperty.OverrideMetadata(typeof(AwakeButton), new FrameworkPropertyMetadata(typeof(AwakeButton)));
Generic.xaml.cs 此文件位于 Themes 文件夹中,包含所有默认样式。 WPF 将自动检查此文件的默认样式,如果没有找到其他样式覆盖,则应用它。
<Style TargetType="AwakeButton">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="AwakeButton">
<Border BorderBrush=TemplateBinding BorderBrush"
BorderThickness="TemplateBinding BorderThickness"
BorderBrush="TemplateBinding BorderBrush"
CornerRadius="TemplateBinding BorderRoundness">
<ContentPresenter />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Stayle>
示例
<Grid>
<AwakeButton BorderRoundness="8" />
</Grid>
但如果你想让它真正通用,使用附加属性,你必须做出附加行为。以下代码适用于在其可视化树中包含 Border
作为子级的每个 DependencyObject
:
class Element : DependencyObject
#region CornerRoundness attached property
public static readonly DependencyProperty CornerRoundnessProperty = DependencyProperty.RegisterAttached(
"CornerRoundness",
typeof(CornerRadius),
typeof(Element),
new PropertyMetadata(default(CornerRadius), Element.OnCornerRoundnessChanged));
public static void SetCornerRoundness(DependencyObject attachingElement, CornerRadius value) =>
attachingElement.SetValue(Element.CornerRoundnessProperty, value);
public static CornerRadius GetCornerRoundness(DependencyObject attachingElement) =>
(CornerRadius) attachingElement.GetValue(Element.CornerRoundnessProperty);
#endregion CornerRoundness attached property
private static void OnCornerRoundnessChanged(DependencyObject attachingElement, DependencyPropertyChangedEventArgs e)
if (Element.TryFindVisualChildElement(attachingElement, out Border elementBorder))
elementBorder.CornerRadius = (CornerRadius) e.NewValue;
public static bool TryFindVisualChildElement<TChild>(DependencyObject parent, out TChild resultElement)
where TChild : DependencyObject
resultElement = null;
if (parent is Popup popup)
parent = popup.Child;
if (parent == null)
return false;
for (var childIndex = 0; childIndex < VisualTreeHelper.GetChildrenCount(parent); childIndex++)
DependencyObject childElement = VisualTreeHelper.GetChild(parent, childIndex);
if (childElement is TChild child)
resultElement = child;
return true;
if (Element.TryFindVisualChildElement(childElement, out resultElement))
return true;
return false;
示例
<StackPanel>
<Button Element.CornerRoundness="8" />
<ToggleButton Element.CornerRoundness="8" />
</StackPanel>
【讨论】:
以上是关于如何以通用方式更改按钮的圆度的主要内容,如果未能解决你的问题,请参考以下文章