2012-05-10 68 views
1

注:取決於this quetionGUI凍結而Dispatcher.BeginInvoke或Task.StartNew

嗨。我有一個視圖模型是這樣的:

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); 
    } 

} 

,並在IPersonService實現我這樣做:

public class PersonService : IPersonService { 
    public IEnumerable<SearchPersonModel> DoSearch(string term){ 
     System.Threading.Thread.Sleep(10000); 
     return some-search-result; 
    } 
} 

但是,我希望,雖然搜索執行查詢時,GUI是免費的。但它凍結了!你有什麼想法我的錯誤在哪裏?你能幫我嗎?先謝謝了!

回答

3

問題是評估task.Result將阻塞,直到查詢完成。

最簡單的選擇可能是讓Search方法代之以執行_dispatcher.BeginInvoke調用。

另一個選項 - 使用C#5會變得更容易 - 將增加任務的延續,以便完成後可以更新UI。目前您使用Task.ContinueWith;在C#5中,您將使用asyncawait

+0

非常感謝你**救援天使**所以你認爲我的取消邏輯是真的嗎? –

+0

還有一個問題:我可以使用'Task'和'BackgroundWorker'來實現取消。你建議哪一個?哪一個有更好的表現? –

+1

兩者之間的表現不會有顯着差異;這不是你應該基於你的決定。 – Servy