Click here to Skip to main content
15,885,757 members
Please Sign up or sign in to vote.
5.00/5 (1 vote)
See more:
Hi,

I've got a very basic ViewModel that has a property SearchText and a command GetPersonsCommand:

C#
private string _searchText;
public string SearchText
{
    get
    {
        return _searchText;
    }
    set
    {
        if (value != this._searchText)
        {
           this._searchText = value;
           OnPropertyChanged("SearchText");
        }
    }
}
public BaseCommand GetPersonsCommand { get; set; }


There's nothing fancy happening in BaseCommand, it's just a basic implementation of ICommand.

View:
In my view, I have a "Search" TextBox. I created a Behavior that has a slight delay on TextChanged (allowing the user to type) and when they stop typing, my GetPersonsCommand gets fired. This works.
HTML
<TextBox x:Name="txtSearch" Text="{Binding SearchText, Mode=TwoWay}">
    <i:Interaction.Behaviors>
        <b:DelayTextBox Command="{Binding GetPersonsCommand}" Interval="1000" />
    </i:Interaction.Behaviors>


This is what happens: User types in TextBox -> When they stop typing GetPersonsCommand gets fired. Great so far...

My issue is that the first time the user types "John", the Command is fired, the SearchText property is still blank. Now the user types again "John Doe" and the SearchText property is now "John".

Why does the SearchText property only update itself after my Command is fired? In my head, when a user changes the text in the TextBox, because of the 2 way binding, the ViewModel's SearchText property should IMMEDIATELY be updated.

What am I doing wrong?

Here's my behavior, incase that matters....
C#
public class DelayTextBox : Behavior<TextBox>
{
    #region Properties

    public ICommand Command
    {
        get { return (ICommand)GetValue(CommandProperty); }
        set { SetValue(CommandProperty, value); }
    }

    public static readonly DependencyProperty CommandProperty =
        DependencyProperty.Register("Command", typeof(ICommand), typeof(DelayTextBox), null);

    public double Interval
    {
        get { return (double)GetValue(IntervalProperty); }
        set { SetValue(IntervalProperty, value); }
    }

    public static readonly DependencyProperty IntervalProperty =
        DependencyProperty.Register("Interval", typeof(double), typeof(DelayTextBox), new PropertyMetadata((s, e) =>
        {
            DelayTextBox parent = (DelayTextBox)s;
            if (parent != null && parent._timer != null)
            {
                parent._timer.Stop();
                parent._timer.Interval = TimeSpan.FromMilliseconds((double)e.NewValue);
            }
        }));

    #endregion

    private DispatcherTimer _timer;
    protected override void OnAttached()
    {
        base.OnAttached();

        this.AssociatedObject.TextChanged += AssociatedObject_TextChanged;

        this._timer = new DispatcherTimer();
        this._timer.Tick += timer_Tick;
        this._timer.Interval = TimeSpan.FromMilliseconds(this.Interval);
    }

    protected override void OnDetaching()
    {
        base.OnDetaching();

        this.AssociatedObject.TextChanged -= AssociatedObject_TextChanged;
        this._timer.Tick -= timer_Tick;
    }

    private void timer_Tick(object sender, EventArgs e)
    {
        this._timer.Stop();

        if (this.Command != null)
        {
            this.Command.Execute(null);
        }
    }

    private void AssociatedObject_TextChanged(object sender, TextChangedEventArgs e)
    {
        if (this._timer.IsEnabled)
        {
            this._timer.Stop();
            this._timer.Start();
        }
        else
        {
            this._timer.Start();
        }
    }
}


Thanks in advance!
Posted
Comments
Silvabolt 9-Jul-13 11:41am    
Hmmm, very well written question by the way, and I think you know more silverlight than I do, but it could be this. The binding property only updates every time the textbox loses focus because that's how it knows when all textbox changes and actions on it are complete.

So when you first type 'John', you haven't lost focus yet and you are probably checking the SearchText value somewhere in your GetPersonsCommand while the binding hasn't updated yet. After your command finishes, you may have done something to put focus on another control, so the binding finally updates to 'John'. Then when you type 'John Doe', it once again doesn't pick the change up until after your command finishes, but in the middle of your command, you will see the current value of 'John'. Hence the "delayed" updates. Try putting a debug point in the SearchText Property setter itself and see when it updates.
Dev_2580 10-Jul-13 4:18am    
Thanks for the reply. You're absolutely right in saying that its the property only changes when you lose focus. In Silverlight 5 you can set UpdateSourceTrigger=PropertyChanged in your binding and the ViewModel property is set when text property changes and not on lose focus.

Got my answer here.
http://social.msdn.microsoft.com/Forums/en-US/8051216a-a813-4d7f-9d02-cc0f0c5ec562/ui-sets-viewmodel-property-after-command-fired

Cheers!

1 solution

Got my answer here.

Just needed to add UpdateSourceTrigger=PropertyChanged to my binding to update the ViewModel property on TextChange and not on lose focus. (Silverlight 5)
 
Share this answer
 
v2

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900