NOTE: Depends on this quetion
Hi. I have a view-model like this:
public class ViewModel {
private readonly IPersonService _personService;
private readonly ObservableCollection<SearchPersonModel> _foundedList;
private readonly DispatcherTimer _timer;
private readonly Dispatcher _dispatcher;
private CancellationTokenSource _tokenSource;
public SearchPatientViewModel(IPersonService personService) {
_personService = personService;
_foundedList = new ObservableCollection<SearchPersonModel>();
_dispatcher = (/*CurrentApplication*/).Dispatcher;
_timer = new DispatcherTimer(
TimeSpan.FromMilliseconds(1000),
DispatcherPriority.Normal,
TimerCallBack,
_dispatcher);
_tokenSource = new CancellationTokenSource();
}
public string Term {
get { return _term; }
set {
// implementing INotifyPropertyChanged
if(_term== value)
return;
_term= value;
OnPropertyChanged(() => Term);
tokenSource.Cancel(); // canceling prev search query
_timer.Stop(); // stop the timer to reset it
// start it again to do a search query if user change not the term for 1000ms
_timer.Start();
}
}
private void TimerCallBack(object sender, EventArgs e) {
_timer.Stop();
_tokenSource = new CancellationTokenSource();
var task = Task<IEnumerable<SearchPersonModel>>.Factory
.StartNew(Search, _tokenSource.Token);
_dispatcher.BeginInvoke((Action)(() => {
_foundedList.Clear();
foreach(var item in task.Result)
_foundedList.Add(item);
}), DispatcherPriority.Background);
}
private IEnumerable<SearchPersonModel> Search() {
return _personService.DoSearch(this.Term);
}
}
and in the IPersonService
implementation I do this:
public class PersonService : IPersonService {
public IEnumerable<SearchPersonModel> DoSearch(string term){
System.Threading.Thread.Sleep(10000);
return some-search-result;
}
}
However, I expect that while search query is executing, GUI be free. But it froze! Have you any idea where is my mistake? can you help me please? Thanks in advanced!
The problem is that evaluating
task.Result
will block until the query has completed.The simplest option is probably to make the
Search
method perform the_dispatcher.BeginInvoke
call at the end instead.Another option - which will become easier with C# 5 - would be to add a continuation to the task, so that when it's completed you can update the UI. At the moment you'd use
Task.ContinueWith
; with C# 5 you'd useasync
andawait
.