XAML designer cannot resolve references using custom implementation of ResourceDictionary - c#

I'm trying to make use of the SharedResourceDictionary from this tutorial. This class derives from ResourceDictionary, but loads content only once even if it is referenced multiple times. It works like a charm when I build and run it.
However, any styles referenced using a SharedResourceDictionary will cause a compiler error in the XAML designer:
The resource "X" could not be resolved.
This error does not occur when I simply switch SharedResourceDictionary to ResourceDictionary.
The reference {StaticResource LightGreenBrush} in the following example will cause an error, even though it is defined in ColorDictionary.xaml:
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<SharedResourceDictionary Source="pack://Application:,,,/MyAssembly;component/ResourceDictionaries/ColorDictionary.xaml"/>
</ResourceDictionary.MergedDictionaries>
<Style TargetType="{x:Type Button}">
<Setter Property="Background" Value="{StaticResource LightGreenBrush}"/>
</Style>
</ResourceDictionary>
Is there any way to prevent this error from showing on (what seems to be) perfectly valid XAML?

Related

How to reference a local resource dictionary from within the same FrameworkElement's property in UWP

Is there a way to reference a local ResourceDictionary from within the same FrameworkElement's property?
I tried the following
<TextBlock Text="{StaticResource txt}">
<TextBlock.Resources>
<x:String x:Key="txt">asdf</x:String>
</TextBlock.Resources>
</TextBlock>
but get the error
The resource "txt" could not be resolved.
Moving the txt resource from the TextBlock to the Page resources would work but that seems messy and i was hoping that it's possible to reference a FrameworkElements local ResourceDictionary.
Using CustomResource instead of StaticResource at least allows to auto complete to txt, but it doesn't work because then invoking Initializecomponent throws an exception: "No custom resource loader set" and i'm not sure if implementing and setting a custom loader would solve that at all.
Is there a way to do this using the local resource dictionary?
UWP FrameworkElement resource lookup looks for parent control resources, not child control resources.
This document details how Resources works.
Edit
It is recommended to use Resource Dictionary file.
Right click on your project
Choose Add
Choose Resource Dictionary.
You can put your all your resource in this file.
Then add a resource file reference in App.xaml.
Dictionary1.xaml
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style x:Key="txt" TargetType="TextBlock">
<Setter Property="Text" Value="asdf"/>
</Style>
</ResourceDictionary>
App.xaml
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Dictionary1.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
Page.xaml
<TextBlock Style="{StaticResource txt}" ></TextBlock>

Generic xaml file isn't getting added to Resources in UWP Class Library

So I have a seemingly simple setup but for some reason my UWP app isn't processing my Generic.xaml file
I have a shared class library that targets 16299 and its min version is 16299.
I created a Themes directory and under it I put a Generic.xaml file which is a Resource dictionary.
Inside this I tried adding a style and then referencing it by key but the UWP app isn't able to find the style.
For example
Generic.xaml
<Style TargetType="ListViewItem" x:Key="ListViewItemEvenRowStyle" >
<Setter Property="Padding" Value="0" />
<Setter Property="Background" Value="Black" />
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
</Style>
<Style TargetType="ListViewItem" x:Key="ListViewItemOddRowStyle" >
<Setter Property="Padding" Value="0" />
<Setter Property="Background" Value="White" />
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
</Style>
Which results in this exception when I reference it with StaticResource
Windows.UI.Xaml.Markup.XamlParseException: 'The text associated with
this error code could not be found.
Cannot find a Resource with the Name/Key ListViewItemEvenRowStyle
I also tried putting this in ResourceDictionary.ThemeResources and referencing it with ThemeResource but I keep getting the same result.
This is the CSProj definition
<Page Include="Themes\Generic.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
You need to use ResourceDictionary.MergedDictionaries, instead of ResourceDictionary.ThemeResources.
In your main UWP project, open the 'App.xaml' file, add the following code:
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="YourClassLibrary/Themes/Generic.xaml"></ResourceDictionary>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
More information, please see XAML theme resources and ResourceDictionary.MergedDictionaries.
[Updated on 2019/7/10]
I'm curious how Infragistics, Telerik, and Microsoft UWP.Toolkit manage to accomplish this. If I add a telerik control dll to my project and reference their controls, I don't need to add anything to my resource dictionaries.
The Telerik and WindowsCommunityToolkit are open source. You could check their source code. These controls are custom controls. Each control has its own style file and it will be applied to it in the control's constructor method by setting DefaultStyleKey = typeof(YourCustomControlClass).
For example, the Microsoft.Toolkit.Uwp.UI.Controls/Carousel/ control. You could see the Carousel.xaml style file is in the same folder with the Carousel.cs class. In the Carousel constructor, it uses DefaultStyleKey = typeof(Carousel); to apply the style. But just with these steps, the system still cannot find the corresponding style. You could see the Microsoft.Toolkit.Uwp.UI.Controls/Themes/ folder, it has a Generic.xaml file in there. It actually is a 'ResourceDictionary'. It use ResourceDictionary.MergedDictionaries to merge resource in different custom control folders.
With this way, the main project just need to add reference to your control library and use the controls directly without using ResourceDictionary.MergedDictionaries in the main project.

Unable to override default style of wpf control in generic.xaml

So we are trying to retemplate some stock wpf controls by changing their default styles in the generic.xaml
When we normally do this we subclass a control and then override the default style key of the subclassed control in its static initializer. However, we are trying to just override the basic control now without subclassing it. That way anyone in the company using the stock wpf control will get our new styling by default.
I can't seem to get this to work though.
In my sandbox application which is a watered down version of our actual problem, I have the following.
MainWindow.xaml
<StackPanel>
<TextBlock>It doesn't work</TextBlock>
<local:CustomTextBlock>It works</local:CustomTextBlock>
</StackPanel>
Themes/Generic.xaml
<Style TargetType="{x:Type TextBlock}">
<Setter Property="FontSize" Value="100" />
</Style>
<Style TargetType="{x:Type test:CustomTextBlock}">
<Setter Property="FontSize" Value="100" />
</Style>
CustomTextBlock.cs
public class CustomTextBlock : TextBlock
{
static CustomTextBlock()
{
Type _CustomTextBlock = typeof(CustomTextBlock);
DefaultStyleKeyProperty.OverrideMetadata(
_CustomTextBlock,
new FrameworkPropertyMetadata(_CustomTextBlock));
}
}
Which results in this being displayed.
My theory is that the WPF engine is ignoring our style because the default style key is either A: not overridden or B: is finding their style in their generic.xaml first.
My question is, is there a work around for this? Are my assumptions correct?
UPDATE:
According to reference source, the default style key is overridden in the stock wpf control for TextBlock.cs in this case
Reference Source TextBlock.cs (Line 346)
To accomplish this, you can put your styles either directly into App.xaml or into a separate ResourceDictionary (named DefaultStyles.xaml).
Putting directly into App.xaml is easy enough, just put the style within the Resources element.
If you want to put the styles into a file (this is useful if you want the styles for multiple applications or within multiple assemblies) you add it to the MergedDictionaries of your App.xaml as such
<Application x:Class="MyAwesomeApp"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Themes/DefaultStyles.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>
This assumes that you put the file DefaultStyles into the Themes folder. If it is in another assembly you would do the following:
<ResourceDictionary Source="/Company.Controls.UI;component/DefaultStyles.xaml"/>
Have a look at this post (What is so special about Generic.xaml).
The main issue seems to be:
WPF looks for the default style in a special resource dictionary in the Themes folder in the same assembly as the control.
'Your' control is defined in 'your' assembly, TextBlock is defined in PresentationFramework. So you better create another ResourceDictionary for re-styling standard controls and include/merge it in each of your xaml documents (I suppose, this hurts).
Hope it helps.

Design Layout differs from Runtime Layout

I have a Project, where I am using prism for Navigation between usercontrols.
The App.xaml has some Definition for resources:
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/Resources/GlobalResources.xaml" />
<ResourceDictionary Source="pack://application:,,,/Resources/Themes/Generic.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
These are applied during design time and everything Looks the way it's supposed to. As I run the application the resources are not applied anymore. Resources referenced by key Work fine (e.g. BoolToVisConverter), but Resources applied to control types are ignored.
Important
The assumption made in the last sentence of the question is wrong.
Nothing is ignored during runtime - it's ignored during design time.
After Investigation of the problem, it has nothing to do with the merged dictionaries, nor with resources not being applied during runtime.
The problem arises through a definition of a style for TextBlock:
<Style TargetType="TextBlock">
<Setter Property="Margin" Value="2,2,3,2" />
</Style>
This style will be ignored during design time, but applied in runtime - thus leading to a different layout.
Adding explicit keys for resources or anything else are not necessary.
For testing purposes, if an design is applied or not just add some silly text-color or something like that - if I'd done that early, I would have found the problem in a jiffy.

SilverLight Control Library - Cannot Reference Relative MergedDictionary by Generic.xaml

I'm at my ropes end with this. I have spent countless hours trying to figure this out and no such luck.
Short Explanation of Problem
Inside my custom control class, when I check Application.Current.Resources["key"] I am returned null. This "Key" style is inside a local dictionary which is supposed to be merged with the Application.Current.Resources by my Control Library's themes/generic.xaml resource.
How do I reference/confirm a reference to a MergedDictionary in my SilverLight Control Library's themes/generic.xaml.
Is this even possible or is my thinking on how merged resources are suppose to be merged entirely wrong?
Please help. Thanks in advance.
Long Explanation of Problem
I have a Silverlight Control Library with a Controls folder, and a Themes folder. Inside the Themes folder I have generic.xaml. Its content:
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/SilverLightLib;component/Themes/EnhancedLabelDict.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
Inside the Themes folder I have EnhancedLabelDict.xaml. Its content:
<Style x:Key="ReadOnlyTextBox" TargetType="TextBox">
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="Background" Value="#FFFFFFFF"/>
<Setter Property="Foreground" Value="#FF000000"/>
<Setter Property="Padding" Value="2"/>
<Setter Property="BorderBrush">
<!-- A lot more code -->
</Style>
Both these files build action is set to Page.
Now I have no idea if the generic.xaml is even loading my resource. The only way I can tell is if I put some un-formatted text between . This causes an error.
If I use an incorrect path to my ResourceDictionary, I receive a run time error - 'Failed to assign to property 'System.Windows.ResourceDictionary.Source'
Inside my Controls folder, I have EnhancedLabel.cs which extends ContentControl. Inside it's constructor, I create a new TextBox and assign it's style like so:
Style style = Application.Current.Resources["ReadOnlyTextBox"] as Style;
this.textBox.Style = style;
I have this style in both the App.xaml and my EnhancedLabelDict.xaml which is inside my library. When I comment out the Style in App.xaml, the 'ReadOnlyTextBox' style is not found (null). Uncomment it, it is found.
I don't understand why I cannot reference my style from within my EnhancedLabel.cs.
If I take the EnhancedLabelDict.xaml, add it to a Themes folder inside a Resources folder inside my main Application. If I then add the following to my App.xaml:
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/SilverLightPOC;component/Resources/Themes/EnhancedLabelDict.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
My control works! So other than the path, there is nothing different. But this doesn't work because I don't want to have to store Dictionary files that my Library depends on, inside the main application.
Please help.
There is an optimization bug in Silverlight when you have more than 3 levels deep of nested dictionaries - they're not loaded unless you use a workarround.
See
Adding a Merged Dictionary to a Merged Dictionary

Categories

Resources