简体   繁体   中英

Custom control inconsistency in border brush property?

I have created my own control in WPF. Initially I created it as a usercontrol but found the preferred way to do this is to create a class which inherits from control and then place my respective xaml in a control template inside Generic.xaml .

This worked fine when it was in my exe but when I moved it to a dll the border disappeared from my control . My control is based off a textbox and is a pretty much a copy and paste of the textbox's control template with the addition of a button the user can click.

I've identified the relevant part of the control template that is not working which is the BorderBrush="{TemplateBinding Border.BorderBrush}" bit below as well as the next line.

<Style TargetType="{x:Type local:ButtonBox}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type local:ButtonBox}">
                <mwt:ListBoxChrome 
                        Background="{TemplateBinding Panel.Background}"
                        BorderBrush="{TemplateBinding Border.BorderBrush}"
                        BorderThickness="{TemplateBinding Border.BorderThickness}"
                        RenderMouseOver="{TemplateBinding UIElement.IsMouseOver}"
                        RenderFocused="{TemplateBinding UIElement.IsKeyboardFocusWithin}"
                        Name="Bd"
                        SnapsToDevicePixels="True">

I understand template binding but I don't understand why we are binding to Border.BorderBrush . Where is the border that we are binding to? The visual tree shows no border that is part of my control. If I replace these 2 lines with hard coded values then I get a border. I suspect there might be something missing from the dll that the exe has such as a style or something that applies to Border??

Thanks in advance for any replies and anyone who took the time to read. Cheers, Michael

I finally got this sorted out. To answer my first question "Why are we using Border.BorderBrush in this code when there is no border defined in the control template":

BorderBrush="{TemplateBinding Border.BorderBrush}"

The border in Border.BorderBrush is there because the dependency property is defined on the Border class. Although Control has a dependency property of BorderBrush the property is actually defined in Border. ie, this is how is it defined in Border

BorderBrushProperty = DependencyProperty.Register("BorderBrush", typeof(Brush), typeof(Border), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.SubPropertiesDoNotAffectRender | FrameworkPropertyMetadataOptions.AffectsRender, new PropertyChangedCallback(Border.OnClearPenCache)));

and this is how it is used in Control

BorderBrushProperty = Border.BorderBrushProperty.AddOwner(typeof(Control), new FrameworkPropertyMetadata(Border.BorderBrushProperty.DefaultMetadata.DefaultValue, FrameworkPropertyMetadataOptions.None));

The key point here is that Control does not define its own dependency property of BorderBrush, instead it uses AddOwner to associate itself with the existing dependency property. This is why it is defined as Border.BorderBrush in the control template even though the textbox does not have a border in its control template.

The answer to my second question "where is this value set", is that it is set in the textbox's default style. I can get a look at the default style for a textbox by doing this:

            var style = (Style)Application.Current.TryFindResource(typeof(TextBox));
            if (style == null) return;
            XmlWriterSettings settings = new XmlWriterSettings();
            settings.Indent = true;
            StringBuilder sb = new StringBuilder();
            XmlWriter writer = XmlWriter.Create(sb, settings);
            XamlWriter.Save(style, writer);
            MessageBox.Show(sb.ToString());

Once we run this code we can see in the style were both properties are hard coded. This seems odd to me but this is apparently the way it has been done.

  <Setter Property="Border.BorderBrush">
    <Setter.Value>
      <LinearGradientBrush StartPoint="0,0" EndPoint="0,20" MappingMode="Absolute">
        <LinearGradientBrush.GradientStops>
          <GradientStop Color="#FFABADB3" Offset="0.05" />
          <GradientStop Color="#FFE2E3EA" Offset="0.07" />
          <GradientStop Color="#FFE3E9EF" Offset="1" />
        </LinearGradientBrush.GradientStops>
      </LinearGradientBrush>
    </Setter.Value>
  </Setter>
  <Setter Property="Border.BorderThickness">
    <Setter.Value>
      <Thickness>1,1,1,1</Thickness>
    </Setter.Value>
  </Setter>

After I copy pasted that into the style for my control everything worked as expected.

Simple hey? :-)))

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM