0

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

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

我怎样才能解决这个问题?我可以为此使用模板吗?

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

错误 2 无法在元素“StackPanel”上设置名称属性值“ifBlock”。“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>
4

3 回答 3

3

通过引入代码隐藏,您创建了一个额外的 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(如果有)中删除。

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

于 2009-11-08T23:03:12.733 回答
0

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

如果您滚动自己的 Border(而不是继承 Border 类),名称范围问题可能由以下原因引起:

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

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

如果在您的边界上设置了显式 NameScope,也可能会导致这种情况。在这种情况下,将分配名称,但 FindName 不会在 Window/UserContol/template 级别找到它。

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

于 2009-11-07T18:02:27.570 回答
0

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

于 2009-11-08T08:11:49.157 回答