Merged Resource Dictionaries of Windows does not reflect on child controls - c#

Resource dictionary merged to the Window as given in the code below.
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="DefaultTheme.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
I had created a custom control for context menu and had created the corresponding style in the DefaultTheme.xaml file. Even though at the window level it had the resource dictionary merged, the styles were not accessible for the custom controls.
Since it was custom control I had to merge the dictionary in the C# constructor like this -
const string defaultThemePath = "DefaultTheme.xaml";
var dictionary = new ResourceDictionary { Source = new Uri(defaultThemePath, UriKind.Relative) };
Resources.MergedDictionaries.Add(dictionary);
If the resource dictionary is merged, it should be available for child controls is an expectation. Is my understanding wrong about merged resource dictionary?
Edit
As #Rohit Vats has rightly pointed, my custom control is context menu and it is not part of the visual child of the window. Hence it does not have the resource dictionary inherited.

I just quickly check by putting one SolidColorBrush in random ResourceDictionary and merge it under App resources and use that resource from ContextMenu and ContextMenu was able to access the resource.
From MSDN, StaticResource lookup behaviour works like this:
The lookup process checks for the requested key within the resource
dictionary defined by the element that sets the property.
The lookup process then traverses the logical tree upward, to the
parent element and its resource dictionary. This continues until the
root element is reached.
Next, application resources are checked. Application resources are
those resources within the resource dictionary that is defined by the
Application object for your WPF application.
As evident from the above assertion, it looks for logical parent and not Visual parent and in case resource is not found anywhere, it looks for resource under App resources.
So, your case for ContextMenu will work if you merge resources under App resources.

Related

Accessing a DynamicResource in code-behind [duplicate]

I have a DataTemplate defined in a xaml file that I want to access via C# code.
Can anyone please tell me how can I access it?
I added a new ResourceDictionary file and its name is Dictionary1.xaml.
I have a data template such as:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<DataTemplate x:Key="mytemplate">
<TextBlock Text="Name:" Background="Blue"/>
</DataTemplate>
</ResourceDictionary>
not I have a ListBox called listBox1 and I want to assign it to it's Itemtemplate property
but I'm not getting how can i do it?
Since Application.Current was null in my case, I've ended up using this:
var myResourceDictionary = new ResourceDictionary();
myResourceDictionary.Source =
new Uri("/DllName;component/Resources/MyResourceDictionary.xaml",
UriKind.RelativeOrAbsolute);
and then getting the specified key I needed by using
myResourceDictionary["KeyName"] as TypeOfItem
(source)
Where exactly are you defining it?
If you define it in the ResourceDictionary of your object, then
Application.Current.Resources[typeof(yourDataTemplateTargetType)]
should work. If you are defining it as a member of something else, like say, an ItemsControl, you need to get a handle to the ItemsControl instance and call the ItemTemplate property.
Edit: Ok, I think we're getting somewhere. So you are defining a ResourceDictionary in its own file. Before you can use it in your UI and access it from your code behind, you need to merge that ResourceDictionary into your application. Are you doing this?
If you are, then the next step is to get this resource. Each FrameworkElement has a method called FindResource. This method is great because it walks up the ResourceDictionary tree and attempts to locate the resource with the key. So, if you want to access this resource from a UserControl, you can do the following in the code behind:
FindResource(typeof(yourDataTemplateTargetType));
If this doesn't work for you, please show us exactly how you are declaring this resource dictionary and how it is getting merged into your application's resources.
If you for example have a template for Button in your resource dictionary in the App.xaml file you can access it using the following code:
Application.Current.Resources[typeof(Button)]
If you have merged resource dictionary using code like below
<Window x:Class="MainWindow">
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="DefaultStyle.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
</Window>
Then, instead of Application.Current.Resources["ResourceKey"] you need to specify Control name (in this case MainWindow) also like below
var style = Application.Current.MainWindow.Resources["ResourceKey"];
// OR
var style = Application.Current.MainWindow.TryFindResource("ResourceKey");
If you're getting the resources within the same project, try this:
yourControl.Style = FindResource("YourResourceKey") as Style;
Otherwise, try this:
ResourceDictionary res = (ResourceDictionary)Application.LoadComponent(new Uri("/ProjectName;component/FolderName/ResourceDictionaryName.xaml", UriKind.Relative));
yourControl.Style = (Style)res["YourResourceKey"];
You can access a resource dictionary you added to your project as follows:
var rd = new ResourceDictionary();
rd.Source = new Uri("ms-appx:///Dictionary1.xaml");
Then you can access a resource stored in the resource dictionary like so:
someObject.Property = rd["mytemplate"];
NOTE:
You will have to modify the URI to the resource dictionary according to the location you created it relative to the project's base directory.
I found the answer here
https://learn.microsoft.com/en-us/dotnet/framework/wpf/advanced/how-to-use-a-resourcedictionary-to-manage-localizable-string-resources
create a ressource dictionary "ColorResources.xaml"
add to it:
Blue
edit your app.xml and add:
use the color from your code
var color = (System.Windows.Media.Color)Application.Current.FindResource("ButtonColor1");
and voilĂ 
ps : admin can you fix the code? it does not show up, thanks
Any of the above approaches work getting the resource based on the location, if you are following MVVMm I would recommend doing it this way:
create a Service like ProvideDataTemplateService, (to create a service usual inherit from Behavior )
Use Container of Your choice to inject this service where you would like to have aces to DataTemple.
For the life of me, although I was able to load my resource dictionary via XAML, I wasn't able to load it via "code behind" (in C#).
So I resorted to have a view loading it: (MyView.xaml)
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/My.Proj;component/My/Path/myResourceDictionary.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
Then access it in my UT by instanciating that view and accessing it:
new MyView().Resources.MergedDictionaries[0]
Hacky, but works.
Just to add another answer here in case you don't have a view or Application.Current is null. I realize this is probably uncommon but in my case I have an addin to a parent application and Application.Current is null; I also want to pass one of my resources to the parent as an ImageSource so I don't have a XAML view created to get resources from directly.
You can also make the dictionary into a code behind creatable object. Just set the x:Class attribute in the XAML and then create a .xaml.cs file in the code behind. Your updated XAML, lets call the code file MyDictionary.xaml, would then look something 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"
x:Class="Some.Namespace.MyDictionary"
mc:Ignorable="d">
...Resources...
</ResourceDictionary>
And the code behind (MyDictionary.xaml.cs) would look something like this:
using System.Windows;
namespace Some.Namespace
{
public partial class MyDictionary : ResourceDictionary
{
public MyDictionary()
{
InitializeComponent();
}
}
}
Don't forget to call InitializeComponent() as that's what loads the resources. Actually not sorry, see edit below
After you do this you can simply construct an instance of the class anywhere in code and reference the resources by key like this:
var dictionary = new MyDictionary();
var resource = dictionary["whateverKey"] as WhateverResourceType;
Thanks to this post for leading to the idea.
EDIT
Just ran into one potential issue with this. I got a 'Cannot re-initialize ResourceDictionary instance' exception with this setup on some of my controls. On further research this could be related to calling InitializeComponent in the constructor. Instead I removed the constructor from the code behind and added a static method to get an initialized instance as follows:
public static MyDictionary ConstructInitializedInstance()
{
var dictionary = new MyDictionary();
dictionary.InitializeComponent();
return dictionary;
}
You could also just create and initialize in your code behind.

Reference resourceDictionary from parent .xaml file

I'm learning WPF. I'm trying to reference ResourceDictionary in App.xaml from AboutView.xaml to apply the materialview style.
Tried pack uri way and also "../" but VSS is still complaining "An error occurred while trying to find App.xaml".
The folder structure:
What am I doing wrong?
AboutView.xaml
App.xaml
To ASh:
So with referenced, my materialview button shows nicely.
Relying on App.xaml to apply materialview style across all Windows doesn't work if I don't reference it explicitly. The button is stripped of its style.
The app.xaml isn't a ResourceDictionary, but contains the definition for your Application (it starts with an <Application>element, not a <ResourceDictionary>). You can move your resources out of the app.xaml into their own ResourceDictionary and then reference that dictionary from your view and other elements as needed.

Approach to using resources in a user control without relying on App.xaml

I converted an application to a DLL library where my main window became a user control. I was using the method of creating a System.Windows.Application object manually to store my resources but I want move away from that and have my user control be self sufficient, so I can simply do something like:
CustomUserControl control = new CustomUserControl ( object_to_pass);
It will then take care of everything else internally. The basic layout of the control is a frame that hosts multiple pages, like a wizard style app.
I am having two main issues:
Setting up references to the view models
I thought that instead of using System.Windows.Application.FindResource which I extensively used, I will use a similar function on the user control class and pass a reference to my user control around via a singleton.
To do this I use mvvm-light's SimpleIoc container in a class called 'ViewModelLocator' to keep track of all the view models. Problem is, this was a resource in App.xaml loaded from the datacontext binding of the user control.
This cannot be done anymore as the user control itself has to instantiate the resources containing it further along in its own xaml:
<UserControl x:Class="WUP.Views.WarmUpPluginUserControl"
mc:Ignorable="d"
...
...
<!--This will not work-->
DataContext="{Binding Source={StaticResource Locator}, Path=MainWindowLogic}">
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Path/To/ViewModelLocator/Resource.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
Now I have to instantiate the ViewModel locator in the user control code behind and set it up as a resource with Resources.Add. This forces me to switch to dynamic resource for all references to the ViewModel locator from all other views (Pages). Not only does this cause issues described further on, its ugly as I can no longer access member function with the path like I used to:
DataContext="{Binding Source={StaticResource Locator}, Path=MainWindowLogic}">
Referencing resources from xaml, Dynamic vs Static
The resources I use are brushes, colours, templates and converters, each in their own resource dictionary, and I add them in the right order to avoid dependency issues.
The method in the first part works ok for accessing resources from the ViewModel via the reference to the user control in the singleton. The problem now is how to have the resources loaded in each view of the app. I tried the brute force method of sticking them all in Page.Resources or UseControl.Resources but that gave me resource not found errors in some pages despite them existing there. I am looking into why this happens but I am not sure
I then tried Dr.WPF's method of creating a singleton class that you can use to create a single instance of resources and expose them as a dependent property. This forces me to use dynamic resources again for all my views.
This is fine for all my resources except the converters, and I get errors for all converters originally referenced in this way:
Visibility="{Binding Functions.DictatesActions, Converter={StaticResource BooleanToVisibilityConverter}, UpdateSourceTrigger=PropertyChanged}"
So I don't know how to deal with this is the dynamic scenario.
I am seriously thinking to abandon this approach and just use System.Windows.Application to store all my resources, despite it potentially causing issues with other user controls in the hosting application (winforms). Please let me know if there is a better way!
I finally managed to fix my issues:
Setting up references to the view models
Here I just had to do it all from the code behind. As I mentioned I used a ViewModelLocator to keep track of all my VMs, so I set up the references as resources in the actual user control constructor:
Resources["Start"] = view_model_locator.Start;
Resources["SelectUnit"] = view_model_locator.SelectUnit;
Resources["HardwareChecks"] = view_model_locator.HardwareChecks;
Resources["ConfigurationChecks"] = view_model_locator.ConfigurationChecks;
...
I then included the reference to the user control in the ViewModel locator as static property:
ViewModelLocator.WarmUpPluginUserControl = this;
Then I could access it from the other views in their code behind like this:
DataContext = ViewModelLocator.WarmUpPluginUserControl.FindResource("Start");
I could also use it in the VMs in the same way that I used the Application.Current.FindResource(). It's not the most elegant solution, but it worked
Referencing resources from xaml, Dynamic vs Static
Here I stuck with the brute force method of including all the resources at the top of every page:
<WUP:WUPPage.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/WarmUpPlugin;component/Resources/Colors.xaml"/>
<ResourceDictionary Source="pack://application:,,,/WarmUpPlugin;component/Resources/Styles.xaml"/>
...
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
This did cause issues for me in the beginning where I had resource not found errors, but this was due to some of my dictionaries having dependencies other ones so I had to add them in to the relevant dictionaries via MergedDictionaries.
I did not notice this dependency issue when the application was standalone as all the resources required were already loaded in the application scope.
I intend to replace this with the Dr WPF method, but I would still have to change all my XAML references to dynamic from static then deal with the converters not being able be accessed via dynamic resource references.

WPF Resource file attached to Style file: Error -> The name 'InitializeComponent' does not exist in the current context [duplicate]

Is it possible to set code behind a resource dictionary in WPF. For example in a usercontrol for a button you declare it in XAML. The event handling code for the button click is done in the code file behind the control. If I was to create a data template with a button how can I write the event handler code for it's button click within the resource dictionary.
I think what you're asking is you want a code-behind file for a ResourceDictionary. You can totally do this! In fact, you do it the same way as for a Window:
Say you have a ResourceDictionary called MyResourceDictionary. In your MyResourceDictionary.xaml file, put the x:Class attribute in the root element, like so:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="MyCompany.MyProject.MyResourceDictionary"
x:ClassModifier="public">
Then, create a code behind file called MyResourceDictionary.xaml.cs with the following declaration:
namespace MyCompany.MyProject
{
partial class MyResourceDictionary : ResourceDictionary
{
public MyResourceDictionary()
{
InitializeComponent();
}
... // event handlers ahead..
}
}
And you're done. You can put whatever you wish in the code behind: methods, properties and event handlers.
== Update for Windows 10 apps ==
And just in case you are playing with UWP there is one more thing to be aware of:
<Application x:Class="SampleProject.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:rd="using:MyCompany.MyProject">
<!-- no need in x:ClassModifier="public" in the header above -->
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<!-- This will NOT work -->
<!-- <ResourceDictionary Source="/MyResourceDictionary.xaml" />-->
<!-- Create instance of your custom dictionary instead of the above source reference -->
<rd:MyResourceDictionary />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>
I disagree with "ageektrapped"... using the method of a partial class is not a good practice. What would be the purpose of separating the Dictionary from the page then?
From a code-behind, you can access a x:Name element by using:
Button myButton = this.GetTemplateChild("ButtonName") as Button;
if(myButton != null){
...
}
You can do this in the OnApplyTemplate method if you want to hookup to controls when your custom control loads. OnApplyTemplate needs to be overridden to do this. This is a common practice and allows your style to stay disconnected from the control. (The style should not depend on the control, but the control should depend on having a style).
Gishu - whilst this might seem to be a "generally not to be encouraged practice" Here is one reason you might want to do it:
The standard behaviour for text boxes when they get focus is for the caret to be placed at the same position that it was when the control lost focus. If you would prefer throughout your application that when the user tabs to any textbox that the whole content of the textbox was highlighted then adding a simple handler in the resource dictionary would do the trick.
Any other reason where you want the default user interaction behaviour to be different from the out of the box behaviour seems like good candidates for a code behind in a resource dictionary.
Totally agree that anything which is application functionality specific ought not be in a code behind of a resource dictionary.
Adding on....these days, with the advent of {x:Bind ...}, if you want to put your DataTemplate into a shared ResourceDictionary file, you are required to give that file a code behind.
XAML is for constructing object graphs not containing code.
A Data template is used to indicate how a custom user-object is to be rendered on screen... (e.g. if it is a listbox item) behavior is not part of a data template's area of expertise. Redraw the solution...

how to create skins for a GUI in WPF?

I was wondering how I should go about creating custom settings for all the color schemes and such. I know I can create styles for individual components or parts..but how should I create a set of skins?
for example, right now I'm using a maroon colored gradientbrush in a lot of subcontrols. However, I'm sure that people other than me will hate the color scheme.
I know that I can create a dependency property on my top level control for the color and then bind the individual parts that need that color to that dependency property. However, there will need to be many properties. Should I just create a separate style object that contains all these properties and place it as field in my user control?
I'm just wondering if there are other ways of doing this in WPF. For example, I guess there could be some way of doing this in xaml or utilizing some built in class in the default libraries.
You can do this by creating new resource dictionary and define there colors and control templates for your controls.
Example you can find in WPF Themes project (download link).
You can change your style by changing resource dictionary, e.g:
<Application x:Class="ThemesSample.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="Window1.xaml">
<Application.Resources>
<ResourceDictionary Source="ExpressionDark.xaml"/>
</Application.Resources>
</Application>
If you want to change theme at runtime you should use following code:
ResourceDictionary dict = new ResourceDictionary();
dict.Source = new Uri("BureauBlack.xaml", UriKind.Relative);
this.Resources.MergedDictionaries.Add(dict);

Categories

Resources