How can I programmatically access System.Windows.ResourceDictionary? - wpf

I am trying to implement Load/Save annotations (complex children, not ink strokes, like an editable text box) of an InkCanvas and when I use XamlReader.Load I get an exception where it is trying to load something into the dictionary that is already there. I believe I need to access the dictionary and either check to see if something is already there or just clear it out.
My question is, how can I access the resource dictionary programmatically or is there a better way to handle this?

All FrameworkElement derived classes include a Resources property you can use to access the resource dictionary for that element. You can also directly access Application.Resources if the resource is defined at the Application level.

Related

What are the options to control the DynamicResource references?

Let's presume, that we want to create a UserControl and make it able to be styled by the caller.
What are the options we have in such a case?
As I understand we can use DynamicResources in xaml of the UserControl.
We can expose some DPs and bind the UserControl's elements to them.
Sometimes I face the situations when I use a UserControl but it can't be rendered on the screen. If this happens, I start to explore the solution and try to understand what resources can't be found by the UserControl.
This leads to the significant loss of time.
How can we prevent such the troubles?
A solution that I see is to write some code inside those UserControls which use DynamicResources with intention to try to find the required resources and throw an exception. It can simplify the debugging.
The more resources we have in a solution, the more headache we suffer from.
You should use the dependency properties and then the consumer/host of the control can bind dynamic resources to them either declaratively or programmatically.
Don't go looking for dynamic resources yourself, this introduces a dependencies into your control, instead you should work with what you are given. You can default to in built styles if you're not given anything.
The only time you should think about defaulting to externally defined dynamic resources is when you've got a really complex control (like a data grid) and you also supply theme assemblies (like control vendors do). Other than that, using the DP approach is more manageable and easier for you to document.
In any case you shouldn't throw exceptions if dynamic resources are not found. If you are programmatically looking for a resource and fail to find it then have a default. If you are binding to a dynamic resources source declaratively in XAML then either let the normal binding error occur if it isn't found, or use a proxy dependency property combined with a data trigger

Can the WPF ResourceDictionary return a new instance for each request

We're using ResourceDictionaries to store layout information for our app. The lazy initialisation is great because we can grab the required layout for an element only when that element is created. The problem is that each element gets the same instance from the ResourceDictionary for each one that shares the layout (or the same one if it goes out of scope and is needed later).
We could store templates in the dictionary then it doesn't matter if they're shared but we have quite a nice system going if it wasn't for this caching behaviour.
Is there a way to change this behaviour of the dictionary or am I going to have to write my own class which creates items from the XAML on demand?
Try applying x:Shared="false" attribute. Each resource should then get seperate copy.

Difficulties with ThemeInfo in WPF?

I am stuck with ThemeInfo attributes inside my AssemblyInfo.cs file. I am trying to write a custom control. The custom control is in a dll called "MyCustomControls.dll". Futhermore the control itself derives from another custom control which is inside another dll called "MyAnotherCustomControls.dll".
I read on MSDN that ThemeInfo must be declared with 2 parameters responsible for control theme specific location and generic specific location, though I have no idea what is "theme" and what "generic". How can I understand those two better?
If somebody could explain me an example from scratch what is "generic" and what "theme". Futhermore when to use "generic" or "theme". How are those two used by WPF system at all? I really need an explaination in plain english so please save your time if you are about to post me an MSDN link. I read msdn documentation about ThemeInfo and I dont get it.
Also can somebody please tell me how to just by using ThemeInfo tell my "MyCustomControls.dll" to use dictionary resources defined in "MyAnotherCustomControls.dll"? Is that even possible to do just by ThemeInfo or do I have to deal with MergedDirectories in "MyCustomControls.dll"? I would like the WPF system take care of locating resources so that I can use style keys from "MyAnotherCustomControls.dll"without the need to add merged directory in "MyCustomControls.dll".
I read on MSDN that ThemeInfo must be declared with 2 parameters responsible for control theme specific location and generic specific location, though I have no idea what is "theme" and what "generic". How can I understand those two better?
Basically the WPF framework will look for a xaml resource whose name matches the OS theme name. So if you're running on XP with the blue theme that will be "luna.normal.xaml". If it does not find one with that exact name, it will look for the "generic.xaml". In actuality I think they look for the "classic.xaml" first if they don't find one that matches the OS specific one and then they look for generic.xaml. You can think of the generic.xaml as the default resources.
The ThemeInfo attribute simply tells WPF where those resources are defined. There are 3 options:
None - You aren't providing either the "theme" or "generic" resources. This is really an optimization so the WPF framework doesn't bother looking for them. You wouldn't typically use this for the GenericDictionaryLocation but you might use this for the ThemeDictionaryLocation in case you weren't going to define OS theme specific resources (i.e. you didn't want your control to look different under different OS themes). Typically control vendors will define a resource dictionary for each possible OS theme so that the controls look consistent with the other controls and windows running in that operating system.
ExternalAssembly - This means that you are defining a separate assembly for the resources. So if you look at the WPF framework you will see that they use this for the PresentationFramework assembly for the ThemeDictionaryLocation. Then they defined a separate assembly for each OS theme they want to support (e.g. PresentationFramework.Aero.dll, PresentationFramework.Luna.dll, etc.). The name of the assembly it will search for is the name of the defining assembly plus the name of the theme.
SourceAssembly - This means that the resources are defined within the assembly itself. So in that assembly you would have a "themes" folder which contains the resource dictionaries.
This article on MSDN about control authoring really isn't that bad about providing information about this.
Also can somebody please tell me how to just by using ThemeInfo tell my "MyCustomControls.dll" to use dictionary resources defined in "MyAnotherCustomControls.dll"? Is that even possible to do just by ThemeInfo or do I have to deal with MergedDirectories in "MyCustomControls.dll"? I would like the WPF system take care of locating resources so that I can use style keys from "MyAnotherCustomControls.dll"without the need to add merged directory in "MyCustomControls.dll".
You can't use ThemeInfo to tell WPF that it should look for your resources in some arbitrary assembly. That being said if you don't set or override the DefaultStyleKey, as is typically done when defining a custom control, then it should continue to use the resources for the base class that did have its DefaultStyleKey set/overridden for the default resources.
It should be noted however that local Style resolution (i.e. when the Style property of your control is not set and WPF looks from the place at which the element is sited and walks up the visual/logical tree looking for a Style that might implicitly affect that element) will always look for Style whose Key matches the exact type of the class. So if have a Style whose TargetType (and therefore the default Key when that is placed in a ResourceDictionary) is TextBox defined in the Resources of your Window, it will affect all TextBox instances within that Window (unless they have a Style closer in the visual tree - i.e. defined in the resources of an element between itself some ancestor - or its Style property is set). However, if you have a class that derives from TextBox (e.g class MyTextBox : TextBox) then it will not pick up/use that Style. Instead it will be looking for a Style whose TargetType/Key is typeof(MyTextBox). One way to hack around that would be to set the Style property to a DynamicResource to the base type. e.g.
public MyTextBox()
{
this.SetResourceReference(StyleProperty, typeof(TextBox));
}
Basically this sets a local value on the control's Style property that is doing a dynamic resource lookup for a Style whose Key (and therefore TargetType for Styles where the x:Key is not set) is the specified type (TextBox in this case).
As you noted the alternative is to define the xaml files locally in your assembly for each theme that the base class' assembly defines and then add a ResourceDictionary to its MergedDictionaries that uses the pack uri notation to reference the resources in the base class's assembly. If you are setting the DefaultStyleKey then you will likely need to define a Style whose TargetType is your class' type in each of those ResourceDictionaries and then set the BasedOn to a StaticResource where the resource key is the type of the base class. It sounds though like you shouldn't need to do this.

Set the Style of a control programatically in Silverlight 4?

I am new to Silverlight, but I couldn't find anything about this when I googled it.
I have a button that I am trying to set the style programatically. I have the style defined in a XAML file and I want to pull the style into C# so I can dynamically create a button and assign it this style. So far, this is what I am trying:
button.Style = (Style)Resources["CloseButtonStyle"];
However, it just makes the button have no style. Is there an easy way to do this? I feel like this should be obvious, but I can't get it to work.
You are assuming that your Resources property on the current object is the one that contains the defined style. However, I assume, given the symptoms of your issue, that CloseButtonStyle is actually defined further up the control hierarchy.
Instead, you need to traverse your control hierarchy until you find the resource (or if you know the object that defines it, just refer directly to that object). Unfortunately, Silverlight doesn't include FindResource call like WPF, but it's not too difficult to implement your own.
I can call button1.Style = (Style)Resources["NonExistentKey"]; and it makes my button have no style at all as well, point being that the resource is probably not being found, you won't get an exception.
You directly access the Resources property, but is the style really in the immediate resource dictionary of your Window/UserControl/whatever-you-have?

Modify XAML string dynamically

I want to add/remove some part of XAML dynamically i.e. from code behind file in C#.how to Add any specific XAML string on specified location (means under some tag) from .cs file. Please help.
XAML is xml you can use XmlReader and XmlWriter or any other of the XML serialization mechanismn of .NET to write/read XML (XMlDocument is probably the best approach here to modify existing xml). ALso there are the XamlReader and XamlWriter class that allow ou to (de)serialize any object graph from/to XAML automatically. If you can use .NET 4.0, you have even more fine grained possibilities to athor XAML because it has a new XAML stack. Use this as a starting point.
What is it that modifying the XAML will do for you?
If you just want to change the appearance of your WPF application (perhaps by adding some more content at certain locations), it will most likely be easier to do this by referencing the objects in question. So, if you need to add some text to a button, name the button with x:Name="myButton" and in code set: myButton.Content = "Click Me"
XAML is really a technology for constructing object hierarchies. Pretty much every element in the XAML corresponds to a .NET CLR class. When loaded, these classes are instantiated nd populated according to the attributes used in the XAML. Once loaded, the XAML has finished it's job and is essentially unloaded/unavailable.
You might need to do something beyond this, but from your brief question it doesn't seem like it. I would just work on the object model and leave the XAML be.

Resources