wpf load resource from another folder/namespace - wpf

How can I load a resource e.g. a style resource from another folder in the same project? Any ideas?
My directory looks like this and I want to use the ButtonStyles.xaml within the ButtonTest.xaml. In the design mode ,before starting the application. Using the resource in the App.xaml works perfectly during runtime.

Add your custom style in a ResourceDictionary in the folder you want -
in my example the file is /Resources/Themes/Button.xaml. Give the style a key:
<Style x:Key="MyButtonStyle" TargetType="{x:Type Button}">
// define your style, for example
<Setter Property="SnapsToDevicePixels" Value="true"/>
<Style>
In case you wish to add multiple style files, it is good to merge your ResourceDictionaries,
for example into a file called Generic.xaml:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/PROJECT_NAME;component/Resources/Themes/Button.xaml"/>
<ResourceDictionary Source="pack://application:,,,/PROJECT_NAME;component/[path and file name]"/>
// add all your resourcedictionaries
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
where you want to use the styles, add the merged ResourceDictionary as a Resource. For example in a UserControl,
add it like this:
<UserControl.Resources>
<inf:DesignTimeResourceDictionary Source="pack://application:,,,/PROJECT_NAME;component/Resources/Themes/Generic.xaml"/>
</UserControl.Resources>
Then when you add your button you can use the style as a dynamic resource using the key you gave it.
<Button Style="{DynamicResource MyButtonStyle}"/>
Make sure to change all the names to match your project and file names.

Related

XAML designer with UserControls in DLL doesn't resolve resource

I have a solution in Visual Studio 2019, made of some projects built as DLL using WPF .NET 5.
Now I need to create some UserControls inside one of this projects, that I will load in a future WPF .NET 5 application, but the problem is that the XAML designer is not able to preview the UserControl with StaticResource that are in an external ResourceDictionary.
I simplify the code:
<UserControl.Resources>
<Style x:Key="sButton" TargetType="Button">
<Setter Property="BorderBrush" Value="{StaticResource color_UC_BorderBrush}"/>
</Style>
</UserControl.Resources>
Having only DLL I don't have an Application with shared ResourceDictionary and color_UC_BorderBrush could not be resolved for preview.
In the following way instead the XAML designer works properly, but I don't want that every single UserControl loads his own ResourceDictionary everytime:
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/MyLib;component/ResourceDictionaries/myRD.xaml"/>
</ResourceDictionary.MergedDictionaries>
<Style x:Key="sButton" TargetType="Button">
<Setter Property="BorderBrush" Value="{StaticResource color_UC_BorderBrush}"/>
</Style>
</ResourceDictionary>
</UserControl.Resources>
In my future WPF .NET 5 application I will use shared ResourceDictionary but for now how can I manage to let the XAML designer works properly inside a DLL or how can I make the MergedDictionary defined in the XAML ignorable?
Maybe there are other ways I don't have in mind. Thank you.
You can't omit merging the resource into a ResourceDictionary within the scope of the control that depends on it.
But instead of merging the same resource into each control's ResourceDictionary, you can choose a ResourceDictionary of a common parent. The XAML resource lookup strategy will traverse the logical tree to search for the required resource, starting at the local ResourceDictionary of the control and ending at the root, before checking App.xaml and Generic.xaml.
In case of the UserControl, you would have to use the DynamicResource markup extension. This is, because the content will only be part of of the logical tree during runtime. In design time, the root from the user control's content point of view is the containing UserControl.
You should know that DynamicResource has a performance penalty. So you typically would try to avoid it.
Also defining the resource in each control's ResourceDictionary will introduce a performance penalty.
The best solution is to define the resource in the application's root control like Window.Resources or even better in the ResourceDictionary inside App.xaml.
Using App.xaml to host the merged ResourceDictionary would also allow to use the cheaper StaticResource from inside the UserControl to lookup the merged resources.
Please read Static and dynamic resources to learn more about the lookup behavior of the XAML engine.
The following example chooses the MainWindow as the host for the merged resources. It is the root of all it's contained elements and therefore reachable from any location in its logical tree.
MainWindow.xaml
Make the resource available for any element that is a child of MainWindow:
<Window>
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<!-- The resource dictionary that contains the shared 'color_UC_BorderBrush' resource -->
<ResourceDictionary Source="pack://application:,,,/MyLib;component/ResourceDictionaries/myRD.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
<MyUserControl />
</Window>
MyUserControl.xaml
<UserControl>
<UserControl.Resources>
<Style x:Key="sButton" TargetType="Button">
<Setter Property="BorderBrush"
Value="{DynamicResource color_UC_BorderBrush}" />
</Style>
</UserControl.Resources>
<Button Style="{StaticResource sButton}" />
</UserControl>

How should application wide resources be organized?

Here is the scenario:
I have been using VS 2010 to write quite a large WPF project using MEF. There are multiple projects within this solution and I have one ResourceDictionary for all of my styles.
The AppStyles.xaml ResourceDictionary is located in my startup project, it contains all of my styles for the project. And within my App.xaml I have the following:
<Application x:Class="Dionysus.Shell.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
DispatcherUnhandledException="UnhandledException" ShutdownMode="OnMainWindowClose">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="AppStyles.xaml"/>
</ResourceDictionary>
</Application.Resources>
Now, this all works perfectly in design mode of VS 2010 and when I am debugging, the correct styles are being applied to all of my controls. But I recently switched to VS 2012, and the designer is no longer working! When I debug it works perfectly but whenever I use one of my styles as follows:
<Button Name="btnForward" Height="23" Margin="10,0" Style="{StaticResource DionysusButton}" Grid.Row="2" Grid.Column="0"/>
I get the following error in the VS 2012 designer:
The resource "DionysusButton" could not be resolved.
I am clueless as to why this is happening, I have renamed my Style, and even the ResourceDictionary to no avail.
Is there a different way I should be doing this in VS 2012 or is this a problem with VS 2012?
I have found a lot of posts that say that changing the x:Name property of my AppStyles.xaml ResourceDictionary to x:Key will resolve this problem but I cannot do that as it is not a valid option for a ResourceDictionary.
Thanx in advance
-- UPDATE
I am using Marc's answer and all seems to be going well except for default styles. I have the following style:
<Style TargetType="DataGrid" x:Name="DataGridStyle"/>
And this is my main ResourceDictionary:
<ResourceDictionary x:Name="Main"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Styles/AppStyling.xaml" />
</ResourceDictionary.MergedDictionaries>
<Style TargetType="DataGrid" BasedOn="{StaticResource DataGridStyle}"/>
When I do not add the Style tag in my main ResourceDictionary it works fine, but the style is not being applied to all items obviously. When I do add it, i get the following exception:
Provide value on 'System.Windows.Markup.StaticResourceHolder' threw an exception
Ideas?
Are you trying to use the styles which are located in your app.xaml in your modules which you export into the shell using PRISM? The modules should not have a reference to your application/shell project (the startup project)? Then they maybe just don't 'know' the project, which contains the styles? Though the question is why it works in VS2010 then... Please let me know, if I misunderstood your MEF scenario, I'll adapt my answer then.
Resources and Prism is abit tricky, and I am a fan of the following approach, which I have posted before, but it might help in your case too. It is much more appropriate for a PRISM solution than placing your resources inside app.xaml:
I usually create a seperate styling project, which I reference from the projects, which I want to style. The styling project has a fixed structure like this:
For every control, I create a styling ResourceDictionary. For example for my buttons:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style x:Key="PrimaryButtonStyle" TargetType="Button">
</Style>
<Style x:Key="ToolbarButton" TargetType="Button">
<Setter Property="BorderThickness" Value="0" />
<Setter Property="Margin" Value="3"/>
<Setter Property="Background" Value="Transparent"></Setter>
</Style>
</ResourceDictionary>
In one main ResourceDictionary, I merge all the other dictionaries, in this case in the file IncaDesign.xaml, which you can see in the picture above:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="clr-namespace:Commons.Controls;assembly=Commons">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Converter/Converter.xaml" />
<ResourceDictionary Source="Styles/Button.xaml" />
<ResourceDictionary Source="BitmapGraphics/Icons.xaml" />
</ResourceDictionary.MergedDictionaries>
<!-- Default Styles -->
<Style TargetType="Button" BasedOn="{StaticResource PrimaryButtonStyle}"></Style>
</ResourceDictionary>
Notice how I defined the default styles, which are applied automatically, unless you specify otherwise. In every window or control, that you want to style, you only need to reference this one ResourceDictionary. Note the definition of the source, which is a reference to the assembly (/Commons.Styling;component...)
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/Commons.Styling;component/IncaDesign.xaml" />
</ResourceDictionary.MergedDictionaries>
<!-- Here you can added resources which belong to the UserControl only -->
<!-- For example: -->
<DataTemplate x:Kex="UcTemplate" />
</ResourceDictionary>
</UserControl.Resources>
Default styles will be set automatically now, and if you want to access a resource explicitly, you can do this, using StaticResource.
<Viewbox Height="16" Width="16" Margin="0,0,10,0">
<ContentControl Content="{StaticResource FileIcon32}" />
</Viewbox>
This is very nice solution in my opinion, which works for very complex solutions, including modular solutions, for example built with PRISM.

DynamicResource Cannot be resolved

I have been trying to learn about resources and styles, I want to create a chromeless window.
I have an example that acheives what I want via the following simple extracts of xaml.
I have a Resource set in Themes/Generic.xaml
<Style x:Key="BorderlessWindowStyle" TargetType="{x:Type Window}">
<Setter Property="AllowsTransparency" Value="true" />
<Setter Property="WindowStyle" Value="None" />
<Setter Property="ResizeMode" Value="CanResizeWithGrip" />
<Setter Property="Background" Value="Transparent" />
</Style>
I have a main window:
<Window x:Class="Project1.Shell"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Project1"
x:Name="Window"
Title="Shell" Height="576" Width="1024" Style="{DynamicResource BorderlessWindowStyle}">
<Grid></Grid>
But the style is not being applied and VS designer states it cannot resolve the resource.
The example I have been looking at does things this way and I cannot discover the difference between what I have seen done and what I am trying to do.
I thought that Genric.xaml was a 'special' resource dictionary that should be discoverable by my Window control - and I am guessing this assumption is my error.
What do I need to do to make this work? (Now I understand I can set these properties in the Window xaml directly, and I have done so and get the effect I want. BUT I really want to undersatnd using the Generic.xaml resource dictionary way as I have presented here)
best regards
John.
Themes/generic.xaml file is automatically used to find default styles for Custom Controls. In your case you have an ordinary Window with custom style. You cannot define this style in Window.Resources section, because the style should be defined at a higher level. The only higher level of Window is App.xaml, because the Window is in fact its child. That's why the solution for your question is to place the style into App.Resources section.
Thought I would add the following example in case it helps some others out. To add a resource dictionary to your app.xaml file you can add the following xaml code to the app.xaml file.
<Application x:Class="ProjectX.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:ProjectX"
StartupUri="MainWindow.xaml">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<!-- Use the Black skin by default -->
<ResourceDictionary Source="Resources\ResourceFile.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
Where 'Resources' coudl be a folder in your project that contains the Resource Dictionary file (ResourceFile.xaml).
The you can add code to your resource dictionary like such:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:ProjectX.Resources">
<!-- The Background Brush is used as the background for the Main Window -->
<SolidColorBrush x:Key="MainBackgroundBrush" Color="#FF202020" />
</ResourceDictionary>
And then finally, dynamically bind to your resource dictionary doing something like:
<Window
x:Class="ProjectX.MainWindow"
Title="Family.Show" Height="728" Width="960"
Background="{DynamicResource MainBackgroundBrush}"
ResizeMode="CanResizeWithGrip">
</Window>

Trying to use a ResourceDictionary, but styles in it come up as not found

I have a Silverlight class library, called MyClassLibrary.
In it, I have a user control, called MyControl.
Within the control I define user resources:
<UserControl.Resources>
<Style x:Key="ComboBoxStyle" TargetType="ComboBox">
(lots of xaml)
</Style>
</UserControl.Resources>
The control consumes the style like this:
<ComboBox Style="{ StaticResource ComboBoxStyle }"></ComboBox>
This all works perfectly, the ComboBox comes up with the right style, so I know the style is written correctly.
What I really want is to have the style be in a resource dictionary, so that it can be used by several different controls within this assembly. So I create, in the SAME assembly, a resource dictionary. I call it ResourceDictionary.xaml.
I move the Style definition from my user control to the resource dictionary.
So then the resource dictionary looks like this:
<ResourceDictionary
xmlns="etc" >
<Style x:Key="ComboBoxStyle" TargetType="ComboBox">
(lots of xaml)
</Style>
</ResourceDictionary>
The control's user resources now look like this:
<UserControl.Resources>
<ResourceDictionary
Source="/MyClassLibrary;component/ResourceDictionary.xaml" x:Name="resDict"/>
</UserControl.Resources>
And the control still consumes the style exactly the same way as before.
Now I know that it is finding the ResourceDictionary.xaml file, because I tried changing the "Source" attribute to NonExistentFile.xaml, and it complained that it couldn't find the file. It doesn't make that complaint with ResourceDictionary.xaml, so I presume it's finding it.
However, when I run the app, I get an error that "Cannot find a Resource with the Name/Key ComboBoxStyle".
What am I doing wrong? This seems so simple and it's not working.
Thanks in advance for any help you can give me.
Not sure if this helps exactly but I include my ResourceDictionaries in App.xaml:
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Sausage/Bangers.xaml"/>
<ResourceDictionary>
.. other stuff, e.g.
<helpers:NotOperatorValueConverter x:Key="NotOperatorValueConverter" />
</ResourceDictionary>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
Even if you don't like the approach, you can see that my Source= is different from yours.
Thank you to both of you, your answers did actually allow me to solve it.
What I really had was something like this:
<UserControl.Resources>
<Style ...> stuff </Style>
</UserControl.Resources>
To which I then added my so it looked like this
<UserControl.Resources>
<Style ...> stuff </Style>
<ResourceDictionary Source="..." />
</UserControl.Resources>
Now this compiled very beatifully but just wouldn't run. I didn't understand that I needed to use MergedDictionaries. So then I got that concept and reorganized the section and now it all works beautifully.
Thanks very much!

DataTemplates in resource dictionaries don't inherit from app.xaml styles?

I added custom named styles to the app.xaml.
I created an external resource dictionary (which I attach in the merged dictionaries of the app.xaml) and when I try to use one of the above named styles in the rcource dictionary, it says that there is no such style.
Also the default styles (i.e. unnamed styles that apply for the entire application) don't apply on the template elements.
Note: The Build Action of the templates is 'Page'.
Here is an example of how my code is written:
<Application x:Class="Application"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
ShutdownMode="OnExplicitShutdown">
<Application.Resources>
<ResourceDictionary>
<Style
x:Key="StackPanelStyle"
TargetType="StackPanel"
BasedOn="{StaticResource {x:Type StackPanel}}">
<Setter Property="Margin" Value="5"/>
<Setter Property="Orientation" Value="Horizontal" />
<Setter Property="Height" Value="40"/>
</Style>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/Templates/DataTemplate1.xaml"/>
<ResourceDictionary Source="/Templates/DataTemplate2.xaml"/>
<ResourceDictionary Source="/Templates/DataTemplate3.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>
This an example of the data template:
<DataTemplate DataType="{x:Type Entity}" x:Key="NameDataTemplate">
<Expander>
<StackPanel>
<--The following line produces: StackPanelStyle was not found.-->
<StackPanel Style="{StaticResource StackPanelStyle}">
<Label Content="Name:"/>
<TextBox Text="{Binding Name}"/>
</StackPanel>
</StackPanel>
</Expander>
</DataTemplate>
Any ideas?
Do I have to merge the dictionaries in a different way?
The code won't work well because the DataTemplate in the resource dictionary doesn't know which one is using it, it just been used. Like Hollywood mode. They compiled separately.
To make this work, you can put your style which in app.xaml in the same resource dictionary of the DataTemplate or if you don't like this coupling, you can put it in a different resource dictionary, and merge it into the DataTemplate's resource dictionary.
The Build Action for your App.xaml should be ApplicationDefinition, and the build action for your Resource Dictionary files should be Page. I'm guessing you have both of those correct because they are default (and I see that you mentioned about Page already).
I can't think of any other problem with your situation. As long as your static resources are defined in the correct order, which they appear to be, it should be able to find them when you run your application.
Edit
Debugging idea: Create a fresh resource dictionary called "TestDictionary.xaml" with a simple button style. Make sure this dictionary is in the same folder as your other dictionaries (DataTemplate1.xaml, etc.). Put a link to only TestDictionary in MergedDictionaries (comment out the others). Put a button on your startup window and apply the style. See if just that works. If it fails, you know you have an issue with your merge. If it succeeds, something about your DataTemplate might be the problem.

Resources