Question

I'm binding a TextBox to a property of my ViewModel. When the user clicks on an ApplicationBar Button, a command is being called (I'm using BindableApplicationBar, which can be found on NuGet). Problem is that when the user types in the TextBox and clicks right away the Application Button, the setter of the TextBox is not being called, which means that the ButtonCommand is using the old text.

I've seen a lot of solutions, but I can't use them in my situation. The only "solution" would be to get rid of the ApplicationBar and use instead a button, which is behind the Keyboard (which pops up when the user clicks on the TextBox. I'm using Windows Phone, so that's why there's a KeyBoard...). So the user has to click somewhere else to use the button -> lostfocus.

Some solutions:

WPF Databind Before Saving

Binding with UpdateSourceTrigger==LostFocus do not fire for Menu or Toolbar interaction

I cant use UpdateSourceTrigger=PropertyChanged and I'm using MVVM, so I also don't really want to use CodeBehind. If there's no other way to do it without CodeBehind, then it's ok.

Was it helpful?

Solution

One solution I've used in the past is to update the binding whenever the contents of the text box changes, rather than when focus is lost.

A simple, reusable way to do this is with a behaviour.

Something like this:

public class RebindOnTextChanged : Behavior<TextBox>
{
    protected override void OnAttached()
    {
        base.OnAttached();
        this.AssociatedObject.TextChanged += this.TextChanged;
    }

    protected override void OnDetaching()
    {
        base.OnDetaching();
        this.AssociatedObject.TextChanged -= this.TextChanged;
    }

    private void TextChanged(object sender, TextChangedEventArgs e)
    {
        var bindingExpression = this.AssociatedObject.GetBindingExpression(TextBox.TextProperty);
        if (bindingExpression != null)
        {
            bindingExpression.UpdateSource();
        }
    } 
}      

and used like:

<TextBox Text="{Binding SomeProperty}">
    <i:Interaction.Behaviors>
        <behaviours:RebindOnTextChanged />
    </i:Interaction.Behaviors>
</TextBox>

OTHER TIPS

The problem (or bug in the framework?) that is occurring here is that the AppBar is not a real Silverlight control so it's being handled differently in terms of stealing focus. I'm not sure how this fits into your design, but in one of my apps I used the following pattern:

    void appBarButton_Click(object sender, EventArgs e)
    {
        // removal of focus from the TextBox to the Page will force the bind.
        this.Focus();

        // wait till the next UI thread tick so that the binding gets updated
        Dispatcher.BeginInvoke(() =>
        {
            // at this point the binding is updated
            MessageBox.Show(RandomText);
        });
    }

This is kind of gross but I used a helper function to wrap a number of different paths that were hitting that so that they didn't have to know about the extra dispatch, or which control was going to steal focus after hitting the button.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top