WPF: How do I properly reference a style in a resource dictionary? - wpf

I've created a separate styles.xaml file which looks like this:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style x:Key="NewButtons" TargetType="Button">
<!-- style code here -->
</Style>
</ResourceDictionary>
In my App.xaml file, I'm adding it as a resource dictionary like so:
<ResourceDictionary x:Key="CustomStyles">
<ResourceDictionary.MergedDictionaries >
<ResourceDictionary Source="pack://application:,,,/styles/styles.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
However, now I'm not too sure how to properly reference it as a style in one of my windows. I tried creating a button like this but it didn't work:
<Button Style="{StaticResource CustomStyles}" />
It gives me an error warning that says "An object of the type 'System.Windows.ResourceDictionary' cannot be applied to a property that expects the type 'System.Windows.Style'"
I get what this error means and I'm sure the fix is someone quite small, I just don't know enough of XAML syntax yet to know what that is.

You're referencing the ResourceDictionary as the Style instead of the Key for the Style.
Try this:
<Button Style="{StaticResource NewButtons}" />

Related

WPF - how to reference a style in a resource when the resource dictionary has a key set

I have created a user control that needs to reference an external resource dictionary file. A style within this resource file is then used against a textbox in the user control.
The external resource dictionary file is as follows:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style x:Key="ValidatedTextboxStyle" TargetType="{x:Type TextBox}">
...
</Style>
I then import this into the user control as follows: (with the long file location removed)
<Control.Resources>
<ResourceDictionary x:Key="Test" Source="..." />
<common:StringCollapseVisibilityConverter x:Key="StringCollapseVisibilityConverter" />
</Control.Resources>
The WPF designer forces me to give it a "key" due to the other resource that is referenced.
Without the dictionary having a name, you would normally reference it like:
Style="{StaticResource ValidatedTextboxStyle}"
How would I reference the style that has name "ValidatedTextboxStyle" within the external resource file taking into account that the imported resource dictionary is given the key name "Test"?
Merged the dictionary in your control and you can use it like earlier via StaticResource.
<Control.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="..." />
</ResourceDictionary.MergedDictionaries>
<common:StringCollapseVisibilityConverter
x:Key="StringCollapseVisibilityConverter" />
</ResourceDictionary>
</Control.Resources>
Also, you can omit setting x:Key now on resource dictionary since all the defined resources in resource dictionary are merged into your control resources.
Now, you can use like earlier:
Style="{StaticResource ValidatedTextboxStyle}"

How can I access a dynamic resource from a different assembly inside a ViewBase

I am working with a Xaml file that is a custom view derived from a ViewBase, and I would like to access a DynamicResource that is in a different assembly. I have seen that it is possible to use something like:
<Application.Resources>
<ResourceDictionary
Source="/mylib;Resources/MyStyleDictionary.xaml" />
</Application.Resources>
However I'm dealing with a xaml file that looks something like:
<myLib:ViewBase>
<Grid>
<Button>
Style="{DynamicResource MyButtonStyle}" // I want this style to come from a different assembly
</Button>
</Grid>
</myLib:ViewBase>
How can I do this?
It's important to understand the difference between Dynamic and Static resources. What's the difference between StaticResource and DynamicResource in WPF?
But to answer the question:
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/SomeOtherAssembly;Resources/SomeOtherDictionaryWithMyButtonStyleKey.xaml" />
<ResourceDictionary Source="/mylib;Resources/MyStyleDictionary.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
The resource is being referenced dynamically, so merging SomeOtherDictionaryWithMyButtonStyleKey.xaml before merging in MyStyleDictionary.xaml should work.

Why can't I find DataTemplates in merged resource dictionaries?

In my MainWindow.xaml, I have the following reference to a ResourceDictionary:
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="MainSkin.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
In MainSkin.xaml, I define a datatemplate:
<DataTemplate x:Key="TagTemplate">
...
</DataTemplate>
Deeper within my application, I attempt to use this data template:
<ContentControl DataContext="{Binding Tag}" ContentTemplate="{StaticResource TagTemplate}"/>
The code compiles successfully, but when I attempt to load a Page or UserControl that contains this StaticResource, I get an exception saying that the TagTemplate can't be found.
What am I doing wrong?
In order to access the contents of a resource defined in a XAML file, you need to "include" that XAML file in each page and control that uses it. So every XAML files will need to have the MergedDictionaries entry that you have in MainWindow.xaml.
Alternatively you can add those merge dictionaries to App.xaml and those resources are included implicitly:
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="MainSkin.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
Are you using that StaticResource in the same Window where it is declared? Otherwise I think that you cannot have access to that.

Add collection or array to wpf resource dictionary

I've search high and low and can't find an answer to this. I have two questions
How do you create an array or collection in XAML. I've got an array I want to stick in there and bind to a combo box. My first idea was to put an ItemsControl in a resource dictionary, but the ItemsSource of a combo box expects IEnumerable so that didn't work.
Here's what I've tried in my resource dictionary and neither works
<ItemsControl x:Key="stateList">
<sys:String>AL</sys:String>
<sys:String>CA</sys:String>
<sys:String>CN</sys:String>
</ItemsControl>
<ItemsControl x:Key="stateList2">
<ComboBoxItem>AL</ComboBoxItem>
<ComboBoxItem>CA</ComboBoxItem>
<ComboBoxItem>CN</ComboBoxItem>
</ItemsControl>
and here's how I bind to it
<ComboBox SelectedValue="{Binding Path=State}" ItemsSource="{Binding Source={StaticResource stateList2}}" >
</ComboBox>
EDIT: UPDATED
I got this first part to work this way
<col:ArrayList x:Key="stateList3">
<sys:String>AL</sys:String>
<sys:String>CA</sys:String>
<sys:String>CN</sys:String>
</col:ArrayList>
However, I'd rather not use an array list, I'd like to use a generic list so if anyone knows how please let me know.
EDIT UPDATE: I guess XAML has very limited support for generics so maybe an array list is the best I can do for now, but I would still like help on the second question if anyone has an anser
2nd. I've tried referencing a merged resource dictionary in my XAML and had problems because under Window.resources I had more than just the dictionary so it required me to add x:Key. Once I add the key, the system can no longer find the items in my resource dictionary. I had to move the merged dictionary to Grid.Resources instead. Ideally I'd like to reference the merged dictionary in the app.xaml but I have the same problem
Here's some sample code. This first part required an x:key to compile because I have converter and it complained that every item must have a key if there is more than one
<UserControl.Resources>
<win:BooleanToVisibilityConverter x:Key="VisibilityConverter" />
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/ResourcesD.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
I had to change it to this
<UI:BaseStep.Resources>
<win:BooleanToVisibilityConverter x:Key="VisibilityConverter" />
</UI:BaseStep.Resources>
<Grid>
<Grid.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/ResourcesD.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Grid.Resources>
</Grid>
Thank you
As far as I understand your problem you want to bind a ComboBox (or a ListBox) with an array of items, right? If you want items from some external data source, you can just make use of handy DataContext property. Search MSDN for more on this. However, if you do want a manual collection, do it this way:
Create your own class:
public class StringCollection : ObservableCollection<string> { }
and now use it like this:
<Window.Resources>
<local:StringCollection x:Key="stringCollection">
<sys:String>Hello</sys:String>
<sys:String>World</sys:String>
</local:stringCollection>
</Window.Resources>
...
<ListBox
Margin="15"
ItemsSource="{StaticResource stringCollection}" />
Or, if you want more generic collection create a class like this:
public class ObjectCollection : ObservableCollection<object> { }
and use it like this:
<local:ObjectCollection x:Key="objectCollection">
<sys:String>Hello</sys:String>
<TextBlock>World</TextBlock>
<sys:Int32>12345</sys:Int32>
</local:ObjectCollection>
...
<ComboBox
Margin="15"
ItemsSource="{StaticResource objectCollection}" />
You may also want to make use of some in-built classes like Int32Collection that implements IEnumerable. You can use them directly as a resource.
The Resources property (of any FrameworkElement like Window, UserControl, or Application) is of type ResourceDictionary not collection of resource dictionaries! so you can't do like this:
<UserControl.Resources>
<!-- The first RD -->
<!--<ResourceDictionary>
<win:BooleanToVisibilityConverter x:Key="VisibilityConverter" />
</ResourceDictionary>-->
<!-- Second RD!!! -->
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/ResourcesD.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
Instead do like this:
<UserControl.Resources>
<!--
There should be only 1 main RD,
Merge other RDs, if any
-->
<ResourceDictionary>
<!-- First Resource -->
<win:BooleanToVisibilityConverter x:Key="VisibilityConverter" />
<!-- Second Resource -->
<ResourceDictionary.MergedDictionaries>
<!-- Now, there can be multiple RDs -->
<ResourceDictionary Source="/ResourcesA.xaml" />
<ResourceDictionary Source="/ResourcesB.xaml" />
<ResourceDictionary Source="/ResourcesC.xaml" />
<ResourceDictionary Source="/ResourcesD.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
Hope this helps.
Regards,
Mihir Gokani
Please correct me if I'm wrong but I think you want something like this?
<Grid.Resources>
<local:MyCustomCollection x:Key="local:MyCustomCollection"/>
</Brid.Resources>
At the top of your window you'd have a property:
xmlns:local="clr-namespace:MyNamespace"
And inside your code you'd have:
MyCustomCollection custCol = MyGrid.Resources["MyCustomCollection"] as MyCustomCollection;
Binding would happen on a control with a property something like this:
ItemsSource="{StaticResource MyCustomCollection}"
For the resources, you just need to mover your additional converter into the newly declared ResourceDictionary:
<App.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/ResourcesD.xaml" />
</ResourceDictionary.MergedDictionaries>
<win:BooleanToVisibilityConverter x:Key="VisibilityConverter" />
</ResourceDictionary>
</App.Resources>
If you add resource dictionary inside Window's resources, you will not be able to access it everywhere, instead you should add in "App"'s resources (check out App.xaml file).
<App.Resources>
<win:BooleanToVisibilityConverter x:Key="VisibilityConverter" />
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/ResourcesD.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</App.Resources>
This will be available in every WPF object regardless of creating any inheritance hierarchy.

How to style a XAML window with a ResourceDictionary that exist in a DLL?

Hi I am trying to create a reusable XAML Window in a DLL.
I have placed in the Themes folder a new ResourceDictionary (I even merged it in the Generic.xaml), but when I try to use its styles in the window, I get an error message that the style doesn't exist:
<Window Style="{StaticResource ModalWindowStyle}" >
<!-- I have also the following -->
<Window.Resources>
<Style TargetType="Button" BasedOn="{StaticResource ButtonStyle}" />
</Window.Resources>
</Window>
I get an exception that this styles don't exist, they are both declared in that ResourceDictionary which is in the Themes folder.
From this post:
... as long as Project B has a reference to Project A.
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/Project A;component/YourSubFolder/YourResourceFile.xaml" />
</ResourceDictionary.MergedDictionaries>
Then you can just use the Resources defined in YourResourceFile.xaml.

Resources