Recently while developing a new app for Windows Phone I ran into a strange problem. Using Caliburn.Micro I set up a binding with a simple TextBox control. Also on the page in an Application Bar Button which raises a Save action method in the view model. The bug was that every time I saved the entity, the Name would be null in the backend service. The debug process revealed that the Property Update for the Name was happening AFTER the Save method.
Reading the documentation and posts by other developers I discovered that the default mode for source updates happens on “Lost Focus” and that, for whatever reason, when the user presses an Application Bar Button the control does NOT actually lose focus, thus the property update happens AFTER the view model method is executed. In Silverlight and WPF, you can set the UpdateSourceTrigger to PropertyChanged which will handle this case.
Unfortunately, for whatever reason, Windows Phone Silverlight does not support this feature so the only option is to update on focus, which obviously doesn’t work. However, this feature is available with some support from the Microsoft Patterns & Practices Prism framework in the UpdateTextBindingOnPropertyChanged custom behavior. Here is the source for the class:
1: public class UpdateTextBindingOnPropertyChanged : Behavior
2: {
3: private BindingExpression expression;
4:
5: protected override void OnAttached()
6: {
7: base.OnAttached();
8:
9: this.expression = this.AssociatedObject.GetBindingExpression(TextBox.TextProperty);
10: this.AssociatedObject.TextChanged += this.OnTextChanged;
11: }
12:
13: protected override void OnDetaching()
14: {
15: base.OnDetaching();
16:
17: this.AssociatedObject.TextChanged -= this.OnTextChanged;
18: this.expression = null;
19: }
20:
21: private void OnTextChanged(object sender, EventArgs args)
22: {
23: this.expression.UpdateSource();
24: }
25: }
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
What this behavior is doing is attaching itself the given control and calling UpdateSource on a custom binding which will force the source to update. In this case, we are associating this source update with the TextChanged event which will cause the property to update as the value of the Textbox changes. (Side note: you will also need to include the System.Windows.Interactivity to get the Behavior project).
Now, to actually use this class, you will need to write some code behind, just two lines. There might be a way to get this into the declarative binding syntax in the XAML, but I do not know how to do that. Here is the code which adds this behavior, it is in the constructor just after the InitalizeComponent.
public SaveLocationView()
{
InitializeComponent();
// manual bindings
var behavior = new UpdateTextBindingOnPropertyChanged();
System.Windows.Interactivity.Interaction.GetBehaviors(tbName).Add(behavior);
}
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
Very simple, hence why I didnt pursue trying to get it into the binding syntax. This correctly fixes the problem with the updating. I hope people find this helpful, and I do hope Microsoft makes this functionality native in future versions.