Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Avoiding XAML resource key conflicts in reusable WPF controls

I'm developing a WPF control and I have no control over applications where it will be used. Some XAML resource dictionary keys are obviously unique for my control, for example, <Style TargetType="{x:Type MyControl}">, so there is no risk of conflicts.

However, I need to use non-unique objects like BooleanToVisibilityConverter too. If I add it with the "BooleanToVisibilityConverter" key, it is possible (and likely) that the consumer of the control who includes my resource dictionary has already defined a similar converter in their code, probably with a different behavior.

Standard controls are avoiding conflicts somehow. There is a <BooleanToVisibilityConverter x:Key="bool2VisibilityConverter" /> in Aero.NormalColor.xaml which is not visible for WPF applications. However, I don't know how to achieve this.

How to avoid resource name conflicts? How to make my resource names "local" for my control?

like image 726
Athari Avatar asked Oct 03 '22 21:10

Athari


2 Answers

Usually WPF controls are designed in a way which doesn't require customer to include any resource dictionaries explicitly. Assembly with WPF controls has ThemeInfo attribute:

[assembly: ThemeInfo(
    ResourceDictionaryLocation.None,
    ResourceDictionaryLocation.SourceAssembly
)]

which specifies where to look for default styles, and default styles are written to Themes/Generic.xaml file.

Anyway, since resource dictionary key is an object, you can define absolutely unique keys in some internal static class:

internal static class ResourceKeys
{
    public static readonly object BooleanToVisibilityConverter = new object();
}

And use them in XAML instead of strings:

<ResourceDictionary xmlns:local="clr-namespace:YOUR_NAMESPACE_HERE">
    <BooleanToVisibilityConverter x:Key="{x:Static local:ResourceKeys.BooleanToVisibilityConverter}" />
</ResourceDictionary>
like image 117
max Avatar answered Oct 05 '22 09:10

max


one solution to avoid keys is, use the ValueConverteras singleton

public sealed class SingletonValueConverter : IValueConverter
{
    private static SingletonValueConverter instance;

    // Explicit static constructor to tell C# compiler
    // not to mark type as beforefieldinit
    static SingletonValueConverter() {
    }

    private SingletonValueConverter() {
    }

    public static SingletonValueConverter Instance {
    get { return instance ?? (instance = new SingletonValueConverter()); }

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture) {
        return ...
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) {
        return ...
    }
}

now you can use the ValueConverterlike this

<TextBlock Text="{Binding TestProperty, Converter={x:Static local:SingletonValueConverter.Instance}}" />

hope this helps

like image 33
punker76 Avatar answered Oct 05 '22 09:10

punker76