在我的所有控件周围创建相同的边框类型

时间:2009-11-07 13:43:08

标签: .net wpf xaml subclass border

我尝试创建自己的Border类,然后将其插入我的控件中,但似乎我无法为边框内的所有内容指定名称:

..
<my:ElementBorder>
        <StackPanel Name="ifBlock" Background="#E0E8FF" />
</my:ElementBorder> 
..

我该如何解决这个问题?我能以某种方式使用模板吗?

编辑: 对不起,我不清楚。是的我使用自己的XAML文件对Border进行了子类化,并且上面的代码出现了这个编译错误:

  

错误2无法设置名称属性   元素上的'ifBlock'值   'StackPanel的'。 'StackPanel'在   元素'ElementBorder'的范围,   已注册名称   当它在另一个范围内定义时。

我的ElementBorder类的内容不是很有趣,但无论如何我都会发布它:

<Border x:Class="DVPE.ElementBorder"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    BorderThickness="4" 
    CornerRadius="4">
</Border>

3 个答案:

答案 0 :(得分:3)

通过引入代码隐藏,您创建了一个额外的NameScope。您可以在调用InitializeComponent()后清除NameScope,在运行时删除此额外的NameScope:

public ElementBorder()
{
  InitializeComponent();
  NameScope.SetNameScope(this, null);
  ...
}

虽然这样可行,但它不是您的最佳解决方案。你最好创建一个UserControl样式。

有两种方法可以做到这一点:使用子类而不使用。

使用子类

创建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" />
    ...

使用&lt; MergeDictionary&gt;将此ResourceDictionary合并到app.xaml或themes / Generic.xaml中定义的那个。标签

请注意,您可以将样式放在app.xaml中的ResourceDictionary中,而不是创建单独的文件。

使用它与使用原始ElementBorder相同:

<my:ElementBorder>
  <StackPanel  ...

没有子类

这需要更少的代码。只需将Style放在ResourceDictionary中,除了给它一个x: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设置为与Background相同:

  <Style TargeType="{x:Type Border}">
    <Setter Property="BorderBrush" Value="{Binding Background, RelativeSource={RelativeSource Self}}" />
    ...

将孩子的背景设置为边框的背景:通常不需要,因为只要未设置孩子的背景颜色,边框的背景颜色就会显示出来。唯一的例外是negative-Margin或RenderTransform情况,其中子项不完全在包含边框内呈现。在这种情况下,您需要将子项的背景绑定到Border的背景。如果不使用附加属性,则无法在应用于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移除(如果有)。

我不建议你做任何这个,除非你真的需要。在您的特定情况下,您可以手动绑定子项或创建包含Border和子控件的模板。如上所述,这些都是创建附加属性的更好解决方案。

答案 1 :(得分:0)

通过搜索逻辑树找到名称范围。

如果你推出自己的边框(而不是子类化Border类),名称范围问题可能由以下原因引起:

  • 未能调用AddLogicalChild
  • 未正确覆盖LogicalChildren枚举

另一方面,如果您将现有Border(或任何Decorator)子类化,它将处理逻辑树。

如果在边框上设置了明确的NameScope,也会导致这种情况。在这种情况下,将分配名称,但FindName将无法在Window / UserContol /模板级别找到它。

发布ElementBorder类的相关部分可能有助于我们为您提供更好的答案。

答案 2 :(得分:0)

这称为Namescope问题查看此处了解更多详情: http://dotnet.dzone.com/news/c-and-wpf-namescope-my-name-is