2010-03-28 6 views
9

hola ¿cuál es la forma más fácil de implementar operaciones de asincronización en WPF y MVVM, digamos si el usuario si el usuario pulsa enter cuando en un campo quiero lanzar un comando y luego regresar mientras un hilo hará algunas operaciones de búsqueda y luego respalde y actualice las propiedades para que la notificación pueda actualizar los enlaces.¿cómo se implementan las operaciones de Async en C# y MVVM?

gracias!

Respuesta

3

¿Qué tal una instancia de BackgroundWorker para llamar a su comando en la máquina virtual?

Actualización: Raspe la sugerencia anterior .. Hay un video en línea en MVVM por Jason Dolinger .. Recomiendo que eche un vistazo a eso. Es una forma más limpia donde la vista es delgada/no contiene ningún código de enhebrado.

Para resumir:

  • la VM ctor almacena en caché el objeto Dispatcher.CurrentDispatcher (hilo principal).
  • al actualizar el almacén de respaldo (resultados), use _dispatcher.BeginInvoke(() => _results.AddRange(entries)) para que la interfaz de usuario se actualice correctamente.
+0

El enlace reflejará el cambio sin una solución? Has probado este enfoque con éxito, gracias a Gishu –

+0

@Oscar: mira la actualización ... o mejor aún mira ese video. – Gishu

+3

Habría sido bueno vincular a la página con el video: http://blog.lab49.com/archives/2650 – OwenP

8

Rob Eisenberg mostraron una aplicación muy limpia de ejecutar operaciones asíncronas en MVVM durante su MIX10 talk. Él ha publicado el código fuente en su blog.

La idea básica es que implemente el comando como devolver un IEnumerable y use la palabra clave yield para devolver los resultados. Aquí es un fragmento de código de su charla, que hace una búsqueda como una tarea en segundo plano:

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

Espero que ayude.

+0

@Doug - Gracias por el enlace. He estado tratando de entender mi asombro por un tiempo ... :) – Gishu

0

En MSDN artículo de Shawn Wildermuth hizo algo como esto: a extraer el artículo aquí: http://msdn.microsoft.com/en-us/magazine/dd458800.aspx

y su puesto más reciente blog aquí: 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; 
} 

con una aplicación como esta :

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; 
    } 
    } 
} 
Cuestiones relacionadas