Search code examples
wpfimagexamluser-controlsresources

WPF UserControls: Image disappears even with 'x:Shared="False"'


I defined a style in a ResourceDictionary for a button with an image:

<Style x:Key="BotonIrAInicioStyle" TargetType="Button">
    <Setter Property="Margin" Value="0"/>
    <Setter Property="Width" Value="{Binding RelativeSource={RelativeSource Self}, Path=ActualHeight}"/>
    <Setter Property="Content">
        <Setter.Value>
            <Image Margin="2" Source="{StaticResource IconoDashboardBlanco}" MaxHeight="20" Stretch="Uniform"
                   RenderOptions.BitmapScalingMode="HighQuality"/>
        </Setter.Value>
    </Setter>
</Style>

The image source is defined in another ResourceDictionary in the same assembly, and marked as x:Shared="False":

<BitmapImage x:Key="IconoDashboardBlanco" x:Shared="False"
UriSource="pack://application:,,,/QualityFramework;component/Images/dashboard64X64.png"/>

Since the style will be used in a different assembly, I used the "pack://application:,,," notation to reference the image. The Build Action for the image is set to Resource (Do not copy to output directory).

In the main assembly I have two UserControls which display a button with identical style:

<Button DockPanel.Dock="Left" Style="{StaticResource BotonIrAInicioStyle}" Click="BotonIrAInicio_Click"/> (Click event has nothing to do with the problem)

PROBLEM:

I open UserControl A containing the button with the image and the image is displayed ok. Then I open UserControl B containing an identical button, image ok. I open UserControl A again, and the image is gone. Happens the same if I open UserControl B and then UserControl A, the last one "owns" the image.

I went everywhere and all the solutions point to the x:Shared="False", the URI notation and the Build Action... I applied all of them and the problem still happens. I also tried cleaning and rebuilding with no success.

What am I missing? Thanks!

PS: if I set the content of both buttons to the image directly it works ok, but the whole point of styling is to avoid exactly that!


Solution

  • The problem is not the BitmapImage it's the content in the setter of the button - it's created once and thus has to "jump" between instances.

    The easy, but not WPF-isque, solution is setting x:Shared="False" on the style.

    The correct way is to use ControlTemplate or DataTemplate.

    From your observations:

    "if I set the content of both buttons to the image directly it works ok" - this is because to do that you create two different instances of Image object.

    But, this: "the whole point of styling is to avoid exactly that!" is a misconception - styles are not meant to set the content of content controls, the content is dependent upon the context. If you have a visual that is repeating for all buttons (without dependency upon the content), it should reside in ControlTemplate for the button. If you have a visual that is dependent upon the content (but the content is not the visual) it should reside in DataTemplate.