2010-03-28 56 views
9

嗨在WPF和MVVM上實現異步操作的最簡單方法是什麼?可以說用戶是否在用戶命中時輸入字段時我想啓動一個命令,然後返回而線程將執行一些搜索操作,然後返回返回並更新屬性,以便通知可以更新綁定。你如何在C#和MVVM中實現異步操作?

謝謝!

回答

3

BackgroundWorker如何在虛擬機上調用您的命令?

更新: 劃傷上述建議.. Jason Dolinger在MVVM上有一個在線視頻..我建議你看一看。這是一個更清晰的方式,視圖很薄/不包含任何線程代碼。

總結:

  • 的VM構造函數緩存Dispatcher.CurrentDispatcher對象(主線程)。
  • 更新後備存儲(結果)時,請使用 _dispatcher.BeginInvoke(() => _results.AddRange(entries))以便正確更新用戶界面。
+0

該綁定是否會反映更改有一個解決方法?你有沒有試過這種方法成功,謝謝Gishu – 2010-03-28 03:57:41

+0

@Oscar:看到更新...或更好的觀看那個視頻。 – Gishu 2010-03-28 15:59:40

+3

本來很高興地鏈接到視頻頁面: http://blog.lab49.com/archives/2650 – OwenP 2010-04-26 20:53:28

8

羅布·艾森伯格表現出了非常乾淨的實現他的MIX10 talk期間運行在MVVM異步操作。他已經在他的博客上發佈了源代碼。

其基本思想是您將該命令實現爲返回IEnumerable並使用yield關鍵字返回結果。這裏的代碼他的談話,這確實一個搜索作爲後臺任務的一個片段:

public IEnumerable<IResult> ExecuteSearch() 
    { 
     var search = new SearchGames 
     { 
      SearchText = SearchText 
     }.AsResult(); 

     yield return Show.Busy(); 
     yield return search; 

     var resultCount = search.Response.Count(); 

     if (resultCount == 0) 
      SearchResults = _noResults.WithTitle(SearchText); 
     else if (resultCount == 1 && search.Response.First().Title == SearchText) 
     { 
      var getGame = new GetGame 
      { 
       Id = search.Response.First().Id 
      }.AsResult(); 

      yield return getGame; 
      yield return Show.Screen<ExploreGameViewModel>() 
       .Configured(x => x.WithGame(getGame.Response)); 
     } 
     else SearchResults = _results.With(search.Response); 

     yield return Show.NotBusy(); 
    } 

希望有所幫助。

+0

@Doug - 感謝您的鏈接。一直試圖把我的頭圍繞在真棒一段時間.. :) – Gishu 2010-04-27 03:35:57

0

在肖恩Wildermuth的MSDN文章中,他做了這樣的事情: 退房這裏的文章:這裏 http://msdn.microsoft.com/en-us/magazine/dd458800.aspx

和他最近的博客文章: http://wildermuth.com/2009/12/15/Architecting_Silverlight_4_with_RIA_Services_MEF_and_MVVM_-_Part_1

public interface IGameCatalog 
{ 
    void GetGames(); 
    void GetGamesByGenre(string genre); 
    void SaveChanges(); 

    event EventHandler<GameLoadingEventArgs> GameLoadingComplete; 
    event EventHandler<GameCatalogErrorEventArgs> GameLoadingError; 
    event EventHandler GameSavingComplete; 
    event EventHandler<GameCatalogErrorEventArgs> GameSavingError; 
} 

像這樣的實現:

public class GameCatalog : IGameCatalog 
{ 
    Uri theServiceRoot; 
    GamesEntities theEntities; 
    const int MAX_RESULTS = 50; 

    public GameCatalog() : this(new Uri("/Games.svc", UriKind.Relative)) 
    { 
    } 

    public GameCatalog(Uri serviceRoot) 
    { 
    theServiceRoot = serviceRoot; 
    } 

    public event EventHandler<GameLoadingEventArgs> GameLoadingComplete; 
    public event EventHandler<GameCatalogErrorEventArgs> GameLoadingError; 
    public event EventHandler GameSavingComplete; 
    public event EventHandler<GameCatalogErrorEventArgs> GameSavingError; 

    public void GetGames() 
    { 
    // Get all the games ordered by release date 
    var qry = (from g in Entities.Games 
       orderby g.ReleaseDate descending 
       select g).Take(MAX_RESULTS) as DataServiceQuery<Game>; 

    ExecuteGameQuery(qry); 
    } 

    public void GetGamesByGenre(string genre) 
    { 
    // Get all the games ordered by release date 
    var qry = (from g in Entities.Games 
       where g.Genre.ToLower() == genre.ToLower() 
       orderby g.ReleaseDate 
       select g).Take(MAX_RESULTS) as DataServiceQuery<Game>; 

    ExecuteGameQuery(qry); 
    } 

    public void SaveChanges() 
    { 
    // Save Not Yet Implemented 
    throw new NotImplementedException(); 
    } 

    // Call the query asynchronously and add the results to the collection 
    void ExecuteGameQuery(DataServiceQuery<Game> qry) 
    { 
    // Execute the query 
    qry.BeginExecute(new AsyncCallback(a => 
    { 
     try 
     { 
     IEnumerable<Game> results = qry.EndExecute(a); 

     if (GameLoadingComplete != null) 
     { 
      GameLoadingComplete(this, new GameLoadingEventArgs(results)); 
     } 
     } 
     catch (Exception ex) 
     { 
     if (GameLoadingError != null) 
     { 
      GameLoadingError(this, new GameCatalogErrorEventArgs(ex)); 
     } 
     } 

    }), null); 
    } 

    GamesEntities Entities 
    { 
    get 
    { 
     if (theEntities == null) 
     { 
     theEntities = new GamesEntities(theServiceRoot); 
     } 
     return theEntities; 
    } 
    } 
}