Pull to refresh

WPF MarkupExtension, использование строк с несколькими ресурсами

Введение


Был у меня случай, когда мне понадобилась string, которая содержала данные из ресурсов XAML в WPF, так как мне не разрешалось указывать ресурсы в string. Я сразу подумал, что, возможно, можно использовать MarkupExtension для этого, но точно не знал, как это сделать. Я провёл некоторые исследования, и я оказался не единственным, кто был заинтересован в этом вопросе. Я обнаружил, что Мартин Греч опубликовал несколько ответов, которые позволили создать строку со строковой частью, объединенной с привязкой. Его MarkupExtension имеет свойство string и свойство Binding, и это было очень просто. Я включил его код в образец для справки.

Я сразу начал работать с этим, с чем-то совершенно другим, так как мне нужно было получить ресурсы XAML, и я хотел иметь возможность иметь несколько ресурсов XAML в string. Я рассматривал наличие нескольких свойств, но решил вместо этого взять лист из того, что недавно было добавлено в C#, интерполяцию строк и использование того же формата с именами ресурсов в фигурных скобках. Я бы мог пройти и вручную извлечь имена ресурсов из строки, но понял, что RegEx лучше решит эту проблему.

Сначала я использовал «грязное» решение, используя цикл foreach, но был уверен, что это не лучший вариант, поэтому поделился кодом на codeproject и спросил, есть ли лучший способ. -*/Конечно, способов достаточно, и Ричард Деминг указал путь.

Код


Код получен из MarkupExtenson и добавляет единственное свойство для string, которая должна быть интерпретирована:

public class ConcatExtension : MarkupExtension
{
    private static readonly Regex Pattern = new Regex("{([^}]+)}", RegexOptions.Compiled);
    public string String { get; set; }

    public override object ProvideValue(IServiceProvider serviceProvider)
    {
        var dep = new DependencyObject();
        if (!DesignerProperties.GetIsInDesignMode(dep))
        {
            return Pattern.Replace(String, match =>
            {
                string newMatch = match.Groups[1].Value;
                serviceProvider.TryProvideValue(newMatch, out object value);
                return Convert.ToString(value);
            });
        }
        return String;
    }
}

Регулярное выражение используется для поиска всех экземпляров, где текст находится между двумя фигурными скобками, которые используются для указания ссылок на ресурсы. Метод RegEx Replace с MatchEvaluator используется для замены имен ресурсов и связанных с значением строки ресурса скобками.

В коде MatchEvaluator используется метод расширения TryProvideValue, который я использовал с IServiceProvider, чтобы находить ресурсы и обрабатывать ошибки, когда ресурс не найден, метод, имеющий выходной аргумент и возвращающий true, если ресурс найден. Если ресурс не найден, данные выходного аргумента о том, что ресурс с этим именем не найден и возвращает false:

public static class ExtensionMethods
{
    public static bool TryProvideValue(this IServiceProvider serviceProvider, string key, out object value)
    {
        try
        {
            value = new StaticResourceExtension(key).ProvideValue(serviceProvider);
            return true;
        }
        catch
        {
            value = $"{{\"{key}\" could not be found}}";
            return false;
        }
    }
}

Пример


Пример представляет собой простое window с двумя элементами управления TextBlock, в Text DependencyPropery которого используется метод Concat ExtensionMethod, содержащий корректное имя ресурса в фигурных скобках:

<TextBlock HorizontalAlignment="Center"
    VerticalAlignment="Center"
    FontSize="15"
    Text="{local:Concat String='This is a test to see if the Concat MarkupExtension really does find the resource TestString: TestString = {TestString}'}"
    TextWrapping="Wrap" />

а другое — недопустимое имя ресурса в фигурных скобках.

<TextBlock HorizontalAlignment="Center"
    VerticalAlignment="Center"
    FontSize="15"
    Text="{local:Concat String='This is a test to see what happens when the  Concat MarkupExtension does not find the resource TestString: TestString = {TestString1}'}"
    TextWrapping="Wrap" />

Существует только один ресурс:

<system:String x:Key="TestString">Testing</system:String>

Вот как выглядит Окно в режиме разработки:



Вот как выглядит Окно в режиме запуска:



Оригинал: codeproject.com
Tags:
Hubs:
You can’t comment this publication because its author is not yet a full member of the community. You will be able to contact the author only after he or she has been invited by someone in the community. Until then, author’s username will be hidden by an alias.