如何在C#和MVVM中实现异步操作?

什么是在WPF和MVVM上实现异步操作的最简单方法,让我们说如果用户在某个字段上输入时我想要启动命令然后返回,而线程将执行一些搜索操作然后返回更新属性,以便通知可以更新绑定。

谢谢!

如何在VM上调用命令的BackgroundWorker实例?

更新:抓住上面的建议..有一个关于MVVM的在线video由Jason Dolinger …我建议你看一下。 这是一种更清晰的方式,视图很薄/不包含任何线程代码。

总结一下:

  • VM ctor缓存Dispatcher.CurrentDispatcher对象(主线程)。
  • 更新后备存储(结果)时,请使用_dispatcher.BeginInvoke( () => _results.AddRange( entries) )以便正确更新UI。

Rob Eisenberg在他的MIX10演讲期间展示了在MVVM中运行异步操作的非常干净的实现。 他在他的博客上发布了源代码。

基本思想是将命令实现为返回IEnumerable并使用yield关键字返回结果。 这是他演讲中的一段代码,它将搜索作为后台任务:

  public IEnumerable 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() .Configured(x => x.WithGame(getGame.Response)); } else SearchResults = _results.With(search.Response); yield return Show.NotBusy(); } 

希望有所帮助。

在Shawn 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 GameLoadingComplete; event EventHandler GameLoadingError; event EventHandler GameSavingComplete; event EventHandler 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 GameLoadingComplete; public event EventHandler GameLoadingError; public event EventHandler GameSavingComplete; public event EventHandler 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; 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; 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 qry) { // Execute the query qry.BeginExecute(new AsyncCallback(a => { try { IEnumerable 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; } } }