通过引入代码隐藏,您创建了一个额外的 NameScope。您可以在运行时通过在调用 InitializeComponent() 后清除 NameScope 来移除这个额外的 NameScope:
public ElementBorder()
{
InitializeComponent();
NameScope.SetNameScope(this, null);
...
}
尽管这会起作用,但这不是您的最佳解决方案。您最好创建一个用户控件的样式。
有两种方法可以做到这一点:使用子类和不使用子类。
有一个子类
创建您的 ElementBorder 子类并覆盖默认样式。不要调用 InitializeComponent():
public class ElementBorder
{
static ElementBorder
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(ElementBorder), new FrameworkPropertyMetadata(typeof(ElementBorer)));
}
// any additional implementation
}
在您的 xaml 文件中,不要包含标记,而是创建一个包含具有所需设置的样式的 ResourceDictionary:
<ResourceDictionary xmlns=... >
<Style TargeType="{x:Type my:ElementBorder}">
<Setter Property="BorderThickness" Value="4" />
...
使用 <MergeDictionary> 标记将此 ResourceDictionary 合并到 app.xaml 或 theme/Generic.xaml 中定义的那个
请注意,您可以只将样式放在 app.xaml 的 ResourceDictionary 中,而不是创建单独的文件。
使用它与使用原始 ElementBorder 相同:
<my:ElementBorder>
<StackPanel ...
没有子类
这需要更少的代码。像以前一样在 ResourceDictionary 中放一个 Style ,除了给它 ax:Key 并使用 Border 作为它的目标类型:
<ResourceDictionary>
<Style x:Key="ElementBorderStyle" TargeType="{x:Type Border}">
<Setter Property="BorderThickness" Value="4" />
...
这可以按如下方式使用:
<Border Style="{StaticResource ElementBorderStyle}">
<StackPanel ...
如果您希望所有边框都具有新样式,那就更容易了。只需省略 x:Key 并使用 Border 作为您的 TargetType:
<ResourceDictionary>
<Style TargeType="{x:Type Border}">
<Setter Property="BorderThickness" Value="4" />
...
这将导致所有边框都获得样式,因此您只需编写:
<Border>
<StackPanel ...
回答下面评论中提出的其他问题
要将 BorderBrush 设置为与背景相同:
<Style TargeType="{x:Type Border}">
<Setter Property="BorderBrush" Value="{Binding Background, RelativeSource={RelativeSource Self}}" />
...
将孩子的背景设置为边框的背景:一般不需要,只要不设置孩子的背景颜色,边框的背景颜色就会透出来。唯一的例外是在负边距或 RenderTransform 情况下,孩子没有完全呈现在包含边框内。在这种情况下,您需要将孩子的背景绑定到边框的背景。如果不使用附加属性,则无法在应用于 BorderBrush 的样式中完成此操作。但是,如果您可以在没有样式的情况下这样做:
<Border x:Name="myBorder"> <!-- Style applied here -->
<StackPanel Background="{Binding Background, ElementName=myBorder}" ...
这也可以通过带有 . 的未命名边框来完成{Binding Background, RelativeSource={RelativeSource FindAncestor,Border,1}
。
如果您想完全按照样式进行操作,则必须添加一些代码。基本上,使用名为“MyBindingTools.BindChildBackgroundToMyBackground”之类的附加属性创建一个类。添加一个 PropertyChangedCallback 以便当该属性设置为“true”时,在子级上创建一个绑定,基本上:
BindingOperations.SetBinding(border, BackgroundProperty, new Binding("Background") { Source = this });
此外,您将需要监视 Border 的 Child 属性,以便在它更改时绑定可以添加到新 Child 并从旧 Child(如果有)中删除。
不过,除非你真的需要,否则我不建议你这样做。在您的特定情况下,您可能可以手动绑定子控件或创建包含边框和子控件的模板。正如我所描述的,这些中的任何一个都是创建附加属性的更好的解决方案。