views:

790

answers:

5

Using data binding, how do you bind a new object that uses value types?

Simple example:

public class Person() {
    private string _firstName;
    private DateTime _birthdate;
    private int _favoriteNumber;
    //Properties
}

If I create a new Person() and bind it to a form with text boxes. Birth Date displays as 01/01/0001 and Favorite Number as 0. These fields are required, but I would like these boxes to be empty and have the user fill them in.

The solution also needs to be able to default fields. In our example, I may want the Favorite Number to default to 42.

I'm specifically asking about Silverlight, but I assume WPF and WinForms probably have the same issue.

EDIT:

I thought of Nullable types, however we are currently using the same domain objects on client and server and I don't want to have required fields be Nullable. I'm hoping the databinding engine exposes a way to know it is binding a new object?

+2  A: 

Perhaps you can try Nullable types?

public class Person() {
    private string? _firstName;
    private DateTime? _birthdate;
    private int? _favoriteNumber;
    //Properties
}

or

public class Person() {
    private Nullable<string> _firstName;
    private Nullable<DateTime> _birthdate;
    private Nullable<int> _favoriteNumber;
    //Properties
}

which is actually the same.

Now, the default values are null, and you can force the properties to have a value by setting them.

More about Nullable types:

http://msdn.microsoft.com/en-us/library/b3h38hb0.aspx

Arcturus
A: 

I'd rewrite the Person class to looks something more like this...

public class Person
  {
    private int _favoriteNumber = 0;
    public string FavoriteNumber
    {
      get
      {
        return _favoriteNumber > 0 ? _favoriteNumber.ToString() : string.Empty;
      }
      set
      {
        _favoriteNumber = Convert.ToInt32(value);
      }
    }

    private DateTime _birthDate = DateTime.MinValue;
    private string BirthDate 
    {
      get
      {
        return _birthDate == DateTime.MinValue ? string.Empty : _birthDate.ToString(); //or _birthDate.ToShortDateString() etc etc
      }
      set
      {
        _birthDate = DateTime.Parse(value);
      }
    }
  }
Hovito
A: 

You can use the IValueConverter to format your textbox bindings to default values based on the value of the object. Here's a few links on the IValueConverter

http://ascendedguard.com/2007/08/data-binding-with-value-converters.html http://weblogs.asp.net/marianor/archive/2007/09/18/using-ivalueconverter-to-format-binding-values-in-wpf.aspx

Unfortunately this might not be what you need since you don't have the option of the Nullable value for each of these properties.

What you can do is to set the default properties for your object when you do the databinding.

You can do this by having a Person.Empty object for default values. Or setting these values explicitly when the DataContext is set.

Either way should work though :)

nyxtom
+1  A: 

Try using a value converter, here's an example that should get your started.

The basic idea is to convert the default value for a type to null when the data is being displayed, and to convert any null values back to the types default value, when the binding source is updated.

public class DefaultValueToNullConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        object result = value;
        Type valueType = parameter as Type;

        if (value != null && valueType != null && value.Equals(defautValue(valueType)))
        {
            result = null;
        }

        return result;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        object result = value;
        Type valueType = parameter as Type;

        if (value == null && valueType != null )
        {
            result = defautValue(valueType);
        }
        return result;
    }

    private object defautValue(Type type)
    {
        object result = null;
        if (type == typeof(int))
        {
            result = 0;
        }
        else if (type == typeof(DateTime))
        {
            result = DateTime.MinValue;
        }
        return result;
    }
}

Then in your xaml reference the converter like this

<Page.Resources>
    <local:DefaultValueToNullConverter x:Key="DefaultValueToNullConverter"/>
</Page.Resources>

<TextBox 
    Text="{Binding 
            Path=BirthDate, 
            Converter={StaticResource DefaultValueToNullConverter},
            ConverterParameter={x:Type sys:DateTime}}" 
    />
Ian Oakes
A: 

After you have your converter in place, you also need to impliment INotifyPropertyChanged on the Person object. That way you can set the binding's Mode=TwoWay two way databinding will update the value in the object when a change is made on the textbox, and vis a vis.

Brian Leahy