user3596113
user3596113

Reputation: 878

Find out whether textbox text didnt change for a second in mvvm pattern

Can anyone help me to find out whether my TextBox's text didn't change for one second or not in MVVM pattern (using WPF).

In my ViewModel, I have a property

public String SearchText
{
    get
    {
        return _searchString;
    }

    set
    {
        _searchString = value;
        _functionProvidersView.Refresh();
    }
}

where _functionProvidersView is of Type ObservableCollection<FunctionProviderViewModel>. I want that refresh to happen only if the text didn't change for one second.

I tried to solve that problem with System.Threading but that didn't do the trick, does anyone have a simple solution?

Edit: Based on that SearchText my Collection is filtered. And because my Filter mechanism is taking some time, I want the filtering only happen if a user didn't change the Textbox text (didn't type anything) for one second.

The TextBox Attribute UpdateSourceTrigger is set to PropertyChanged. I could set this to LostFocus but that's not exactly what I want...

Upvotes: 2

Views: 315

Answers (3)

Alberto
Alberto

Reputation: 15941

One way is to use a timer to delay the refresh invocation:

public class MainVm
{
    System.Threading.Timer timer;

    private string searchText = string.Empty;
    public string SearchText
    {
        get { return searchText; }
        set
        {
            searchText = value;

            timer.Change(1000, System.Threading.Timeout.Infinite); //reset the timer
        }
    }

    public MainVm()
    {
        timer = new System.Threading.Timer(RefreshView, 
                                           null, 
                                           System.Threading.Timeout.Infinite,
                                           System.Threading.Timeout.Infinite);
    }

    private void RefreshView(object state)
    {
        //Here you need to use the dispatcher because the callback is called
        //from a non-UI thread
        Application.Current.Dispatcher.Invoke(new Action(() =>
            _functionProvidersView.Refresh()
        );
    }
}

In this way the RefreshView method will called after 1 second you stopped typing

Upvotes: 1

pushpraj
pushpraj

Reputation: 13669

WPF approach

  • defined a storyboard on TextChanged event
  • added a boolean animation with two frames false at 0 and true at 1 second (you can customize as per your need, perhaps bind to settings)

    <TextBox>
        <TextBox.Triggers>
            <EventTrigger RoutedEvent="TextBox.TextChanged" >
                <BeginStoryboard>
                    <Storyboard>
                        <BooleanAnimationUsingKeyFrames Storyboard.TargetProperty="DataContext.TextChanged" >
                            <DiscreteBooleanKeyFrame KeyTime="0:0:0" Value="False" />
                            <DiscreteBooleanKeyFrame KeyTime="0:0:1" Value="True"/>
                        </BooleanAnimationUsingKeyFrames>
                    </Storyboard>
                </BeginStoryboard>
            </EventTrigger>
        </TextBox.Triggers>
    </TextBox>
    

this will trigger property change upon text change and will send value as true at 1 second

code for view model

  • added a property in view model to trigger the refresh
  • in OnChanged handler i'll perform my logic for refresh etc

    public bool TextChanged
    {
        get { return (bool)GetValue(TextChangedProperty); }
        set { SetValue(TextChangedProperty, value); }
    }
    
    // Using a DependencyProperty as the backing store for TextChanged.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty TextChangedProperty =
        DependencyProperty.Register("TextChanged", typeof(bool), typeof(ViewModel), new PropertyMetadata(false,OnTextChanged));
    
    private static void OnTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        if ((bool)e.NewValue)
        {
            //your logic after 1 second
            (d as ViewModel)._functionProvidersView.Refresh();
        }
    }
    

    in this approach you dont have to manage timer manually it will be handled by wpf

Upvotes: 0

Dhaval Patel
Dhaval Patel

Reputation: 7601

you have to raise the event like RaisePropertyChanged like

public String SearchText
   {
    get
    {
        return _searchString;
    }

    set
    {
        _searchString = value;
       RaisePropertyChanged("functionProvidersView");
    }
   }

Upvotes: 0

Related Questions