问题
Having real problems creating a Merged Dictionary of styles that need to use values from another MergedDictionary
(Brushes.xaml
).
When I try and reference it from another file I get the following error:
"Failed to assign to property 'Windows.UI.Xaml.ResourceDictionary.Source' because the type 'Windows.Foundation.String' cannot be assigned to the type 'Windows.Foundation.Uri'. [Line: x Position: y]"
E.g. in a Resource Dictionary I have the following that works..
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Brushes.xaml" />
</ResourceDictionary.MergedDictionaries>
<Style TargetType="Button">
<Setter Property="Background" Value="{StaticResource customBrush1}" />
<Setter Property="Foreground" Value="{StaticResource customBrush2}" />
However, this isn't ideal as I'd need to reference Brushes.xaml
in every style resource dictionary. So what I want to do is declare the Brushes.xaml
in App.xaml
but everything I try results in the error above. It basically does not recognise the resources defined in Brushes.xaml
unless I add them to each individual style.
E.g. What I want (to be able to do in App.xaml)...
<Application x:Class="Test.UWP.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
RequestedTheme="Light">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="ms-appx:///Test.Xamarin.Forms.Themes.UWP/Brushes.xaml" />
<ResourceDictionary Source="ms-appx:///Test.Xamarin.Forms.Themes.UWP/CustomStyles.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>
CustomStyles.xaml
contains
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Styles\Button\BackButton.xaml" />
<ResourceDictionary Source="Styles\Button\Default.xaml" />
<ResourceDictionary Source="Styles\Button\HyperlinkBasicButton.xaml" />
<ResourceDictionary Source="Styles\Button\HyperlinkButton.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
And e.g. Styles\Button\Default.xaml
contains..
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style TargetType="Button">
<Setter Property="Background" Value="{StaticResource CustomBrush1}" />
<Setter Property="Foreground" Value="{StaticResource CustomBrush2}" />
Where CustomBrush1 is defined in Brushes.xaml
.
I've tried so many things e.g. Tried adding Brushes.xaml to the CustomStyles.xaml - doesn't work. Tried changing the order as this states they should be in inverse order - this doesn't work.
Any help is much appreciated, thanks
As per comment, here is the Brushes.xaml
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<SolidColorBrush x:Key="CustomBrush1"
Color="Black}" />
<SolidColorBrush x:Key="CustomBrush2"
Color="White}" />
</ResourceDictionary>
回答1:
From your description, this behavior is by-design, derive this document we could find.
The lookup sequence then checks the next parent object in the runtime object tree of the app....
If you place Brushes.xaml
at patent level, the sub level Default.xaml
can not get the brush resource and throw exception. The best practice is refer Brushes.xaml
in each resource like the first scenario mentioned above.
And if Brushes.xaml
and Default.xaml
are not in the same folder , we need use ms-appx://
scheme to refer it .
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:TestApp.Styles.Button"
>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="ms-appx:///Brushes.xaml" />
</ResourceDictionary.MergedDictionaries>
<Style TargetType="Button">
<Setter Property="Background" Value="{StaticResource CustomBrush1}" />
<Setter Property="Foreground" Value="{StaticResource CustomBrush2}" />
</Style>
</ResourceDictionary>
Then add above to CustomStyles
.
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:TestApp"
>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Styles/Button/Default.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
At last, we just need to add CustomStyles into MergedDictionaries
within App.xaml file
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="CustomStyles.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
回答2:
I found a solution to this problem. The problem being that one resource dictionary cannot reference anything in another if they are both declared in App.Xaml
(unless the value is in the ControlTemplate - see below)
The solution I have found is to remove all resource dictionaries from App.Xaml, so App.Xaml basically looks like this:
<Application x:Class="Dwp.CRMobile.UWP.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
RequestedTheme="Light">
</Application>
And then instead add them to the OnLaunched
method of App.Xaml.cs
as below. Note you will also need to add this to OnActivated
if the app could also be run by PowerShell etc.
protected override void OnActivated(IActivatedEventArgs e)
{
var eventArgs = e as ProtocolActivatedEventArgs;
var data = new ActivationArgs(e.Kind, eventArgs.Uri.Query);
AddResources();
Run(e, data);
}
protected override void OnLaunched(LaunchActivatedEventArgs e)
{
#if RELEASE
var data = new ActivationArgs(e.Kind, e.Arguments);
#else
var data = new ActivationArgs(ActivationKind.Protocol, e.Arguments);
#endif
AddResources();
Run(e, data);
}
private static void AddResources()
{
var applicationMergedDictionaries = Application.Current.Resources.MergedDictionaries;
applicationMergedDictionaries.Add(GetResourceDictionary("ms-appx:///Test.Xamarin.Forms.Themes.UWP/Brushes.xaml"));
applicationMergedDictionaries.Add(GetResourceDictionary("ms-appx:///Test.Xamarin.Forms.Themes.UWP/CustomStyles.xaml"));
applicationMergedDictionaries.Add(GetResourceDictionary("ms-appx:///Test.HTMobile.Core.UWP/Styles.xaml"));
applicationMergedDictionaries.Add(GetResourceDictionary("ms-appx:///Test.CRFramework.Xamarin.Forms.UWP/Root.xaml"));
}
It's an odd one - something to do with when resources are loaded. Because if I stick to the original method in App.xaml
and use a value from Brushes.xaml
in a style defined in CustomStyles.xaml
it will work if the value is set in a ControlTemplate
, but it will not if it is in a standard Setter Property. This method above solved this problem for me, so hopefully it will help someone else.
来源:https://stackoverflow.com/questions/59138929/uwp-mergeddictionary-style-that-references-other-style-throws-error