drupal hit counter
Jerry Huang | All posts tagged 'data binding force update'

Jerry Huang apps and developing apps

Force a data binding to update

16. June 2012 18:41 by Jerry in Windows Phone Development

The beauty of data binding in Silverlight or WP7 is that it completely separate the UI and data access logics. The ugliness of data binding however is that it doesn't work or work as expect sometimes. The problem is always in Two-Way binding for data input. Consider a very common and straightforward scenario:

A regular page that contains a few textboxes and listpickers for user to input something, and there are 2 buttons inside the application bar - done and cancel. Once user tap the "done" button, data save( or do some validation before that); tap the cancel button simply reset all data input controls. As a result, the best way to implement this is to use a two-way data binding that binding the textbox's Text property to your ViewModal class. Very easy, just a few lines of coding. Is that it? In most cases, yes. However.......

If a user is tapping the "done" button without leaving the textbox (i.e. without losing focus on the textbox), what will happen? The expected behavior is the text binding to viewmodal class and data get saved. You are just too innocent if you think sowink. The text will never get update to your viewmodal class before losing focus. The reason is that the default UpdateSourceTrigger (check MSDN for details) for a textbox (or maybe other controls) is the LostFocus event. With WPF, you may easily change this property like:

[code language=XML]<textbox text="{Binding TextViewModelProperty}" updatesourcetrigger="PropertyChanged"> </textbox>[/code]

In Siliverlight for WP7 however, the XAML doesn't support UpdateSourceTrigger, so you will have to do it manually in your save function:

[code language=C#]object focusObj = FocusManager.GetFocusedElement();
if (focusObj != null && focusObj is TextBox)
{
    var binding = (focusObj as TextBox).GetBindingExpression(TextBox.TextProperty);
    binding.UpdateSource();
}[/code]

 

Once the UpdateSource methid is called, text will be flush to your view-model class. This is the way I used to force a data binding to be inforced. Above coding is based on the post here (no 9 answer):

http://stackoverflow.com/questions/5569768/textbox-binding-twoway-doesnt-update-until-focus-lost-wp7

*credit goes to "StefanWick" and "rrhartjr" (for the WPF part)

 

Is this the end of the story? Is your input page perfect now?  Hoho you wish. The following issue is not really related to data binding but it's very common in every data-input-page with use of application bar button to save. The problem is that data will be save twice if you tap the "done" button quick enough. This bug is actully exists in the latest Facebook app. When you post a piece of comment on somebody's photo in (WP7 facebook app), once tap the "send" button, progress bar (the dot dot dot stuff) shows up at top of the screen, if you tap the "send" button again (believe me, you can), your comment will be posted twice.

I don't know how others resolve this issue, but here is what I did:

1) Write a private function in the xaml.cs
[code language=C#]
         private void EnableControls(bool enabled)
         {
             foreach (Microsoft.Phone.Shell.ApplicationBarIconButton btn in ApplicationBar.Buttons)
             {
                 btn.IsEnabled = enabled;
             }
             pvMain.IsEnabled = enabled;//the Pivot control
         }
 [/code]

2) call EnableControls(false); before the save data function

3) I assume you will bind a property like "InProgress" to the progress bar's IsIndeterminate property, like:

[code language=XML]<toolkit:PerformanceProgressBar x:Name="progressBar" VerticalAlignment="Top" IsIndeterminate="{Binding InProgress}" />[/code]

so the trick here is to call EnableControls(true) when the InProgress becomes false which means the data is saved.
 

[code language=C#]
        void vmNewTrans_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
        {
            switch (e.PropertyName)
            {
                case "InProgress":
                    if (!vmNewTrans.InProgress)
                    {
                        EnableControls(true);
                    }
                    break;
            }
        }
[/code]

That's it! No matter how quick you try to save twice, you will never get duplicated data:)