nevermind nevermind - 1 month ago 23
C# Question

MarkupExtension in ResourceDictionary.Source property

I'm trying to create a markup extension that simplifies writing URIs for the Source property of the WPF ResourceDictionary.

The minimal example of the problem is following:

CS:

public class LocalResourceExtension : MarkupExtension
{
public override object ProvideValue(IServiceProvider serviceProvider)
{
return new Uri("Resources.xaml", UriKind.Relative);
}
}


XAML:

<UserControl ...>
<UserControl.Resources>
<ResourceDictionary Source="{mw:LocalResource}" /> <!-- error MC3022 -->
<!-- <ResourceDictionary Source="Resources.xaml" /> --> <!-- Works fine -->
</UserControl.Resources>
<!-- ... -->
</UserControl>


This does not compile with following error:

error MC3022: All objects added to an IDictionary must have a Key attribute or some other type of key associated with them.


However, if I replace a markup extension with a constant value (as shown in the commented line), everything works fine.

Why is the version with markup extension not working? Is there a workaround for it?

I'm using MSVC 2015.

Answer

This is working for me:

public class LocalResource : MarkupExtension
{
    public override object ProvideValue(IServiceProvider serviceProvider)
    {
        return new ResourceDictionary() { 
            Source = new Uri("Resources.xaml", UriKind.Relative) 
        };
    }
}

XAML

<Window.Resources>
    <myNamespace:LocalResource />
</Window.Resources>

The XAML editor blue-squiggles <myNamespace:LocalResource /> at design time, which kills the Design view. So this only works if you don't use the Design view. I don't, but some do.

I keep telling my girlfriend I'm the greatest genius since Galileo, and she just doesn't believe me. Galileo would've found a way to make Design view work.

UPDATE

Solution number two:

public class LocalResourceDictionary : ResourceDictionary
{
    public LocalResourceDictionary()
    {
        Source = new Uri("Resources.xaml", UriKind.Relative);
    }
}

XAML

<Window.Resources>
    <myNamespace:LocalResourceDictionary />
</Window.Resources>

That works correctly at runtime, silences the squiggle, and allows the designer to work. However, it silently fails to merge the resource file in Design mode. Still not ideal.

UPDATE

OP is smarter than me. This does everything:

public class LocalResourceDictionary : ResourceDictionary
{
    public LocalResourceDictionary()
    {
        Source = new Uri("pack://application:,,,/MyAssemblyName;component/Resourc‌​es.xaml", UriKind.Absolute);
    }
}
Comments