我尝试创建自己的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>
答案 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类),名称范围问题可能由以下原因引起:
另一方面,如果您将现有Border(或任何Decorator)子类化,它将处理逻辑树。
如果在边框上设置了明确的NameScope,也会导致这种情况。在这种情况下,将分配名称,但FindName将无法在Window / UserContol /模板级别找到它。
发布ElementBorder类的相关部分可能有助于我们为您提供更好的答案。
答案 2 :(得分:0)
这称为Namescope问题查看此处了解更多详情: http://dotnet.dzone.com/news/c-and-wpf-namescope-my-name-is