53

Is there a standard way to set a default or fallback value for a WPF binding if the bound string is empty?

<TextBlock Text="{Binding Name, FallbackValue='Unnamed'" />

The FallbackValue only seems to kick in when Name is null, but not when it is set to String.Empty.

Askolein
  • 3,250
  • 3
  • 28
  • 40
kroimon
  • 2,062
  • 3
  • 19
  • 23
  • 3
    there is a much simple answer at [enter link description here][1] [1]: http://stackoverflow.com/questions/16612622/give-textblock-default-value-if-result-returns-null – FLICKER Feb 05 '15 at 19:07
  • there is a much simple solution at [TextBox Default Value if Binding returns null][1] [1]: http://stackoverflow.com/questions/16612622/give-textblock-default-value-if-result-returns-null – FLICKER Feb 05 '15 at 19:09

4 Answers4

82

DataTrigger is the way i do it like this:

<TextBox>
  <TextBox.Style>
        <Style TargetType="{x:Type TextBox}"  BasedOn="{StaticResource ReadOnlyTextBox}">
            <Setter Property="Text" Value="{Binding Name}"/>
            <Style.Triggers>
                <DataTrigger Binding="{Binding Path=Name.Length, FallbackValue=0, TargetNullValue=0}" Value="0">
                    <Setter Property="Text" Value="{x:Static local:ApplicationLabels.NoValueMessage}"/>
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </TextBox.Style>
</TextBox>
iltzortz
  • 2,342
  • 2
  • 19
  • 35
  • I like this approach because it let's me bind the default value to another property in my ViewModel. Thanks :) – Daniel Gruszczyk Oct 06 '17 at 16:51
  • 1
    you can probably also do `Name` and empty string instead of `Name.length`, totally love this approach :) – EricG Oct 20 '17 at 15:41
  • Seeing as `Name` is generally a `string`, then `Name.Length` would be of type `Int32`. For this reason, there is no need specify `TargetNullValue` because the the expression will never evaluate to `null`, granted it evaluates at all. `FallbackValue` is the property pulling the weight here. – Nicholas Miller Sep 11 '18 at 21:13
  • 1
    ugly way to do this... should be 1 liner for such a simple thing. – Konrad Jun 27 '19 at 09:09
44

I was under the impression that FallbackValue provides a value when the binding fails and TargetNullValue provides a value when the bound value is null.

To do what you want you will either need a converter (possibly with a parameter) to convert an empty string to a target value, or put the logic in your view model.

I would probably go with a converter something like this (not tested).

public class EmptyStringConverter : MarkupExtension, IValueConverter
{  
    public object Convert(object value, Type targetType, 
                          object parameter, CultureInfo culture)
    {
        return string.IsNullOrEmpty(value as string) ? parameter : value;
    }

    public object ConvertBack(object value, Type targetType, 
                              object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }

    public override object ProvideValue(IServiceProvider serviceProvider)
    {
        return this;
    }
}
Phil
  • 42,255
  • 9
  • 100
  • 100
9

You should create a converter for this, which implements IValueConverter

public class StringEmptyConverter : IValueConverter {

public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
      return string.IsNullOrEmpty((string)value) ? parameter : value;
    }

public object ConvertBack(
      object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
      throw new NotSupportedException();
    }

}

Then in xaml you'd just provide the converter to the binding, (xxx just represents your Window / UserControl / Style ... where the binding is)

<xxx.Resources>
<local:StringEmptyConverter x:Key="StringEmptyConverter" />
</xxx.Resources>
<TextBlock Text="{Binding Name, Converter={StaticResource StringEmptyConverter}, ConverterParameter='Placeholder Text'}" />
Viv
  • 17,170
  • 4
  • 51
  • 71
0

You could use a converter and do the respective validation on it.

Binding="{Binding Path=Name, Converter={StaticResource nameToOtherNameConverter}}"

and in your converter

public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (!string.IsNullOrEmpty(value.ToString()))
        { /*do something and return your new value*/ }
Santux
  • 367
  • 1
  • 3
  • 13