Use x:Shared to write your FrameworkElements directly as Resource

By | July 25, 2011

We all know that StaticResource works mainly with Freezables in WPF. You cannot define a resource like a Button or a TextBox as StaticResource because the runtime will count it to be shared and creating the resource more than once from Resources will leave you an exception.

Lets look this using an example :

<Grid>
        <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>
        
        <Grid.Resources>
            <Button x:Key="btnBase" Content="My Button"/>
        </Grid.Resources>
       
        <StackPanel Orientation="Vertical" Grid.Row="0" Grid.Column="0" >
            <StaticResource ResourceKey="btnBase"  />
        </StackPanel>
        <StackPanel Orientation="Vertical" Grid.Row="0" Grid.Column="1" >
            <StaticResource ResourceKey="btnBase"  />
        </StackPanel>
        <StackPanel Orientation="Vertical"  Grid.Row="1" Grid.Column="0" >
            <StaticResource ResourceKey="btnBase"  />
        </StackPanel>
        <StackPanel Orientation="Vertical"  Grid.Row="1" Grid.Column="1" >
            <StaticResource ResourceKey="btnBase"  />
        </StackPanel>
    </Grid>

In the above example, I have used a Button to be a Resource Object and used the same button to appear inside more than one StackPanel. Notice the Visual Studio Designer appears to be showing the object perfectly and does not complain about the same. This is because the designer does not work with compiled XAML.
clip_image002

Now if you run this code, you will see that the runtime produces an exception as the Resource system uses the same underlying object to define the object in your application. Button being a FrameworkElement needs to be not shared as resource and needs a new object every time you specify in your XAML.

To address this situation, you can use x:Shared attribute and set it to false on a Resource which lets the compiled XAML to create new instance every time you call for the resource. You might think of this as when the compiled XAML gets the Resource for you, it forgets it as being already created Resource and everytime you call for the same resource it will load the resource again for you.

So if you change the above Resource key inside your XAML to this :

<Grid.Resources>
       <Button x:Key="btnBase" Content="My Button" x:Shared="False"/>
</Grid.Resources>

Your application will start working. As I have already told you, this trick will not be much use as compiled XAML creates each button as new object. So it is immaterial in such case to write in resource if it is not shared.

I hope this small trick helped.

Thanks for Reading.