Это сложно поддерживать из-за того, что Binding работает в WPF. Строковые интерполяции в коде C# могут быть скомпилированы непосредственно на звонки string.Format
и в основном просто обеспечивают удобный синтаксический сахар. Однако для выполнения этой работы с привязкой необходимо выполнить некоторую работу во время выполнения.
Я собрал простой класс, который может это сделать, хотя он имеет несколько ограничений. В частности, он не поддерживает передачу всех параметров привязки, и неудобно вводить XAML, поскольку вам нужно избегать фигурных скобок (возможно, стоит использовать другой символ?). Он должен обрабатывать привязки с несколькими путями и произвольно сложный формат однако, если они правильно экранированы для использования в XAML.
В связи с одним конкретным моментом в вашем вопросе это не позволяет вставлять произвольные выражения, как вы можете делать в интерполированных строках. Если вы захотите это сделать, вам придется немного поучаствовать и сделать что-то вроде компиляции кода «на лету» с точки зрения связанных значений. Скорее всего, вам нужно будет испустить вызов функции, который принимает значения параметров, затем вызовите это как делегат из преобразователя значений и попросите его выполнить встроенные выражения. Это должно быть возможно, но, вероятно, непросто реализовать.
Использование выглядит следующим образом:
<TextBlock Text="{local:InterpolatedBinding '\{TestString\}: \{TestDouble:0.0\}'}"/>
А вот расширение разметки, который делает работу:
public sealed class InterpolatedBindingExtension : MarkupExtension
{
private static readonly Regex ExpressionRegex = new Regex(@"\{([^\{]+?)(?::(.+?))??\}", RegexOptions.Compiled);
public InterpolatedBindingExtension()
{
}
public InterpolatedBindingExtension(string expression)
{
Expression = expression;
}
public string Expression { get; set; }
public override object ProvideValue(IServiceProvider serviceProvider)
{
//Parse out arguments captured in curly braces
//If none found, just return the raw string
var matches = ExpressionRegex.Matches(Expression);
if (matches.Count == 0)
return Expression;
if (matches.Count == 1)
{
var formatBuilder = new StringBuilder();
//If there is only one bound target, can use a simple binding
var varGroup = matches[0].Groups[1];
var binding = new Binding();
binding.Path = new PropertyPath(varGroup.Value);
binding.Mode = BindingMode.OneWay;
formatBuilder.Append(Expression.Substring(0, varGroup.Index));
formatBuilder.Append('0');
formatBuilder.Append(Expression.Substring(varGroup.Index + varGroup.Length));
binding.Converter = new FormatStringConverter(formatBuilder.ToString());
return binding.ProvideValue(serviceProvider);
}
else
{
//Multiple bound targets, so we need a multi-binding
var multiBinding = new MultiBinding();
var formatBuilder = new StringBuilder();
int lastExpressionIndex = 0;
for (int i=0; i<matches.Count; i++)
{
var varGroup = matches[i].Groups[1];
var binding = new Binding();
binding.Path = new PropertyPath(varGroup.Value);
binding.Mode = BindingMode.OneWay;
formatBuilder.Append(Expression.Substring(lastExpressionIndex, varGroup.Index - lastExpressionIndex));
formatBuilder.Append(i.ToString());
lastExpressionIndex = varGroup.Index + varGroup.Length;
multiBinding.Bindings.Add(binding);
}
formatBuilder.Append(Expression.Substring(lastExpressionIndex));
multiBinding.Converter = new FormatStringConverter(formatBuilder.ToString());
return multiBinding.ProvideValue(serviceProvider);
}
}
private sealed class FormatStringConverter : IMultiValueConverter, IValueConverter
{
private readonly string _formatString;
public FormatStringConverter(string formatString)
{
_formatString = formatString;
}
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
if (targetType != typeof(string))
return null;
return string.Format(_formatString, values);
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
return null;
}
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (targetType != typeof(string))
return null;
return string.Format(_formatString, value);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return null;
}
}
}
я сделал очень ограниченное тестирование, поэтому я рекомендую более тщательное тестирование и закаливание перед использованием этого в производстве. Должно быть, надеюсь, что хорошей отправной точкой для кого-то сделать что-то полезное.
Та же проблема возникает с Razor в ASP.NET MVC. Вероятно, это ошибка [https://github.com/aspnet/Razor/issues/401) в двух синтаксических анализаторах –