124

Please take a look at the following line

<TextBox Text="{Binding Price}"/>

This Price property from above is a Decimal? (Nullable decimal).

I want that if user deletes the content of the textbox (i.e. enters an empty string), it should automatically update the data source (the target of the binding) with null (Nothing in VB).

Any ideas on how I can do it in XAML?

Nathan Phillips
  • 11,899
  • 1
  • 31
  • 24
Shimmy Weitzhandler
  • 101,809
  • 122
  • 424
  • 632

3 Answers3

239

I am using .NET 3.5 SP1 so it's very simple:

<TextBox Text="{Binding Price, TargetNullValue=''}"/>

Which stands for (thanks Gregor for your comment):

<TextBox Text="{Binding Price, TargetNullValue={x:Static sys:String.Empty}}"/>

sys is the imported xml namespace for System in mscorlib:

xmlns:sys="clr-namespace:System;assembly=mscorlib"

Hope that helped.

Scott Munro
  • 13,369
  • 3
  • 74
  • 80
Shimmy Weitzhandler
  • 101,809
  • 122
  • 424
  • 632
  • 14
    Actually TargetNullValue works just fine. What it does is set an equivalence between the given value and null. So in this case when the bound value is null it will display an empty string and when the target's value is the empty string it will set the bound value to null. – Bryan Anderson Dec 13 '09 at 16:19
  • 4
    The TargetNullValue works. I got same results when using the value converter. You can also simplify the expression: – Gregor Slavec May 10 '11 at 08:24
  • 2
    I'm confused - the OP says: "..it should automatcally update source with null [when Target is an empty string].", but TargetNullValue updates the _Target_, not the _Source_! – markmnl Jul 03 '13 at 01:18
  • 1
    You're not the only confused one - there are confused comments on the other answer too. The OP also is slightly confused, when he says update the source, he actually means the Target in WPF speak (the source is the Text property on the TextBox). TargetNullValue says what value to set the Source to when the Target is null. The reverse of this, which is what we're taking advantage of here, is that when the source is updated to this specified value, then the target will be set to null. – Nathan Phillips Oct 11 '13 at 18:03
  • @markmnl While TargetNullValue is indeed intended to updated the `Target` and not the `Source`, this solution still does the trick for some reason (I could not quite figure out why). – Tim Pohlmann Apr 04 '16 at 11:48
  • @markmnl I made a new question regarding TargetNullValue: http://stackoverflow.com/questions/36402291/why-does-targetnullvalue-update-nullable-source – Tim Pohlmann Apr 06 '16 at 07:08
  • a virtual pint from me! Cheers man! – pbou Dec 14 '21 at 17:38
12

This value converter should do the trick :

public class StringToNullableDecimalConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, 
        CultureInfo culture)
    {
        decimal? d = (decimal?)value;
        if (d.HasValue)
            return d.Value.ToString(culture);
        else
            return String.Empty;
    }

    public object ConvertBack(object value, Type targetType, 
        object parameter, CultureInfo culture)
    {
        string s = (string)value;
        if (String.IsNullOrEmpty(s))
            return null;
        else
            return (decimal?)decimal.Parse(s, culture);
    }
}

Declare an instance of this converter in the ressources :

<Window.Resources>
    <local:StringToNullableDecimalConverter x:Key="nullDecimalConv"/>
</Window.Resources>

And use it in your binding :

<TextBox Text="{Binding Price, Converter={StaticResource nullDecimalConv}}"/>

Note that TargetNullValue is not appropriate here : it is used to define which value should be used when the source of the binding is null. Here Price is not the source, it's a property of the source...

bargz
  • 153
  • 2
  • 4
Thomas Levesque
  • 286,951
  • 70
  • 623
  • 758
  • 2
    A converter is the proper way to do this, and you can't define these converters in XAML. Converters allow you to change the default "object to object" conversion behavior in data-binding, which is what you're wanting to do. – Will Eddins Dec 13 '09 at 03:40
  • The problem in my case is that I already use a convereter here that does another thing. I posted an answer, please take a look. – Shimmy Weitzhandler Dec 13 '09 at 03:44
  • might want to use IsNullOrWhiteSpace() to allow " " to be counted as null (most probably what you want) – Simon_Weaver Jul 27 '11 at 22:47
  • +1 However: Price is your source here but you are correct TargetNullValue is not appropriate here - TargetNullValue sets the _target_ when the source is null - whereas we want to set the _source_ (to null) when the target is a certain value (an empty string) - which your converter does. – markmnl Jul 03 '13 at 01:49
5

You can try using a ValueConverter (IValueConverter) http://msdn.microsoft.com/en-us/library/system.windows.data.ivalueconverter.aspx

Of the back of my head here, something like:

public class DoubleConverter : IValueConverter
{
    public object Convert(object value, Type targetType, 
        object parameter, CultureInfo culture)
    {
        return (double)value;
    }

    public object ConvertBack(object value, Type targetType, 
        object parameter, CultureInfo culture)
    {
    var doubleValue = Convert.ToDouble(value);

    return (doubleValue == 0 ? null : doubleValue);
    }
}

(Might need some tweaking though)

Shimmy Weitzhandler
  • 101,809
  • 122
  • 424
  • 632
TimothyP
  • 21,178
  • 26
  • 94
  • 142