String interpolation in XAML












4














I'm thinking about ways of getting advance of C# 6 string interpolation in XAML, such as using them instead of value converters in some simple scenarios like replacing a zero by an empty string when binding to numbers.



From its design discussions:




An interpolated string is a way to construct a value of type String
(or IFormattable) by writing the text of the string along with
expressions that will fill in "holes" in the string. The compiler
constructs a format string and a sequence of fill-in values from the
interpolated string.




However, as I suspected, it seems that they can't be used from XAML since it uses a different compiler to generate the BAML and I find no trace of the strings in the generated .g.i.cs files.




  • Are string interpolations not supported in XAML?

  • What workarounds could there be? Maybe using markup extensions to dynamically compile the string interpolations?










share|improve this question






















  • The same problem occurs with Razor in ASP.NET MVC. It's probably a bug in the two parsers
    – Panagiotis Kanavos
    May 26 '15 at 16:16
















4














I'm thinking about ways of getting advance of C# 6 string interpolation in XAML, such as using them instead of value converters in some simple scenarios like replacing a zero by an empty string when binding to numbers.



From its design discussions:




An interpolated string is a way to construct a value of type String
(or IFormattable) by writing the text of the string along with
expressions that will fill in "holes" in the string. The compiler
constructs a format string and a sequence of fill-in values from the
interpolated string.




However, as I suspected, it seems that they can't be used from XAML since it uses a different compiler to generate the BAML and I find no trace of the strings in the generated .g.i.cs files.




  • Are string interpolations not supported in XAML?

  • What workarounds could there be? Maybe using markup extensions to dynamically compile the string interpolations?










share|improve this question






















  • The same problem occurs with Razor in ASP.NET MVC. It's probably a bug in the two parsers
    – Panagiotis Kanavos
    May 26 '15 at 16:16














4












4








4


2





I'm thinking about ways of getting advance of C# 6 string interpolation in XAML, such as using them instead of value converters in some simple scenarios like replacing a zero by an empty string when binding to numbers.



From its design discussions:




An interpolated string is a way to construct a value of type String
(or IFormattable) by writing the text of the string along with
expressions that will fill in "holes" in the string. The compiler
constructs a format string and a sequence of fill-in values from the
interpolated string.




However, as I suspected, it seems that they can't be used from XAML since it uses a different compiler to generate the BAML and I find no trace of the strings in the generated .g.i.cs files.




  • Are string interpolations not supported in XAML?

  • What workarounds could there be? Maybe using markup extensions to dynamically compile the string interpolations?










share|improve this question













I'm thinking about ways of getting advance of C# 6 string interpolation in XAML, such as using them instead of value converters in some simple scenarios like replacing a zero by an empty string when binding to numbers.



From its design discussions:




An interpolated string is a way to construct a value of type String
(or IFormattable) by writing the text of the string along with
expressions that will fill in "holes" in the string. The compiler
constructs a format string and a sequence of fill-in values from the
interpolated string.




However, as I suspected, it seems that they can't be used from XAML since it uses a different compiler to generate the BAML and I find no trace of the strings in the generated .g.i.cs files.




  • Are string interpolations not supported in XAML?

  • What workarounds could there be? Maybe using markup extensions to dynamically compile the string interpolations?







wpf xaml string-interpolation markup-extensions c#-6.0






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked May 26 '15 at 13:14









jnovo

4,49822642




4,49822642












  • The same problem occurs with Razor in ASP.NET MVC. It's probably a bug in the two parsers
    – Panagiotis Kanavos
    May 26 '15 at 16:16


















  • The same problem occurs with Razor in ASP.NET MVC. It's probably a bug in the two parsers
    – Panagiotis Kanavos
    May 26 '15 at 16:16
















The same problem occurs with Razor in ASP.NET MVC. It's probably a bug in the two parsers
– Panagiotis Kanavos
May 26 '15 at 16:16




The same problem occurs with Razor in ASP.NET MVC. It's probably a bug in the two parsers
– Panagiotis Kanavos
May 26 '15 at 16:16












2 Answers
2






active

oldest

votes


















2














This is tricky to support due to the way that Binding works in WPF. String interpolations in the C# code can be compiled directly to string.Format calls and basically just provide a convenient syntactic sugar. To make this work with Binding, though, it's necessary to do some work at runtime.



I've put together a simple class that can do this, though it has a few limitations. In particular, it doesn't support passing through all the binding parameters and it's awkward to type in the XAML since you have to escape the curly braces (maybe worth using a different character?) It should handle multi-path bindings and arbitrarily complex format strings, though, as long as they are properly escaped for use in XAML.



In reference to one particular point in your question, this doesn't allow you to embed arbitrary expressions like you can do in interpolated strings. If you wanted to do that, you'd have to get a bit fancier and do something like on-the-fly code compilation in terms of the bound values. Most likely you'd need to emit a function call that takes the parameter values, then call that as a delegate from the value converter and have it execute the embedded expressions. It should be possible, but probably not easy to implement.



Usage looks like this:



<TextBlock Text="{local:InterpolatedBinding '{TestString}: {TestDouble:0.0}'}"/>


And here is the markup extension that does the work:



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;
}
}
}


I've done very limited testing, so I recommend more thorough testing and hardening before using this in production. Should hopefully be a good starting point for someone to make something useful, though.






share|improve this answer































    1














    This sounds a lot like the StringFormat attribute introduced in .Net 3.5. As you quote, "writing the text of the string along with expressions that will fill in 'holes' in the string", this can be performed within a XAML binding like this:



    <TextBlock Text="{Binding Amount, StringFormat=Total: {0:C}}" />


    Since you can use any of the custom string formats, there's a lot of power under the hood here. Or are you asking something else?






    share|improve this answer

















    • 2




      The OP is asking something else. String interpolation is added in C# 6 and works only with Visual Studio 2015 RC. You can now write $"{myDateVar:yyyy-MM-dd} Boo" instead of the equivalent String.Format("{0:yyyy-MM-dd} Boo",myDateVar)
      – Panagiotis Kanavos
      May 26 '15 at 16:14











    Your Answer






    StackExchange.ifUsing("editor", function () {
    StackExchange.using("externalEditor", function () {
    StackExchange.using("snippets", function () {
    StackExchange.snippets.init();
    });
    });
    }, "code-snippets");

    StackExchange.ready(function() {
    var channelOptions = {
    tags: "".split(" "),
    id: "1"
    };
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function() {
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled) {
    StackExchange.using("snippets", function() {
    createEditor();
    });
    }
    else {
    createEditor();
    }
    });

    function createEditor() {
    StackExchange.prepareEditor({
    heartbeatType: 'answer',
    autoActivateHeartbeat: false,
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader: {
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    },
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    });


    }
    });














    draft saved

    draft discarded


















    StackExchange.ready(
    function () {
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f30459680%2fstring-interpolation-in-xaml%23new-answer', 'question_page');
    }
    );

    Post as a guest















    Required, but never shown

























    2 Answers
    2






    active

    oldest

    votes








    2 Answers
    2






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    2














    This is tricky to support due to the way that Binding works in WPF. String interpolations in the C# code can be compiled directly to string.Format calls and basically just provide a convenient syntactic sugar. To make this work with Binding, though, it's necessary to do some work at runtime.



    I've put together a simple class that can do this, though it has a few limitations. In particular, it doesn't support passing through all the binding parameters and it's awkward to type in the XAML since you have to escape the curly braces (maybe worth using a different character?) It should handle multi-path bindings and arbitrarily complex format strings, though, as long as they are properly escaped for use in XAML.



    In reference to one particular point in your question, this doesn't allow you to embed arbitrary expressions like you can do in interpolated strings. If you wanted to do that, you'd have to get a bit fancier and do something like on-the-fly code compilation in terms of the bound values. Most likely you'd need to emit a function call that takes the parameter values, then call that as a delegate from the value converter and have it execute the embedded expressions. It should be possible, but probably not easy to implement.



    Usage looks like this:



    <TextBlock Text="{local:InterpolatedBinding '{TestString}: {TestDouble:0.0}'}"/>


    And here is the markup extension that does the work:



    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;
    }
    }
    }


    I've done very limited testing, so I recommend more thorough testing and hardening before using this in production. Should hopefully be a good starting point for someone to make something useful, though.






    share|improve this answer




























      2














      This is tricky to support due to the way that Binding works in WPF. String interpolations in the C# code can be compiled directly to string.Format calls and basically just provide a convenient syntactic sugar. To make this work with Binding, though, it's necessary to do some work at runtime.



      I've put together a simple class that can do this, though it has a few limitations. In particular, it doesn't support passing through all the binding parameters and it's awkward to type in the XAML since you have to escape the curly braces (maybe worth using a different character?) It should handle multi-path bindings and arbitrarily complex format strings, though, as long as they are properly escaped for use in XAML.



      In reference to one particular point in your question, this doesn't allow you to embed arbitrary expressions like you can do in interpolated strings. If you wanted to do that, you'd have to get a bit fancier and do something like on-the-fly code compilation in terms of the bound values. Most likely you'd need to emit a function call that takes the parameter values, then call that as a delegate from the value converter and have it execute the embedded expressions. It should be possible, but probably not easy to implement.



      Usage looks like this:



      <TextBlock Text="{local:InterpolatedBinding '{TestString}: {TestDouble:0.0}'}"/>


      And here is the markup extension that does the work:



      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;
      }
      }
      }


      I've done very limited testing, so I recommend more thorough testing and hardening before using this in production. Should hopefully be a good starting point for someone to make something useful, though.






      share|improve this answer


























        2












        2








        2






        This is tricky to support due to the way that Binding works in WPF. String interpolations in the C# code can be compiled directly to string.Format calls and basically just provide a convenient syntactic sugar. To make this work with Binding, though, it's necessary to do some work at runtime.



        I've put together a simple class that can do this, though it has a few limitations. In particular, it doesn't support passing through all the binding parameters and it's awkward to type in the XAML since you have to escape the curly braces (maybe worth using a different character?) It should handle multi-path bindings and arbitrarily complex format strings, though, as long as they are properly escaped for use in XAML.



        In reference to one particular point in your question, this doesn't allow you to embed arbitrary expressions like you can do in interpolated strings. If you wanted to do that, you'd have to get a bit fancier and do something like on-the-fly code compilation in terms of the bound values. Most likely you'd need to emit a function call that takes the parameter values, then call that as a delegate from the value converter and have it execute the embedded expressions. It should be possible, but probably not easy to implement.



        Usage looks like this:



        <TextBlock Text="{local:InterpolatedBinding '{TestString}: {TestDouble:0.0}'}"/>


        And here is the markup extension that does the work:



        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;
        }
        }
        }


        I've done very limited testing, so I recommend more thorough testing and hardening before using this in production. Should hopefully be a good starting point for someone to make something useful, though.






        share|improve this answer














        This is tricky to support due to the way that Binding works in WPF. String interpolations in the C# code can be compiled directly to string.Format calls and basically just provide a convenient syntactic sugar. To make this work with Binding, though, it's necessary to do some work at runtime.



        I've put together a simple class that can do this, though it has a few limitations. In particular, it doesn't support passing through all the binding parameters and it's awkward to type in the XAML since you have to escape the curly braces (maybe worth using a different character?) It should handle multi-path bindings and arbitrarily complex format strings, though, as long as they are properly escaped for use in XAML.



        In reference to one particular point in your question, this doesn't allow you to embed arbitrary expressions like you can do in interpolated strings. If you wanted to do that, you'd have to get a bit fancier and do something like on-the-fly code compilation in terms of the bound values. Most likely you'd need to emit a function call that takes the parameter values, then call that as a delegate from the value converter and have it execute the embedded expressions. It should be possible, but probably not easy to implement.



        Usage looks like this:



        <TextBlock Text="{local:InterpolatedBinding '{TestString}: {TestDouble:0.0}'}"/>


        And here is the markup extension that does the work:



        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;
        }
        }
        }


        I've done very limited testing, so I recommend more thorough testing and hardening before using this in production. Should hopefully be a good starting point for someone to make something useful, though.







        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited Nov 23 '18 at 6:09









        Ghost4Man

        5311613




        5311613










        answered Nov 18 '15 at 16:41









        Dan Bryant

        24.1k34488




        24.1k34488

























            1














            This sounds a lot like the StringFormat attribute introduced in .Net 3.5. As you quote, "writing the text of the string along with expressions that will fill in 'holes' in the string", this can be performed within a XAML binding like this:



            <TextBlock Text="{Binding Amount, StringFormat=Total: {0:C}}" />


            Since you can use any of the custom string formats, there's a lot of power under the hood here. Or are you asking something else?






            share|improve this answer

















            • 2




              The OP is asking something else. String interpolation is added in C# 6 and works only with Visual Studio 2015 RC. You can now write $"{myDateVar:yyyy-MM-dd} Boo" instead of the equivalent String.Format("{0:yyyy-MM-dd} Boo",myDateVar)
              – Panagiotis Kanavos
              May 26 '15 at 16:14
















            1














            This sounds a lot like the StringFormat attribute introduced in .Net 3.5. As you quote, "writing the text of the string along with expressions that will fill in 'holes' in the string", this can be performed within a XAML binding like this:



            <TextBlock Text="{Binding Amount, StringFormat=Total: {0:C}}" />


            Since you can use any of the custom string formats, there's a lot of power under the hood here. Or are you asking something else?






            share|improve this answer

















            • 2




              The OP is asking something else. String interpolation is added in C# 6 and works only with Visual Studio 2015 RC. You can now write $"{myDateVar:yyyy-MM-dd} Boo" instead of the equivalent String.Format("{0:yyyy-MM-dd} Boo",myDateVar)
              – Panagiotis Kanavos
              May 26 '15 at 16:14














            1












            1








            1






            This sounds a lot like the StringFormat attribute introduced in .Net 3.5. As you quote, "writing the text of the string along with expressions that will fill in 'holes' in the string", this can be performed within a XAML binding like this:



            <TextBlock Text="{Binding Amount, StringFormat=Total: {0:C}}" />


            Since you can use any of the custom string formats, there's a lot of power under the hood here. Or are you asking something else?






            share|improve this answer












            This sounds a lot like the StringFormat attribute introduced in .Net 3.5. As you quote, "writing the text of the string along with expressions that will fill in 'holes' in the string", this can be performed within a XAML binding like this:



            <TextBlock Text="{Binding Amount, StringFormat=Total: {0:C}}" />


            Since you can use any of the custom string formats, there's a lot of power under the hood here. Or are you asking something else?







            share|improve this answer












            share|improve this answer



            share|improve this answer










            answered May 26 '15 at 16:10









            karfus

            4231514




            4231514








            • 2




              The OP is asking something else. String interpolation is added in C# 6 and works only with Visual Studio 2015 RC. You can now write $"{myDateVar:yyyy-MM-dd} Boo" instead of the equivalent String.Format("{0:yyyy-MM-dd} Boo",myDateVar)
              – Panagiotis Kanavos
              May 26 '15 at 16:14














            • 2




              The OP is asking something else. String interpolation is added in C# 6 and works only with Visual Studio 2015 RC. You can now write $"{myDateVar:yyyy-MM-dd} Boo" instead of the equivalent String.Format("{0:yyyy-MM-dd} Boo",myDateVar)
              – Panagiotis Kanavos
              May 26 '15 at 16:14








            2




            2




            The OP is asking something else. String interpolation is added in C# 6 and works only with Visual Studio 2015 RC. You can now write $"{myDateVar:yyyy-MM-dd} Boo" instead of the equivalent String.Format("{0:yyyy-MM-dd} Boo",myDateVar)
            – Panagiotis Kanavos
            May 26 '15 at 16:14




            The OP is asking something else. String interpolation is added in C# 6 and works only with Visual Studio 2015 RC. You can now write $"{myDateVar:yyyy-MM-dd} Boo" instead of the equivalent String.Format("{0:yyyy-MM-dd} Boo",myDateVar)
            – Panagiotis Kanavos
            May 26 '15 at 16:14


















            draft saved

            draft discarded




















































            Thanks for contributing an answer to Stack Overflow!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            To learn more, see our tips on writing great answers.





            Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


            Please pay close attention to the following guidance:


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f30459680%2fstring-interpolation-in-xaml%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            What visual should I use to simply compare current year value vs last year in Power BI desktop

            How to ignore python UserWarning in pytest?

            Alexandru Averescu