如何给我的自定义控件一个可重写的默认保证金
本文关键字:一个 可重写 保证金 默认 我的 自定义控件 | 更新日期: 2023-09-27 18:11:23
问题
我创建了一个自定义控件(OmniBox(,它的基本样式设置为:
<Style x:Key="GridStyle" TargetType="Grid" BasedOn="{StaticResource BaseElement}">
<Setter Property="Margin" Value="0,2" />
</Style>
但当我使用我的控制时,我希望能够做一些事情,比如:
<UserControl.Resources>
<Style TargetType="{x:Type ui:OmniBox}">
<Setter Property="HorizontalAlignment" Value="Stretch"/>
<Setter Property="Margin" Value="0,10"/> <!--Not Working?-->
</Style>
</UserControl.Resources>
<Grid>
<StackPanel>
<ui:OmniBox x:Name="One"... />
<ui:OmniBox x:Name="Two"... />
...
让我控制的所有实例都承担违约保证金。不幸的是,我的控件没有响应资源中设置的样式。他们只是保持默认保证金"0,2"。
奇怪的是,如果我像这样明确地设置控件的保证金:
<ui:OmniBox x:Name="One" Margin="0,10" Style="OBDefaultStyle" ... />
<ui:OmniBox x:Name="Two" Margin="0,10" ... />
...
他们确实使用了"0,10"的边距,而不是"0,2"。为什么模板类型不起作用?
如果相关的话,我的OmniBox控制模板都是这样的:
<Style TargetType="{x:Type local:OmniBox}" x:Key="OBDefaultStyle">
<Setter Property="Template" Value="{StaticResource OBDefaultTemplate}" />
</Style>
<ControlTemplate TargetType="{x:Type local:OmniBox}" x:Key="OBDefaultTemplate">
<Grid x:Name="PART_Grid" Style="{StaticResource GridStyle}">
... (Content)
</Grid>
</ControlTemplate>
第一次尝试
在我的网格风格中,我尝试将保证金设置为
<Setter Property="Margin"
Value="{Binding Path=Margin, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:OmniBox}}}" />
但这并没有帮助降低模板化的利润率。
第二次尝试
我尝试创建一个自定义的保证金依赖属性,并将网格绑定到该属性:
<Style x:Key="GridStyle" TargetType="Grid" BasedOn="{StaticResource BaseElement}">
<Setter Property="Margin" Value="{Binding Path=MyMargin, RelativeSource={RelativeSource TemplatedParent}}" />
</Style>
我的自定义属性被定义为:
public static readonly DependencyProperty MarginProperty = DependencyProperty.Register("Margin", typeof(Thickness), typeof(OmniBox), new FrameworkPropertyMetadata(new Thickness(0,2,0,2), new PropertyChangedCallback(OnMarginChanged)));
不管怎样,它没有起作用。在上面的dependency属性中设置的默认边距仍然覆盖我试图在样式模板中设置的边距。
您可以通过覆盖DefaultStyleKey:的元数据来为自定义控件添加默认样式
public class MyButton : Button
{
static MyButton()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(MyButton), new FrameworkPropertyMetadata(typeof(MyButton)));
}
}
然后,您创建一个名为Generic.xaml
的资源字典,该字典位于项目根目录中的Themes
目录中(因此路径为"/Themes/Generic.xaml"(。在该资源字典中,您为控件创建了一个默认样式:
<!-- Base the style on the default style of the base class, if you don't want to completely
replace that style. If you do, remember to specify a new control template in your style as well -->
<Style TargetType="SomeNamespace:MyButton" BasedOn="{StaticResource {x:Type Button}}">
<Setter Property="Margin" Value="10" />
</Style>
如果您只添加一个MyButton
控件,它将获得默认样式,但您可以通过应用新样式来覆盖默认样式中设置的属性:
<Window x:Class="SomeNamespace.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:SomeNamespace="clr-namespace:SomeNamespace"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<Style TargetType="SomeNamespace:MyButton">
<Setter Property="Margin" Value="20" />
</Style>
</Window.Resources>
<Grid>
<SomeNamespace:MyButton />
</Grid>
</Window>
GridStyle
指定TargetType="Grid"
,因此设置器<Setter Property="Margin" Value="0,2" />
应用于控制模板根处的Grid
。设置包含OmniBox
的Margin
属性不会影响该网格的边距。
尝试在模板中指定:
<Grid x:Name="PART_Grid" Margin="{TemplateBinding Margin}">
请注意,我没有像您在模板中那样设置Style
属性。这是因为网格的Margin
属性将始终反映包含它的OmniBox
的Margin
属性,从而否定GridStyle
中Margin
属性的影响。相反,您将希望默认OmniBox.Margin
属性并完全删除GridStyle
:
<Style TargetType="{x:Type local:OmniBox}" x:Key="OBDefaultStyle">
<Setter Property="Margin" Value="0 2" />
<Setter Property="Template" Value="{StaticResource OBDefaultTemplate}" />
</Style>
是否覆盖了OmniBox
控件中的DefaultStyleKey
属性?
在解决了这个问题之后,我明白了我需要做什么。在控件的类中,我需要覆盖margin属性的默认值:
static OmniBox()
{
MarginProperty.OverrideMetadata(typeof(OmniBox), new FrameworkPropertyMetadata(new Thickness(0,2,0,2)));
}
在那之后,我完全去掉了omnibox的"网格"组件上的空白,因为控件本身带有空白。现在,当用户在OmniBox上设置"Margin"属性时,它会接受它,如果不接受,则使用默认值。
非常感谢大家的建议和努力。