2010-03-28 15 views
9

ciao qual è il modo più semplice per implementare operazioni asincrone su WPF e MVVM, diciamo se l'utente se l'utente tocca entra quando su un campo voglio lanciare un comando e poi tornare indietro mentre un thread eseguirà alcune operazioni di ricerca e poi arriverà indietro e aggiornare le proprietà in modo che la notifica possa aggiornare i binding.come implementare le operazioni asincrone in C# e MVVM?

grazie!

risposta

3

Come su un'istanza BackgroundWorker per chiamare il comando sulla VM?

Aggiornamento: Scratch il suggerimento di cui sopra .. C'è un video online su MVVM di Jason Dolinger .. Vi consiglio di dare un'occhiata a questo. È un modo più pulito dove la vista è sottile/non contiene alcun codice di threading.

Riassumendo:

  • VM ctor memorizza nella cache l'oggetto Dispatcher.CurrentDispatcher (thread principale).
  • durante l'aggiornamento del backing store (risultati), utilizzare _dispatcher.BeginInvoke(() => _results.AddRange(entries)) in modo che l'interfaccia utente sia aggiornata correttamente.
+0

il legame rifletterà il cambiamento senza una soluzione? hai provato questo approccio con successo, grazie a Gishu –

+0

@Oscar: vedi l'aggiornamento ... o meglio ancora guarda quel video. – Gishu

+3

Sarebbe stato carino collegare alla pagina il video: http://blog.lab49.com/archives/2650 – OwenP

8

Rob Eisenberg ha mostrato un'implementazione davvero pulita delle operazioni asincrone in MVVM durante il suo MIX10 talk. Ha pubblicato il codice sorgente sul suo blog.

L'idea di base è implementare il comando come restituire un oggetto IEnumerable e utilizzare la parola chiave yield per restituire i risultati. Ecco un frammento di codice dal suo discorso, che fa una ricerca come attività in background:

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

Speranza che aiuta.

+0

@Doug - Grazie per il collegamento. State cercando di avvolgere la mia testa intorno alla suggestione per un po 'ora .. :) – Gishu

0

In Shawn Wildermuth articolo MSDN che ha fatto qualcosa di simile: check-out l'articolo qui: http://msdn.microsoft.com/en-us/magazine/dd458800.aspx

e il suo recente post più blog qui: 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 un'implementazione come questo :

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; 
    } 
    } 
} 
Problemi correlati