96

I want to format my string binding as Amount is X where X is a property bound to a label.

I've seen many examples but the following doesn't work:

<Label Content="{Binding Path=MaxLevelofInvestment, 
   StringFormat='Amount is {0}'}" />

I've also tried these combinations:

StringFormat=Amount is {0}
StringFormat='Amount is {}{0}'
StringFormat='Amount is \{0\}'

I even tried changing the binding property's datatype to int, stringand double. Nothing seems to work. This is a very common use case but doesn't seem to be supported.

twip
  • 638
  • 2
  • 9
  • 20
Everything Matters
  • 2,672
  • 4
  • 25
  • 42

4 Answers4

249

The reason this doesn't work is that the Label.Content property is of type Object, and Binding.StringFormat is only used when binding to a property of type String.

What is happening is:

  1. The Binding is boxing your MaxLevelOfInvestment value and storing it the Label.Content property as a boxed decimal value.
  2. The Label control has a template that includes a ContentPresenter.
  3. Since ContentTemplate is not set, ContentPresenter looks for a DataTemplate defined for the Decimal type. When it finds none, it uses a default template.
  4. The default template used by the ContentPresenter presents strings by using the label's ContentStringFormat property.

Two solutions are possible:

  • Use Label.ContentStringFormat instead of Binding.StringFormat, or
  • Use a String property such as TextBlock.Text instead of Label.Content

Here is how to use Label.ContentStringFormat:

<Label Content="{Binding Path=MaxLevelofInvestment}" ContentStringFormat="Amount is {0}" />

Here is how to use a TextBlock:

<TextBlock Text="{Binding Path=MaxLevelofInvestment, StringFormat='Amount is {0}'}" />

Note: For simplicity I omitted one detail in the above explanation: The ContentPresenter actually uses its own Template and StringFormat properties, but during loading these are automatically template-bound to the ContentTemplate and ContentStringFormat properties of the Label, so it seems as if the ContentPresenter is actually using the Label's properties.

Nikhil Agrawal
  • 47,018
  • 22
  • 121
  • 208
Ray Burns
  • 62,163
  • 12
  • 140
  • 141
  • thanks for the detailed explanation, now it makes sense. up to WPF team to make this neat for the future. – Everything Matters Nov 18 '10 at 10:50
  • I like your answer, would you know how to use 2 params instead of just 1? Really struggling here (like TextBlock stringFormat can handle multiple when using triggers etc). – EricG Oct 23 '17 at 11:41
  • Why is it in this case you need to put **Path=** in front of your binding? normally i could just do `Content="{Binding MaxLevelofInvestment}"` and it works just fine... – MistaGoustan Nov 01 '18 at 15:56
  • 17
    For posterity: if you start a ContentStringFormat with a `{0}`, don't forget to put `{}` before it. So make it `ContentStringFormat="{}{0} some text here"` – jep Sep 10 '19 at 04:02
  • Also for posterity, see https://stackoverflow.com/a/7980937/120440 for the purpose of the `{}`-- it's baffling until you understand why. – Angelo Oct 05 '21 at 15:41
6

Make a universal StringFormatConverter : IValueConverter. Pass your format string as ConverterParameter.

Label Content="{Binding Amount, Converter={...myConverter}, ConverterParameter='Amount is {0}'"

Also, make StringFormatMultiConverter : IMultiValueConverter when you need more than one object in format string, for instance, Completed {0} tasks out of {1}.

Mogsdad
  • 44,709
  • 21
  • 151
  • 275
4

I just checked and for some reason it doesn't work with the Label, probably because it uses a ContentPresenter for the Content property internally. You can use a TextBlock instead and that will work. You could also put the TextBlock excerpt below in the content of a Label if you need to inherit styling, behaviour etc.

<TextBlock Text="{Binding Path=MaxLevelofInvestment, StringFormat='Amount is \{0\}'} />
Guy
  • 3,353
  • 24
  • 28
1

Try using a converter....

<myconverters:MyConverter x:Key="MyConverter"/>


<Label Content="{Binding Path=MaxLevelofInvestment, Converter={StaticResource MyConverter"} />


public class MyConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return String.Format("Amount is {0}", value);
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return value;
    }
}
Gabe
  • 49,577
  • 28
  • 142
  • 181
  • 4
    It is overkill. I explain the cause of the problem and present two simple solutions in my answer. – Ray Burns Nov 17 '10 at 21:56
  • I agree this hides usage, I've recently inherited a project where this approach was taken and would much prefer developers to use the build in StringFormat than roll their own. – Fermin Jan 25 '12 at 09:27