Is wrapping resource into ResourceDictionary necessery - wpf

Can you please tell is the difference between these two syntaxes?
<UserControl.Resources>
<Style..
</UserControl.Resources>
<UserControl.Resources>
<ResourceDictionary>
<Style..
</ResourceDictionary>
</UserControl.Resources>

In your illustration, nothing.
But in the future, you may want to merge in further dictionaries, which would require the more verbose syntax:
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="url.xaml"/>
</ResourceDictionary.MergedDictionaries>
<Style />
</ResourceDictionary>
</UserControl.Resources>

Related

Is there a way to make a DynamicResource be dynamic for a Freezable in a ResourceDictionary?

I have this in Brushes.xaml:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="clr-namespace:SkinBox.Controls">
<SolidColorBrush x:Key="{x:Static controls:Keys.BackgroundBrushKey}"
Color="{DynamicResource {x:Static controls:Keys.BackgroundColorKey}}" />
</ResourceDictionary>
And use it like this in Generic.xaml:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:SkinBox.Controls"
xmlns:system="clr-namespace:System;assembly=System">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/SkinBox.Controls;component/Themes/Skins/Blue.xaml" />
<ResourceDictionary Source="pack://application:,,,/SkinBox.Controls;component/Themes/Brushes.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
The problem is that wpf freezes the brush so the DynamicResource has no effect.
Is there a clean way to solve this? I can only think of nasty hacks.
Thought of a workaround:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="clr-namespace:SkinBox.Controls">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/SkinBox.Controls;component/Themes/Skins/Yellow.Colors.xaml" />
<ResourceDictionary Source="pack://application:,,,/SkinBox.Controls;component/Themes/Brushes.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
This still does not give true dynamic resources but it reapplies the brushes so that they update when applying the skin.
Removes the need for duplicating the brushes in every skin.

Merged dictionaries and local resources

I have a Styles.xaml that groups many ResourceDictionarys inside a MergedDictionary.
I imported Styles.xaml in my UserControl.Resources
<UserControl.Resources>
<ResourceDictionary Source="Dictionaries\Styles.xaml" />
</UserControl.Resources>
but when I try to add a converter
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Dictionaries\Styles.xaml" /> <--! Exception -->
</ResourceDictionary.MergedDictionaries>
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/>
</ResourceDictionary>
</UserControl.Resources>
it raises
ArgumentNullException: Value cannot be null.
Parameter name: item
Wrapping the converter inside another MergedDictionary has no effect.
How can I solve this?
Thank you all!
SOLVED
I eventually figured it out: the Exception was raised inside one the .xaml files, but Visual Studio does not provide enough info to locate the faulty line.
Following code does work.
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Dictionaries\Styles.xaml" />
</ResourceDictionary.MergedDictionaries>
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/>
</ResourceDictionary>
</UserControl.Resources>
Try this
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/PROJECTNAMESPACE (TestProject.Something);component/Dictionaries/Styles.xaml" />
</ResourceDictionary.MergedDictionaries>
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/>
</ResourceDictionary>
</UserControl.Resources>

XAML ResourceDictionary same-assembly reference

I'm developing a WPF control library, and I need to reference a resource dictionary defined in the same assembly.
I managed to get it working with a separate-assembly reference.
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary
Source="pack://application:,,,/MyLocalAssembly;component/Foo.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
While with a same-assembly reference it doesn't work, and raises an exception ("Cannot locate resource 'Foo.xaml'.") at load time. Note that in the designer everything works fine, no matter which method I use.
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary
Source="pack://application:,,,/Foo.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
Don't use absolute path for the resource dictionary. Simply use relative path reference.
For example,
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary
Source="folder/Foo.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>

When <ResourceDictionary> has both direct resources and merged resources, why can't resources be found?

File app.xaml
<Application.Resources>
<ResourceDictionary>
<SolidColorBrush x:Key="appBrush" Color="Red"/>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Dictionary1.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
File Dictionary1.xaml
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<ControlTemplate x:Key="ct">
<Rectangle Fill="{StaticResource appBrush }"/>
</ControlTemplate>
</ResourceDictionary>
Then MainWindow uses the template defined.
<Control Template="{StaticResource ct}"/>
Run. It says cannot find appBrush. What's the problem?
Note, changing StaticResource to DynamicResource definitely lets it work. But what is the reason forcing me to make the change?
Change your App.xaml to this and it will work:
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary>
<SolidColorBrush x:Key="appBrush" Color="Red"/>
</ResourceDictionary>
<ResourceDictionary Source="Dictionary1.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
I believe it is related to how resources are merged together. In these type of situations, I always use a Brushes.xaml resource dictionary to define all my brushes, and merge that in ahead of any other resource dictionaries.

Xaml Design View can't find Background Brush

in order to clean up my code, I'm trying to split my app.xaml into seperate resource dictionaries. This works at runtime, but not at design time:
snipped in app.xaml
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/;component/Theme/Colors.xaml" />
<ResourceDictionary Source="/;component/Theme/Styles.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
Colors.xaml
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<SolidColorBrush x:Key="backgroundBrush" Color="Gold"/>
</ResourceDictionary>
Styles.xaml
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style TargetType="StatusBar">
<Setter Property="Background" Value="{StaticResource backgroundBrush}" />
</Style>
</ResourceDictionary>
Snipped of MainWindow.xaml
<Window x:Class="test.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="test" Width="800" Height="600" >
<StatusBar Name="statusBar" DockPanel.Dock="Bottom">
<StatusBarItem Content="{Binding statusMessage}" />
</StatusBar>
DesignView gives the error:
Error 8 '{DependencyProperty.UnsetValue}' is not a valid value for property 'Background'. C:\Daten\DotNet\test\test\MainWindow.xaml 123
If I put backgroundBrush directly into app.xaml like so:
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/;component/Theme/Colors.xaml" />
<ResourceDictionary Source="/;component/Theme/Styles.xaml" />
<ResourceDictionary>
<SolidColorBrush x:Key="backgroundBrush" Color="Gold"/>
</ResourceDictionary>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
DesignView has no problems.
So is there a way to tell DesignView where to find backgroundBrush, if this brush is placed into a seperate resource dictionary?
Thats the problem with StaticResource isnt it. It needs the resource key resolved explicitly using shared \ merged \ direct resource dictionaries hierarchically up.
There are two options...
merge Colors.xaml dictionary in Styles.xaml
OR
in Styles.xaml refer the bursh using DynamicResource.
In case Resources are in different assemblies than that where MainWindow resides and the one dictionary is refering to the other dictionary. In that case reference is not resolved. This bug is already reported at Microsoft site in case your target framework is 4.0. However they have provided a workaround for it. Simply add the empty style in your Resource dictionaries and it will work fine like this -
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/;component/Theme/Colors.xaml" />
<ResourceDictionary Source="/;component/Theme/Styles.xaml" />
</ResourceDictionary.MergedDictionaries>
<Style TargetType="{x:Type Window}"/>
</ResourceDictionary>
</Application.Resources>
For further refernce please look at this link - https://connect.microsoft.com/VisualStudio/feedback/details/555322/global-wpf-styles-are-not-shown-when-using-2-levels-of-references#details
Try
{StaticResource ApplicationPageBackgroundThemeBrush}
for your status bar background value

Resources