Reputation: 878
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
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
Reputation: 13669
WPF approach
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
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
Reputation: 7601
you have to raise the event like RaisePropertyChanged
like
public String SearchText
{
get
{
return _searchString;
}
set
{
_searchString = value;
RaisePropertyChanged("functionProvidersView");
}
}
Upvotes: 0