DynamicResource color doesn't work for BorderBrush on a Border - Bug?
Asked Answered
S

5

12

Visual Studio 2010 | .NET/WPF 4.0

I think this might be a WPF bug, but I can't seem to find a bug report about it. To cover the possibility that I'm just missing something obvious, I turn to stackoverflow for answers!

Consider this xaml (nothing in the codebehind):

<Window x:Class="DownExpanders.BorderTest"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="BorderTest" Height="300" Width="300">
    <Window.Resources>
        <Color x:Key="BackgroundColor" R="255" G="0" B="0" A="255"/>
        <Color x:Key="BorderColor" R="0" G="0" B="255" A="255"/>
        <SolidColorBrush x:Key="BorderColorBrush" Color="{DynamicResource BorderColor}"/>
    </Window.Resources>
    <Grid>
        <Border BorderThickness="20">
            <Border.Background>
                <SolidColorBrush Color="{DynamicResource BackgroundColor}"/>
            </Border.Background>
            <Border.BorderBrush>
                <SolidColorBrush Color="{DynamicResource BorderColor}"/>
            </Border.BorderBrush>
        </Border>

        <Border Margin="40" BorderBrush="{DynamicResource BorderColorBrush}" BorderThickness="20"/>
    </Grid>
</Window>

In the designer, it renders as expected. The outer border has a big blue border and a red background, the inner border has a big blue border. Great.

When I run the code, the outer border has NO border - it looks like it just doesn't load. The background is set to red correctly. Meanwhile, the inner border does load its blue border correctly.

If I change all "DynamicResource" to "StaticResource", it renders correctly when run. The inconsistency is really bugging me, and I can't figure it out.\

So:

  1. Why doesn't DynamicResource work for BorderBrush?
  2. Given #1, why does it work for Background?
  3. Why does explicitly defining the solid color brush in the resources seem to fix things?

EDIT:

Looks like it's a bug that MS decided not to fix (thanks to Sheridan for the link): http://connect.microsoft.com/VisualStudio/feedback/details/589898/wpf-border-borderbrush-does-not-see-changes-in-dynamic-resource

Spectrochemistry answered 22/7, 2013 at 14:5 Comment(4)
Interesting, still happens in .net 4.5.50760 so if it is a bug they didn't fix it yet.Shwa
Ye would definitely think it's a bug. You could also add to your bug report, Snoop reports the outer border's brush as Transparent(No errors) and this issue does not occur if you just set the Brush directly even for the outer border as in BorderBrush="{DynamicResource BorderColorBrush}". Hence looks more like an issue of when the SolidColorbrush for BorderBrush is being created from a DynamicResource Color, it gets things screwed up. Not sure maybe some weird case of trying to lock resources / access themCareycarfare
oh something else I just saw too, If you move the resources to a higher scope, say App.xaml, it works fine for your exact codeCareycarfare
Just sometimes dynamic resources do not work if they are not placed in the App.xaml.Lowgrade
W
2

Apparently, the answer to your question is no, this behaviour is not a bug.

This issue was posted on the Microsoft Connect site by a user and the following reply was given:

DynamicResources are "looked up" at runtime rather than compile time. The "Dynamic" refers not to "can be dynamically updated at any time" but "we'll look it up later, when it's actually needed."

If you want to change the border brush at runtime, you'll need to apply a Name="" attribute to the Border in order to touch it from the codebehind, or you can use a Binding to set the value of the brush to a DependencyProperty (if you're using the MVVM pattern or something similar). Change the property and the border brush gets updated by the binding system.

BTW, this would have been a good question over at StackOverflow--"Why isn't my DynamicResource being updated?"

Personally, I like the last line best. Microsoft at its most useful! The page can be found here.

Westerman answered 22/7, 2013 at 15:37 Comment(2)
I'd accept that response from Microsoft if it was a consistent behavior. The Background loads just fine. Only BorderBrush has problem. In fact the OP of that bug noted the same thing, and MS response was "we're not fixing it." Well crap, I guess there's the answer. Giving you the checkmark for finding the bug report :PSpectrochemistry
I have created a simple work-around: #19427851Patnode
S
3

This doesn't seem to be the case with the RadialGradientBrush.

<Window x:Class="WpfApplication3.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">

    <Grid>
        <Grid.Resources>
            <Color x:Key="BackgroundColor" R="255" G="0" B="0" A="255"/>
            <Color x:Key="BorderColor" R="0" G="0" B="255" A="255"/>
            <SolidColorBrush x:Key="BorderColorBrush" Color="{DynamicResource BorderColor}"/>
        </Grid.Resources>
        <Border BorderThickness="20">
            <Border.BorderBrush>
                <RadialGradientBrush>
                    <GradientStop Color="{DynamicResource BorderColor}"/>
                    <GradientStop Color="{DynamicResource BorderColor}"/>
                </RadialGradientBrush>
            </Border.BorderBrush>
            <Border.Background>
                <SolidColorBrush Color="{DynamicResource BackgroundColor}"/>
            </Border.Background>
        </Border>

        <Border Margin="40" BorderBrush="{DynamicResource BorderColorBrush}" BorderThickness="20"/>

    </Grid>
</Window>

enter image description here

Shwa answered 22/7, 2013 at 14:27 Comment(0)
W
2

Apparently, the answer to your question is no, this behaviour is not a bug.

This issue was posted on the Microsoft Connect site by a user and the following reply was given:

DynamicResources are "looked up" at runtime rather than compile time. The "Dynamic" refers not to "can be dynamically updated at any time" but "we'll look it up later, when it's actually needed."

If you want to change the border brush at runtime, you'll need to apply a Name="" attribute to the Border in order to touch it from the codebehind, or you can use a Binding to set the value of the brush to a DependencyProperty (if you're using the MVVM pattern or something similar). Change the property and the border brush gets updated by the binding system.

BTW, this would have been a good question over at StackOverflow--"Why isn't my DynamicResource being updated?"

Personally, I like the last line best. Microsoft at its most useful! The page can be found here.

Westerman answered 22/7, 2013 at 15:37 Comment(2)
I'd accept that response from Microsoft if it was a consistent behavior. The Background loads just fine. Only BorderBrush has problem. In fact the OP of that bug noted the same thing, and MS response was "we're not fixing it." Well crap, I guess there's the answer. Giving you the checkmark for finding the bug report :PSpectrochemistry
I have created a simple work-around: #19427851Patnode
P
1

Another interesting thing is that it does not happen when use a Rectangle instead of a Border.

    <Rectangle StrokeThickness="20">
        <Rectangle.Stroke>
            <SolidColorBrush Color="{DynamicResource BorderColor}"/>
        </Rectangle.Stroke>
        <Rectangle.Fill>
            <SolidColorBrush Color="{DynamicResource BackgroundColor}"/>
        </Rectangle.Fill>
    </Rectangle>
Proconsul answered 22/7, 2013 at 14:29 Comment(0)
A
0

It seems to be fixed in 4.5. In my case it works in Windows 8, but don't work in Windows XP (that don't have .net 4.5).

Amanda answered 4/4, 2014 at 15:34 Comment(0)
R
0

Here is a custom control which you can use in place of the Border. It fixes the problem with the BorderBrush property. It uses Rectangles which work as another answer indicates. Please note that this control will probably not match the performance of using the Border control but it does work, so I suggest only using it where necessary.

<Style TargetType="{x:Type controls:BorderFix}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type controls:BorderFix}">
                <DockPanel x:Name="PART_Container"
                           Background="{TemplateBinding Background}"
                           LastChildFill="True"
                           UseLayoutRounding="{TemplateBinding UseLayoutRounding}">
                    <Rectangle x:Name="PART_LeftBorder"
                               DockPanel.Dock="Left"
                               Fill="{TemplateBinding BorderBrush}"
                               Width="{Binding Path=BorderThickness.Left, RelativeSource={RelativeSource TemplatedParent}}"/>
                    <Rectangle x:Name="PART_TopBorder"
                               DockPanel.Dock="Top"
                               Fill="{TemplateBinding BorderBrush}"
                               Height="{Binding Path=BorderThickness.Top, RelativeSource={RelativeSource TemplatedParent}}"/>
                    <Rectangle x:Name="PART_RightBorder"
                               DockPanel.Dock="Right"
                               Fill="{TemplateBinding BorderBrush}"
                               Width="{Binding Path=BorderThickness.Right, RelativeSource={RelativeSource TemplatedParent}}"/>
                    <Rectangle x:Name="PART_BottomBorder"
                               DockPanel.Dock="Bottom"
                               Fill="{TemplateBinding BorderBrush}"
                               Height="{Binding Path=BorderThickness.Bottom, RelativeSource={RelativeSource TemplatedParent}}"/>
                    <ContentPresenter x:Name="PART_Content"/>
                </DockPanel>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

public sealed class BorderFix : ContentControl
{
    static BorderFix()
    {
        DefaultStyleKeyProperty.OverrideMetadata(typeof(BorderFix), new FrameworkPropertyMetadata(typeof(BorderFix)));
    }
}

The fact that we have to do this is pretty ridiculous. Another answer suggests that this bug is fixed in the version of .NET used by Windows 8. I have not tested that but let us hope that is correct. .NET 4.5.51209 exhibits the same problem.

Ridiculous answered 4/11, 2014 at 14:50 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.