Pergunta

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?

Foi útil?

Solução

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>

Outras dicas

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

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top