locked
TwoWay Binding working on strings, but not on datetimes and int - Release Preview RRS feed

  • Question

  • I have twoway binding setup for my data entry form.  After making edits to the form, the model's string properties have received the changes, but the dates and ints are not receiving the twoway communication.

    <TextBlock Text="Short Description: " Style="{StaticResource TitleTextStyle}" Margin="0,0,0,5"/>
    <TextBox Text="{Binding SelectedItem.ShortDescription, Mode=TwoWay}"/>
    <TextBlock Text="Purchase Date: " Style="{StaticResource TitleTextStyle}" Margin="0,0,0,5"/>
    <TextBox Text="{Binding SelectedItem.PurchaseDate, Mode=TwoWay}"/>

    My Model is based on BindableBase

    public class Item : BindableBase
    
    private DateTime _DateAdded;
    [DataMemberAttribute]
    public DateTime DateAdded
    {
        get { return this._DateAdded; }
        set { this.SetProperty(ref this._DateAdded, value); }
    }
    Any help would be appreciated.

    Thanks, Terrence



    • Edited by Terrence_ Wednesday, June 20, 2012 3:21 PM
    Wednesday, June 20, 2012 1:38 PM

Answers

  • Terrence,

    The reason I couldn't repeat the problem is because you said you were using an int.  It appears from your most recent post that it is a decimal.  In that case I can repeat the problem.  Not entirely sure why a there is a problem, but its pretty easy to solve.  Here's the code for a converter:

    public class DecmialConverter:IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, string language)
        {
            return value.ToString();
        }
        public object ConvertBack(object value, Type targetType, object parameter, string language)
        {
            return decimal.Parse(value as string);
        }
    }

    and in your page:

    <Page.Resources>
        <local:DecmialConverter x:Key="DecmialConverter"/>
    </Page.Resources>
    ...
    <TextBlock Text="Short Description: " Style="{StaticResource TitleTextStyle}" Margin="0,0,0,5"/>
    <TextBox Text="{Binding Number, Mode=TwoWay,Converter={StaticResource DecmialConverter}}" />

    and you should be good to go.

    ...Stefan

    • Marked as answer by Jesse Jiang Monday, June 25, 2012 1:57 AM
    Thursday, June 21, 2012 3:11 AM
  • Well what you do depends on the context of your application. What you ideally want to do is to some sort of validation.  Unfortunately WinRT doesn't have validation (http://social.msdn.microsoft.com/Forums/en-IE/winappswithcsharp/thread/9df8acb3-5f2a-46d0-8706-5fc3258e2c9c).

    Fundamentally the system is not built for line of business applications, so it's going to be difficult.  Quite frankly it would be almost tempting if I would have to do what you're doing to handle either the TextChanged or lost focus events and then parse it manually (no binding) and if there was an error then display a border red around the outside to indicate an error, otherwise fill your model with data.  Really depends on your application. If you can interpret a result if it can't parse properly, then you can use the converter but the whole situation is really going to be pretty difficult to manage.

    HTH. Let me know if enough I need to be any clearer on any of that.

    ...Stefan

    • Marked as answer by Jesse Jiang Monday, June 25, 2012 1:57 AM
    Thursday, June 21, 2012 4:04 AM

All replies

  • In my projects, I implement INotifyPropertyChanged myself.  I am betting that this has to do with the fact that DateTime and Int are value types.  When SetProperty tries to use the references, it swallows an exception, and the PropertyChanged event isn't raised.

    Wednesday, June 20, 2012 1:55 PM
  • InLoco, thanks for your thoughts.

    So you think Microsoft's latest and greatest efforts to guide us in the right direction on XAML binding via the BindableBase base class is flawed?  It is not out of the question, but I would hope they would have tested it in this simple situation.

    Could someone from MS comment on this, or someone else point out my error?

    Thanks.


    Thanks, Terrence

    Wednesday, June 20, 2012 3:00 PM
  • @Terrence,

    can you give me an example of the problem you're having with binding to numbers?  It works perfectly fine for me.  Also check the output window. There may be an error there.  For example, it is unable to convert dates by default:

    Error: Cannot save value from target back to source. BindingExpression: Path='DateAdded' DataItem='IntBindingBug.Item, IntBindingBug, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'; target element is 'Windows.UI.Xaml.Controls.TextBox' (Name='null'); target property is 'Text' (type 'String').

    So what you need to do in that situation is add a converter.

    ...Stefan

    Wednesday, June 20, 2012 9:19 PM
  • Stephan, thanks for your comments.

    Well I will check for errors in the output window when I get home tonight, but as far as numbers go, when I change on on the form, the change is not reflected in the model that it is bound to.  All textboxes bound to strings that change, the model reflects the changes.


    Thanks, Terrence

    Wednesday, June 20, 2012 9:24 PM
  • Well this works for me:

    public class Item : BindableBase
    {
        private int _number;
        [DataMember]
        public int Number
        {
            get { return this._number; }
            set { this.SetProperty(ref this._number, value); }
        }
        private DateTime _DateAdded;
        [DataMember]
        public DateTime DateAdded
        {
            get { return this._DateAdded; }
            set { this.SetProperty(ref this._DateAdded, value); }
        }
    }

    and:

    <TextBox Text="{Binding Number, Mode=TwoWay}"/>

    If put a breakpoint in the set for the Number, it does get called, which I assume you are suggesting isn't happening for you?

    The other thing to remember is that the model will not be updated until the focus leaves the textbox, but given that the strings are updating, I assume that you have figured that out.

    ...Stefan

    Wednesday, June 20, 2012 9:28 PM
  • Stefan, I will look into it in about 2 hours when I get home and report back with I find.

    Thank you for your help.


    Thanks, Terrence

    Wednesday, June 20, 2012 9:33 PM
  • I suspect the issue is the fact that I am binding to an object, my ViewModel, that has many objects on it.

    My textboxes are bound to SelectedItem.ShortDescription (string), and  SelectedItem.PurchasePrice (int).

    Here is my error:

    //Error: Cannot save value from target back to source.

    //BindingExpression: Path='SelectedItem.PurchasePrice'

    //DataItem='NVIN_Metro.DataModel.ViewModel, NVIN_Metro, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null';

    //target element is 'Windows.UI.Xaml.Controls.TextBox' (Name='null');

    //target property is 'Text' (type 'String').'NVIN_Metro.exe' (Managed (v4.0.30319)):

    //Loaded 'C:\Windows\assembly\GAC_MSIL\Microsoft.VisualStudio.Debugger.Runtime\11.0.0.0__b03f5f7f11d50a3a\Microsoft.VisualStudio.Debugger.Runtime.DLL'


    Thanks, Terrence

    Thursday, June 21, 2012 2:01 AM
  • Can you try using an IValueConverter to see if that helps?

    ...Stefan

    Thursday, June 21, 2012 2:43 AM
  • Well I was trying to avoid adding more complexity to my system.  If int's work for you without a converter then they should work for me.

    I have noticed that the BinableBase : INotifyPropertyChanged

    class does not even get called when I change an int or a datetime, yet it does get called when a string is called.


    Thanks, Terrence

    Thursday, June 21, 2012 2:58 AM
  • Terrence,

    The reason I couldn't repeat the problem is because you said you were using an int.  It appears from your most recent post that it is a decimal.  In that case I can repeat the problem.  Not entirely sure why a there is a problem, but its pretty easy to solve.  Here's the code for a converter:

    public class DecmialConverter:IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, string language)
        {
            return value.ToString();
        }
        public object ConvertBack(object value, Type targetType, object parameter, string language)
        {
            return decimal.Parse(value as string);
        }
    }

    and in your page:

    <Page.Resources>
        <local:DecmialConverter x:Key="DecmialConverter"/>
    </Page.Resources>
    ...
    <TextBlock Text="Short Description: " Style="{StaticResource TitleTextStyle}" Margin="0,0,0,5"/>
    <TextBox Text="{Binding Number, Mode=TwoWay,Converter={StaticResource DecmialConverter}}" />

    and you should be good to go.

    ...Stefan

    • Marked as answer by Jesse Jiang Monday, June 25, 2012 1:57 AM
    Thursday, June 21, 2012 3:11 AM
  • Stefan you are a life saver.  Thanks so much for your help.  That solved my problem, and now I can get back to writing code.

    I thought I was using int's but you are right, they are decimals.

    What does your datetime converter look like?  If you have written one.


    Thanks, Terrence

    Thursday, June 21, 2012 3:31 AM
  • Is pretty easy to write one, it is virtually the same:

    public class DateTimeConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, string language)
        {
            return value.ToString();
        }
        public object ConvertBack(object value, Type targetType, object parameter, string language)
        {
            return DateTime.Parse(value as string);
        }
    }
    You would need to error-checking in both of them, as Parse could cause an exception.
    Thursday, June 21, 2012 3:36 AM
  • Stefan what are  you doing if your user screws up the date text box and it does not parse into a datetime?

    If you don't have time for this, I understand.


    Thanks, Terrence

    Thursday, June 21, 2012 3:56 AM
  • Well what you do depends on the context of your application. What you ideally want to do is to some sort of validation.  Unfortunately WinRT doesn't have validation (http://social.msdn.microsoft.com/Forums/en-IE/winappswithcsharp/thread/9df8acb3-5f2a-46d0-8706-5fc3258e2c9c).

    Fundamentally the system is not built for line of business applications, so it's going to be difficult.  Quite frankly it would be almost tempting if I would have to do what you're doing to handle either the TextChanged or lost focus events and then parse it manually (no binding) and if there was an error then display a border red around the outside to indicate an error, otherwise fill your model with data.  Really depends on your application. If you can interpret a result if it can't parse properly, then you can use the converter but the whole situation is really going to be pretty difficult to manage.

    HTH. Let me know if enough I need to be any clearer on any of that.

    ...Stefan

    • Marked as answer by Jesse Jiang Monday, June 25, 2012 1:57 AM
    Thursday, June 21, 2012 4:04 AM
  • Well, you told me what I was thinking...No Validation.  I was looking for the standard way to validate, I guess I will have to hack it together like you suggested.

    Thanks again Stefan.

    What part of the world do you live in?  I am in Austin, Texas.


    Thanks, Terrence

    Thursday, June 21, 2012 12:08 PM
  • TRWTF is that there is currently no Metro-XAML (I'm not sure how one should call the UI framework for Metro-style apps using XAML, so I'm calling it that for short) Calendar or DatePicker control that comes with Windows 8.  However, if you wanted to get one, you can write your app using HTML/CSS/WinJS and use the HTML5 Calendar tag.  Just FYI; I haven't written my own HTML app for Metro yet.

    Thursday, June 21, 2012 1:40 PM
  • Thanks InLoco, I will sitck with xaml/c# until I can get a grip of how to better program on the platform.

    Thanks, Terrence

    Thursday, June 21, 2012 2:13 PM