UWP MergedDictionary Style that references other style throws error

十年热恋 提交于 2020-01-03 05:18:08

问题


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

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!