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

в 15:48, , рубрики: .net, C#

Введение

Был у меня случай, когда мне понадобилась 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>

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

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

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

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

Оригинал: codeproject.com

Автор: Лунтик

Источник

Поделиться

* - обязательные к заполнению поля