Referencing a Parent's ResourceDictionary in a UserControl - wpf

I have a library of WPF UserControls, and a ResourceDictionary that is shared within the library.
All the UserControls in this library appear only within a single 'shell' parent control, which is really just a container for a collection of smaller controls. I'm able to access the ResourceDictionary from my shell control as expected when I add the following XAML
<Control.Resources>
<ResourceDictionary Source="MyResources.xaml" />
</Control.Resources>
However I can't access the ResourceDictionary from child controls that sit inside the 'shell' control.
I was under the impression that WPF should check locally for resources, and then traverse upwards until appropriate resources are found?
Instead I'm getting
Cannot find resource named '{BoolInverterConverter}'.
Resource names are case sensitive. Error at
object 'System.Windows.Data.Binding' in markup file...
Obviously I can (and am) referencing the ResourceDictionary in my child controls; but each and every control now needs to reference this dictionary and I believed that this was not necessary.
Any ideas, am I doing something strange or is my expectation of behaviour incorrect?

What's going on is described here, though the documentation's a little opaque. If you add a ResourceDictionary to an element'sResources property without specifying a key, WPF expects that you're merging in resource dictionaries, and it populates the dictionary with the contents of the dictionaries in its MergedDictionaries property. It ignores the actual contents of the ResourceDictionary with no key.
So what you want to do is this:
<Control.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="MyResources.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Control.Resources>
Edit:
A working example:
MainWindow.xaml:
<Window x:Class="MergedDictionariesDemo.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:MergedDictionariesDemo="clr-namespace:MergedDictionariesDemo" Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Dictionary1.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
<Grid>
<MergedDictionariesDemo:UserControl1 />
</Grid>
</Window>
Dictionary1.xaml:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<SolidColorBrush x:Key="UCBrush"
Color="Bisque" />
</ResourceDictionary>
UserControl1.xaml:
<UserControl x:Class="MergedDictionariesDemo.UserControl1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Border Margin="10" BorderBrush="Navy" BorderThickness="1" CornerRadius="10">
<TextBlock Margin="10"
Background="{DynamicResource UCBrush}">
The background of this is set by the resource UCBrush.
</TextBlock>
</Border>
</UserControl>

Related

WPF - Define a alias for a SolidColorBrush In App.Resource (StaticResourceExtension?)

I use MaterialDesign in my app and I would like to give an alias to the PrimaryHueLightBrush SolidColorBursh, which is defined there. I have found that StaticResourceExtension seems to be the solution to this. But I have not been able to get this to work.
Also I would like the "alias" to be defined in the App.xaml so the alias will be accessible from my entire application.
I have defined the "alias" in the App.xaml and I use it in the MainWindow.xaml.
App.xaml
<Application x:Class="MaterialDesignTest.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:MaterialDesignTest"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
StartupUri="MainWindow.xaml">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<materialDesign:BundledTheme BaseTheme="Light" PrimaryColor="DeepPurple" SecondaryColor="Lime" />
<ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Defaults.xaml" />
</ResourceDictionary.MergedDictionaries>
<StaticResourceExtension x:Key="MyAlias" ResourceKey="PrimaryHueLightBrush" />
</ResourceDictionary>
</Application.Resources>
MainWindow
<Window x:Class="MaterialDesignTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:MaterialDesignTest"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
mc:Ignorable="d"
Background="{DynamicResource MaterialDesignPaper}"
TextElement.Foreground="{DynamicResource MaterialDesignBody}"
Title="MainWindow" Height="Auto" Width="500">
<Border Background="{DynamicResource MyAlias}" />
</Window
In the designer of my MainWindow I can see that the Border gets the DeepPurple color defined in the App.xaml file. So that connection seem to work.
When I try to run my application there is an error:
Index was out of range. Must be non-negative and less than the size of the collection.
VS point the error to the beginning of the x:Key parameter of the StaticResourceExtension element in the App.xaml-file.
Is there a solution for this?
I don't need to use a StaticResourceExtension. Just something so I can have an alias.
PrimaryHueLightBrush is the "alias".
What you can do is to create a copy of the brush and reference the copy instead:
<SolidColorBrush x:Key="MyAlias" Color="{Binding Color,
Source={StaticResource PrimaryHueLightBrush}}"/>

Moving merged XAML ResourceDictionaries to Generic.xaml causes error

I have created two custom controls, both inherited from System.Windows.Controls.Button. One is called XLButton and the other is XLBox. They have identical XAML styles/templates in two separate ResourceDictionary objects in two separate .xaml files, and identical code-behind files, except that "XLButton" appears in the XLButton files where "XLBox" appears in the XLBox files, and vice versa.
I have created a simple test window with a two-row Grid. I merge the the ResourceDictionary files into a the Window.Resources of that test window and create an instance of each custom control, one in the top row, one in the bottom. This works fine. Here's the test window's XAML:
<Window x:Class="ScratchPadWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:ExLuminaControls"
mc:Ignorable="d"
Title="ScratchPadWindow" Height="118" Width="145">
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/Styles/XLBox.xaml" />
<ResourceDictionary Source="/Styles/XLButton.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<local:XLBox Content="Hi!"/>
<local:XLButton Grid.Row="1" Content="Yeah!"/>
</Grid>
</Window>
This works just fine. But, when I comment out the ResourceDictionary.MergedDictionaries section and copy it in its original form to Themes\Generic.xaml, so it looks like this:
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:ExLuminaControls"
mc:Ignorable="d">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/Styles/XLButton.xaml" />
<ResourceDictionary Source="/Styles/XLBox.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
I get a "Cannot locate resource 'styles/xlbutton.xaml' error, associated with this line:
<local:XLBox Content="Hi!"/>
That doesn't make sense to me, but what's more confusing is that the problem goes away if i click "Disable project code" in the designer.
I'm using Blend 2017 Community.
Can anyone help me understand this?
Thanks!
it's path problem, when in generic, use it like this
<ResourceDictionary Source="/AssemblyName;Component/Styles/XLButton.xaml" />
or have to go up with "../../"
themes and generic lowercase
assembly info
app.xaml if nothing works
[assembly: ThemeInfo(
ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
//(used if a resource is not found in the page,
// or application resource dictionaries)
ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
//(used if a resource is not found in the page,
// app, or any theme specific resource dictionaries)
)]
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/Fluent;Component/Themes/Generic.xaml" />
...
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
Definition and style
#region --------------------CONSTRUCTORS--------------------
static WaitSpin()
{
FrameworkElement.DefaultStyleKeyProperty.OverrideMetadata(typeof(WaitSpin),
new FrameworkPropertyMetadata(typeof(WaitSpin)));
}
/// <summary>
/// LoadingAnimation constructor.
/// </summary>
public WaitSpin()
{
this.DefaultStyleKey = typeof(WaitSpin);
}
#endregion
<Style x:Key="{x:Type local:WaitSpin}" TargetType="{x:Type local:WaitSpin}">

Linked resource dictionary and StaticResource reference at root level

I'm aware of this, which doesn't apply to my case, and this, which I'm not sure whether it can be adapted.
I'm working on a WPF control library, and I don't have an App.xaml file. I use a file called Styles.xml to store common brushes and other resources. In the XAML file of my user control I import the resources and then I try to use brush sBrush as a background.
This works except that at the root level:
<UserControl x:Class="CMControls.TitledWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300"
Background="{StaticResource ResourceKey=sBrush}"> <!--EXCEPTION!-->
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary
Source="pack://application:,,,/CMControls;component/Styles.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
<Canvas Background="{StaticResource ResourceKey=sBrush}" ... <!--Ok.-->
...
I presume this happens because when the root element is instantiated its children are not, including UserControl.Resources. Is there any workaround? Note that in the designer everything works fine, no matter where I make the reference.
Change UserControl Background after Resource Merging line,because you have to add resources before using them!
<UserControl x:Class="CMControls.TitledWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary
Source="pack://application:,,,/CMControls;component/Styles.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
<UserControl.Background> <!--Set background here!-->
<StaticResource ResourceKey="sBrush"></StaticResource>
</UserControl.Background>
...

Including resource dictionary in UserControl.Resources fails to compile

I have a custom control that I want to apply some styles from a resource dictionary in another project. For some reason, adding resources in the UserControl.Resources fails, however placing it in the Grid.Resources succeeds;
<UserControl x:Class="My.Name.Space.MyUserControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d" d:DesignHeight="200" d:DesignWidth="300">
<UserControl.Resources>
<ResourceDictionary x:Key="UserControlResources">
<!--Putting it here fails-->
</ResourceDictionary>
</UserControl.Resources>
<Grid>
<Grid.Resources>
<ResourceDictionary x:Key="GridResources">
<!--Putting it here succeeds-->
</ResourceDictionary>
</Grid.Resources>
<!--Control XAML-->
</Grid>
</UserControl>
I get an error "The name 'IntializeComponent' does not exist in the current context". However, looking at the autogenerated MyUserControl.g.i.cs file, hey presto; there it is. What am I doing wrong? What is the difference between these two declarations?
Thanks, Sterren

Accessing resources during initialization of control

lets assume we have the following control definition
<ctrl:ChildWindow x:Class="Control.Editor"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ctrl="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls"
xmlns:local="clr-namespace:Control"
Width="400" Height="300"
local:AttachedProperties.DialogResult="{Binding Path=DialogResult}"
Title="{Binding Path=Caption}" Style="{StaticResource Title}" DataContext="{Binding}" HasCloseButton="False">
<ctrl:ChildWindow.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/Control;component/Resources/BaseAppearance.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</ctrl:ChildWindow.Resources>
</ctrl:ChildWindow&gt
The problem is that the style on the root control cannot be set because the ResourceDictionary is not loaded.
How can I get access to the StaticResource Title during the initialization of the control, when I don't have access to the App class? I'm also not sure that it would be possible, if I would have access to it.
Regards
I'd recommend accessing your resource and doing the work in the .Loaded() event of your control.
Edit: On second thought... I think I know what you're doing now... You have a resource set in your App.xaml class, but you want to access it in your control.
Easy way around the problem is to set it to a DynamicResource instead... but this is less performant.
What is the BuildAction set to on your App.xaml in the property's tab?
If it is ApplicationDefinition... then you should be able to access your resource as you currently are.
I found the common way without using code behind. I knew it is possible. ^^
<ctrl:ChildWindow x:Class="Control.Editor"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ctrl="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls"
xmlns:local="clr-namespace:Control"
Width="400" Height="300"
local:AttachedProperties.DialogResult="{Binding Path=DialogResult}"
Title="{Binding Path=Caption}" DataContext="{Binding}" HasCloseButton="False">
<ctrl:ChildWindow.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/Control;component/Resources/BaseAppearance.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</ctrl:ChildWindow.Resources>
<crtl:ChildWindow.Style>
<StaticResource ResourceKey="Title" />
</crtl:ChildWindow.Style>
</ctrl:ChildWindow&gt

Resources