开发者

Create the same border type around all my controls

开发者 https://www.devze.com 2022-12-11 06:43 出处:网络
I tried to create my own Border class and then insert it in my controls but then it seems I cannot assign names to everything inside the borders:

I tried to create my own Border class and then insert it in my controls but then it seems I cannot assign names to everything inside the borders:

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

How can I get around this? Can I use templating somehow for that?

EDIT: Sorry that I was unclear. Yes I subclassed Border with my own XAML file and got this compiler error with the code above:

Error 2 Cannot set Name attribute value 'ifBlock' on element 'StackPanel'. 'StackPanel' is under the scope of element 'ElementBorder', which already had a name registered when it was defined in another scope.

The contents of my ElementBorder class aren't very interesting but I'll post it anyway:

<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>


By introducing code-behind you have created an additional NameScope. You can remove this extra NameScope at runtime by clearing the NameScope after calling InitializeComponent():

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

Although this will work, it is not your best solution. You would be better off creating a style that a UserControl.

There are two ways to do this: With a subclass and without.

With a subclass

Create your ElementBorder subclass and override the default style. Do not call InitializeComponent():

public class ElementBorder
{
  static ElementBorder
  {
    DefaultStyleKeyProperty.OverrideMetadata(typeof(ElementBorder), new FrameworkPropertyMetadata(typeof(ElementBorer)));
  }
  // any additional implementation
}

In your xaml file, instead of including a tag, create a ResourceDictionary containing a style with the settings you want:

<ResourceDictionary xmlns=... >

  <Style TargeType="{x:Type my:ElementBorder}">
    <Setter Property="BorderThickness" Value="4" />
    ...

Merge this ResourceDictionary into the one defined in app.xaml or themes/Generic.xaml using a <MergeDictionary> tag

Note that you can just put the style in the ResourceDictionary in your app.xaml instead of creating a separate file.

Using this is identical to using your original ElementBorder:

<my:ElementBorder>
  <StackPanel  ...

Without a subclass

This requires less code. Just put a Style in a ResourceDictionary as before, except give it a x:Key and use Border as it's target type:

<ResourceDictionary>

  <Style x:Key="ElementBorderStyle" TargeType="{x:Type Border}">
    <Setter Property="BorderThickness" Value="4" />
    ...

This can be used as follows:

 <Border Style="{StaticResource ElementBorderStyle}">
   <StackPanel ...

If you want all of your borders to have the new style, it is even easier. Just omit the x:Key and use Border as your TargetType:

<ResourceDictionary>

  <Style TargeType="{x:Type Border}">
    <Setter Property="BorderThickness" Value="4" />
    ...

This will cause all borders to get the style, so you can just write:

<Border>
  <StackPanel ...

Answer to additional question asked in comment below

To set the BorderBrush the same as the Background:

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

To set the child's Background to the Border's background: Generally not necessary since as long as child's background color isn't set, the border's background color will show through. The only exception is in negative-Margin or RenderTransform situations where the child doesn't render entirely inside the containing border. In that case you will need to bind the child's Background to the Border's Background. This can't be done in a style applied to the BorderBrush without using an attached property. But if you're ok doing it without a style:

<Border x:Name="myBorder">  <!-- Style applied here -->
  <StackPanel Background="{Binding Background, ElementName=myBorder}" ...

this can also be done with an unnamed border with {Binding Background, RelativeSource={RelativeSource FindAncestor,Border,1}.

If you want to do it entirely in the style, you'll have to add some code. Basically, create a class with an attached property named something like "MyBindingTools.BindChildBackgroundToMyBackground". Add a PropertyChangedCallback so that when that property is set to "true", a binding is created on the child, basically:

BindingOperations.SetBinding(border, BackgroundProperty, new Binding("Background") { Source = this });

In addition you will need to monitor the Border's Child property so that when it changes the binding can be added to the new Child and removed from the old Child (if any).

I wouldn't recommend you do any of this unless you really need to, though. In your specific situation you can probably either bind the child manually or create a template that contains both the Border and the child control. Either of these would be better solutions that creating the attached property as I described.


Name scopes are found by searching the logical tree.

If you rolled your own Border (as opposed to subclassing the Border class), name scope problems can be caused by:

  • Failing to call AddLogicalChild
  • Not correctly overriding the LogicalChildren enumeration

On the other hand, if you subclassed the existing Border (or any Decorator) it would handle the logical tree.

This can also be caused if an explicit NameScope is set on your border. In that case, the name would be assigned but FindName won't find it at the Window/UserContol/template level.

Posting the relevant sections of your ElementBorder class might help us give you a better answer.


This is known as Namescope problem Check here for more details: http://dotnet.dzone.com/news/c-and-wpf-namescope-my-name-is

0

精彩评论

暂无评论...
验证码 换一张
取 消