Add items dynamically to ResourceDictionary. Convert File path to resource Key - wpf

I have ResourceDictionary in my application. I need to add some items from c# code to this collection:
<UserControl.Resources>
<ResourceDictionary>
</ResourceDictionary>
</UserControl.Resources>
As key for resources i want to use path to file.
For example:
c:\some folder\##file.txt
What is the best wey to convert this file path to valid ResourceDictionary Key?

<UserControl.Resources>
<ResourceDictionary xmlns:sys="clr-namespace:System;assembly=mscorlib">
<sys:String x:Key="c:some folder#file.txt">
whatever
</sys:String>
</ResourceDictionary>
</UserControl.Resources>
<Grid>
<Label Content="{StaticResource c:some folder#file.txt}" />
</Grid>
Remove back slash and encode special characters.

This article on CP tell you how use loose XAML files at Runtime, also some other. Have a look.

Related

Setting style on/in UserControl without having to define MergeDictionary?

I'm looking to set a style on some UserControls that's kept in a resource dictionary at the base of my project tree. The only way I've found to do so is below by defining MergeDictionary in the resources to link in the xaml file with styles. I'd prefer to not have to put this same code on every single control that needs this style though. Is there a better way to do this?
<UserControl
x:Class="TestApp.Screens.Sub.Details"
...
Style="{DynamicResource BottomContentUserControl}">
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="../../GeneralStyles.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
</UserControl>
You can add the styles to the ApplicationResourceDictionary or you could add them to your App.xaml file so that they will be applied throughout your application.

Reference custom resource defined in another xaml file

I am trying to create a new resource in one xaml file and reference it in another xaml file.
i.e I define
<Window.Resources>
<ImageBrush x:Key="TileBrush" TileMode="Tile" ViewportUnits="Absolute" Viewport="0 0 32 32" ImageSource="MyImageButton.png" Opacity="0.3">
</ImageBrush>
</Window.Resources>
And attempt to use it in another xaml file by
<Grid>
<Button Background="{StaticResource TileBrush}" Margin="5" Padding="5" FontWeight="Bold" FontSize="14">
A Tiled Button
</Button>
</Grid>
However I get the error "StaticResource reference 'TileBrush' was not found."
I can reference the resource from the same xaml file but don't know how to do so from another file.
In WPF, the resource references works as a tree. Each control have resource, and children control can access parent's resources. The global application resource dictionary is in the App.xaml file. In this file you can include several resource dictionaries as a Merged Dictionary. See this code sample:
<?xml version="1.0" encoding="utf-8"?>
<Application ...>
<Application.Resources>
<ResourceDictionary>
<vm:ViewModelLocator x:Key="Locator" d:IsDataSource="True" />
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="View\SomeFileDictionary.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>
The SomeFileDictionary.xaml is located in the View folder of my project structure. And has looks like this:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ViewModel="clr-namespace:Cepha.ViewModel"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
... >
<DataTemplate DataType="{x:Type ViewModel:SomeType}">
<TextBox .../>
</DataTemplate>...
And each dictionary key or data template defined in this file (or App.xaml), can be referenced in any place of your project. Hope this helps...
You should define this in the app.xaml file. These resources are shared throughout the entire project

ResourceDictionary in application resources cannot be found

I'm facing some strange issue with a ResourceDictionary in my Application.Resources.
In order to fill multiple ComboBoxes inside my application, I want to store the data in a ResourceDictionary.
However, I get the "Cannot find a Resource with that Name/Key..." error constantly.
My XAML-Code here:
<Application.Resources>
<ResourceDictionary x:Key="RDArray">
<sys:String x:Key="item1">Item1</sys:String>
<sys:String x:Key="item2">Item2</sys:String>
<sys:String x:Key="item3">Item3</sys:String>
</ResourceDictionary>
</Application.Resources>
<ListBox x:Name="lb" ItemsSource="{Binding Values, Source={StaticResource RDArray}}" />
Due to some lucky circumstances I was able to find out that putting another resource like Style above the Dictionary solves the problem.
<Application.Resources>
<Style x:Key="fubar" />
<ResourceDictionary x:Key="RDArray">
<sys:String x:Key="item1">Item1</sys:String>
<sys:String x:Key="item2">Item2</sys:String>
<sys:String x:Key="item3">Item3</sys:String>
</ResourceDictionary>
</Application.Resources>
The "bug" occurs in a WPF application as well as in Silverlight.
Although I can solve this using the shown "trick", I am curious where this error is coming from. I wasn't able to find anything about this. Maybe it is just me and something I am understanding wrong about resources in WPF.
This is because if you have a resource dictionary as the only item in the resources section then the contents simply get added to the parent dictionary (I snooped and this seems to be the case). To get around this you need to put your resource dictionary in separate xaml file (List.xaml in this case):
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<ResourceDictionary x:Key="RDArray">
<sys:String x:Key="item1">Item1</sys:String>
<sys:String x:Key="item2">Item2</sys:String>
<sys:String x:Key="item3">Item3</sys:String>
</ResourceDictionary>
</ResourceDictionary>
and then reference that in your main app:
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="List.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
<ListBox x:Name="lb" ItemsSource="{Binding Values, Source={StaticResource RDArray}}"/>
Thanks for your answer.
In my real application I created that separated file, but I didn't make a second ResourceDictionary inside of it a nd just put the string values there. So it looked like:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<sys:String x:Key="item1">Item1</sys:String>
<sys:String x:Key="item2">Item2</sys:String>
<sys:String x:Key="item3">Item3</sys:String>
</ResourceDictionary>
So this was of course not working either.
Thanks for your answer, definitely solves this one.

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.

Resources