Wpf: Passing Parameters To A ResourceDictionary - wpf

Is there a way to pass parameters to a resource dictionary? I think that I can attach a code behind for the purpose of specifying event handlers, but unfortunately, I also need to access a reference to the parent control from the event handlers. The codebehind, I believe, can be attached by specifying an x:Class attribute for the resource dictionary in xaml, and then creating a class in the same folder, the filename for which is something like [resource dictionary name].xaml.cs.
The purpose is to seperate the code for four hierarchical data templates that I'm using in a single treeview control. The xaml for the treeview is getting a bit long and ugly to look at, so I was hoping to break it down into four resource dictionaries. Any thoughts are welcome!
Andrew

You know you can merge your Resource Dictionaries and then reference the DataTemplate within those dictionaries as needed within the TreeView.

Resource dictionaries sound like a slightly peculiar way to do this. Resource dictionaries are all about sharing instances - they let you use a single instance of something (e.g. a style, a template, a brush, or whatever) from multiple places. They're not really a mechanism for dividing your UI up to simplify individual Xaml files.
The usual mechanism for splitting overly complicated Xaml files up into a few, more manageable smaller files is the user control. (Resource dictionary merging comes into play when you already have a resource dictionary, and it's got too big. But you wouldn't normally introduce a resource dictionary just to start splitting things up. On the contrary, resource dictionaries tend to encourage overly large Xaml files, which is why dictionary merging had to be invented in the first place!)
Most of the time, when I define a data template, I make it contain nothing but a single user control. And if that becomes more complex, I'd split that user control up into more user controls.
From your description, it sounds like your Xaml file has become large because you've got four large hierarchical data templates in there. If you took the body of each template and turned it into a user control, your four templates would now become very simple - something like this:
<HierarchicalDataTemplate x:Key="t1" ItemsSource="{Binding Path=Children}">
<loc:TreeItemTypeOne />
</HierarchicalDataTemplate>
and you'd most likely no longer need to put those templates into separate files. But because the guts of each template is now in a user control, that gives you a place to put your codebehind.
You mention needing a reference to the parent control. That worries me - it makes it sound like you have too much code in your codebehind. But one thing at a time... You could solve that problem by defining a dependency property called ParentControl on your user control, and then put this in the template:
<loc:TreeItemTypeOne
ParentControl="{Binding RelativeSource=
{RelativeSource AncestorType=loc:ParentControlType}}" />
But frankly, as soon as I find myself in a position where I need this, I ask myself: how did I get myself into a position where that seemed necessary, and what can I do to fix that?

Related

Several WPF- / XAML-Files performing better than a big one?

I was talking recently to another GUI developer that was looking at one of my WPF applications. He suggested to break down my very large WPF views (files) into several smaller views. According to him this should promote loading performance as elements that are loaded from UserControls in separate files are rendered only when they actually come into view.
In my main view I currently have over 10k lines of XAML. As the main part of this view is a big TabControl with several large TabItems it would be easy to transfer the content of each TabItem into a separate file. It is true that most of the Tabs will not be used by every user or at least not directly after startup.
However, I was not able to verfy his claim by searching the web. Whenever I search the internet for WPF performance optimization I find all kinds of suggestions, but splitting up large XAML files into smaller ones was never mentioned in any way there.
For me, personally, having one big XAML per view is more comfortable and reusability is really not a problem in my case. So now I am wondering:
Would it really make sense to break my large views up into serveral small XAML files for each part that might not be needed at first?
Would it really make sense to break my large views up into serveral small XAML files for each part that might not be needed at first?
From a maintainability and reusability point of view, yes. But whether you define content of each TabItem inline or in a separate UserControl won't matter from a performance point of view.
So you won't gain any performance benefits of doing this:
<TabItem>
<local:UserControl1 />
</TabItem>
...versus doing this:
<TabItem>
<Grid>
...
</Grid>
</TabItem>
You should consider adopting the MVVM design pattern and bind the ItemsSource property of the TabControl to an IEnumerable property of a view model and use DataTemplates to define the appearance of each item rather than defining everything inline though. Doing this, only the contents of the selected TabItem will be loaded into the visual tree.

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

How to enable dynamic skinning for ConverterParameters

What's the best way to enable dynamic skinning of a WPF Application when some items requiring skin modification do not support values of type DynamicResourceExtention? In particular, our problem is that ConverterParameters require StaticResourceExtentions.
Here's our situation with ConverterParameters Using Visual Studio 2008 and WPF 3.5.
We have a custom converter which takes a value and a parameter and simply returns their product.
Very simple, works fine, and we use it for various tasks, including setting some window element sizes. For example, passing a value of "Source={x:Static SystemParameters.PrimaryScreenHeight}" and a parameter of "0.1" enables us to set an element's height to exactly 1/10 of the screen height.
Height="{Binding Source={x:Static SystemParameters.PrimaryScreenHeight},
Converter={StaticResource PctConverter},
ConverterParameter=0.1}"
where PctConverter is a resource reference to our custom converter. No problem there.
Now we want to skin the application dynamically, by extracting the ConverterParameter and putting it in a seperate resource. For example, we might want the element height to be 0.1 of the screen height in some skins, and say 0.25 of the screen height in others. Initially we thought we'd simply set the ConverterParameter to a DynamicResource, but this is not supported, so we have to set it using a StaticResourceExtension like this:
Height="{Binding Source={x:Static SystemParameters.PrimaryScreenHeight},
Converter={StaticResource PctConverter},
ConverterParameter={StaticResource OurElementHeightParameter}}"
where OurElementHeightParameter is defined in a seperate ResourceDictionary (call it MainResource.xaml) as follows:
<sys:Double x:Key="OurElementHeightParameter">0.1</sys:Double>
(where namespace is defined as xmlns:sys="clr-namespace:System;assembly=mscorlib".)
This works fine, as far as extracting the CustomParameter is concerned, but it still hasn't enabled us to change our ConverterParameter by swapping skins on the fly.
After researching this some more, in particular the following articles
How to assign wpf resources to other resource tags
Skinning using a color as staticresource for another color
Aliasing resources
what we think we need to do now is take our StaticResourceExtention and set its value dynamically behind the scenes using resource aliases.
Trying to do this, we replaced the previous OurElementHeightParameter resource with the following two resources
<sys:Double x:Key="SkinnedHeightRatio">0.1</sys:Double>
<StaticResourceExtension x:Key="OurElementHeightParameter" ResourceKey="SkinnedHeightRatio" />
which works fine, producing an identical result.
When that worked okay, we thought it would be a simple matter of placing the SkinnedHeightRatio resource in a seperate ResourceDictionary (call it Skin.xaml) and merging that with the original MainResource.xaml ResourceDictionary and we would have the dynamic skinning we are after.
But, as soon as we extract <sys:Single x:Key="SkinnedHeightRatio">0.1</sys:Single> to another ResourceDictionary we encounter build error as follows:
Unknown build error, 'Index was out of range. Must be non-negative and less than the size of the collection.'
Even more strange is that if we keep the two resources above in the same ResourceDictionary and just seperate them by putting another random resource between them, for example
<sys:Double x:Key="SkinnedHeightRatio">0.1</sys:Double>
<Thickness x:Key="SomeRandomResource" >5</Thickness>
<StaticResourceExtension x:Key="OurElementHeightParameter" ResourceKey="SkinnedHeightRatio" />
then the OurElementHeightParameter points to the SomeRandomResource directly above it and not the
resource specified in its ResourceKey property (SkinnedHeightRatio) which is only 2 lines above it...
In this case, the parameter passed to the converter is the Thickness SomeRandomResource.
All very confusing, and makes us think we are barking up the wrong tree completely. So where are we going wrong?
If anyone needs full code for an application reproducing the problem, I can post it up.
Any pointers greatly appreciated.
It might be simpler to create a multi-value converter and bind to two values for it.

How to create databinding over two xaml files?

I am trying to come to a working understanding of how databinding works, but even after several tutorials I only have a basic understanding of how databinding works. Thus this question might seem fundamental to those more familiar with silverlight. Even if it is trivial, please point me to some tutorial that deals with this problem. All that I could find simply solved this via adding the data binding on a parent page.xaml (that i must not use in my case).
For the sake of this example let us assume, that we have 5 files:
starter.cs
button1.xaml + codeBehind
button2.xaml + codeBehind
The two buttons are generated in code in the starter(.cs) file, and then added to some MapLayer
button1 my_button1 = new button1();
button2 my_button1 = new button2();
someLayer.Children.Add(my_button1);
someLayer.Children.Add(my_button2);
My aim is to connect the two buttons, so that they always display the same "text" (i.e. my_button1.content==my_button2.content = true;). Thus when something changes my_button1.content this change should be propagated to the other button (two way binding).
At the moment my button1.xaml looks like this:
<Grid x:Name="LayoutRoot">
<Button x:Name="x_button1" Margin="0,0,0,0" Content="{Binding ElementName=x_button2, Path=Content}" ClickMode="Press" Click="button1_Click"/>
</Grid>
But everthing that i get out of that is a button with no content at all, it is just blank as the binding silently fails.
How could I create the databinding in the context I described? Preferably in code and not XAML ;)
Thanks in advance
The chunk of documentation you need to read is this: XAML Namescopes
Your button1 xaml has a binding looking for an element with the name "x_button2". However in a real application there can be many controls which in turn have nested controls. All of these controls have all manner of UI elements some of which may have names.
It would be impossible to get anything done if all names throughout the entire application had be unique. Yet that would need to be true if it were for your button1 to be able to hunt down the existence of another control somewhere in the visual tree outside of that which it actually knows (its own xaml).
Hence each loaded Xaml document exists in its own "namescope" and the search for other elements with other names is limited to that "namescope".
The are various solutions to this problem depending on what you real requirements are as opposed to the simplified problem in your question.
Typically you give each of your controls a DependencyProperty to which the inner button Content property binds. In "MapLayer" as call it, could then bind the propert on one of your button controls to the other.

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