Dipende dal tipo di applicazione che si sta scrivendo - ad esempio - accettate i bug? Quali sono i tuoi dati richiesti: soft realtime? acido? clienti eventualmente coerenti e/o parzialmente connessi/a volte disconnessi?
Attenzione che esiste una distinzione tra concorrenza e asincronizzazione. È possibile avere asincronizzazione e quindi chiamare interleaving del metodo call senza effettivamente avere un programma in esecuzione simultaneo.
Un'idea potrebbe essere quella di avere un lato di lettura e scrittura dell'applicazione, in cui la scrittura pubblica eventi quando è stata modificata. Ciò potrebbe portare a un sistema basato su eventi: il lato di lettura verrebbe creato dagli eventi pubblicati e potrebbe essere ricostruito. L'interfaccia utente potrebbe essere basata su attività - in quanto un'attività da svolgere produrrebbe un comando che il BL prenderà (o livello dominio se lo si desidera).
Un passo logico successivo, se si dispone di quanto sopra, è anche andare di origine evento. Quindi si ricrea lo stato interno del modello di scrittura attraverso ciò che è stato precedentemente commesso. C'è un gruppo di google su CQRS/DDD che potrebbe aiutarti in questo.
Per quanto riguarda l'aggiornamento dell'interfaccia utente, ho trovato che le interfacce IObservable in System.Reactive, System.Interactive, System.CoreEx sono adatte. Permette di saltare diversi contesti di invocazione simultanei - dispatcher - pool di thread, ecc. E si integra bene con la Libreria parallela attività.
Dovresti anche considerare dove mettere la tua logica aziendale - se vai al dominio direi che potresti metterlo nella tua applicazione come avresti una procedura di aggiornamento in atto per i binari che distribuisci comunque, quando arriva il momento di aggiornare, ma c'è anche la scelta di metterlo sul server. I comandi potrebbero essere un buon modo per eseguire gli aggiornamenti sul lato scrittura e una comoda unità di lavoro quando il codice orientato alla connessione fallisce (sono piccoli e serializzabili e l'interfaccia utente può essere progettata attorno ad essi).
Per fare un esempio, dare un'occhiata a this thread, con questo codice, che aggiunge una priorità per l'IObservable.ObserveOnDispatcher (...) - chiamano:
public static IObservable<T> ObserveOnDispatcher<T>(this IObservable<T> observable, DispatcherPriority priority)
{
if (observable == null)
throw new NullReferenceException();
return observable.ObserveOn(Dispatcher.CurrentDispatcher, priority);
}
public static IObservable<T> ObserveOn<T>(this IObservable<T> observable, Dispatcher dispatcher, DispatcherPriority priority)
{
if (observable == null)
throw new NullReferenceException();
if (dispatcher == null)
throw new ArgumentNullException("dispatcher");
return Observable.CreateWithDisposable<T>(o =>
{
return observable.Subscribe(
obj => dispatcher.Invoke((Action)(() => o.OnNext(obj)), priority),
ex => dispatcher.Invoke((Action)(() => o.OnError(ex)), priority),
() => dispatcher.Invoke((Action)(() => o.OnCompleted()), priority));
});
}
L'esempio potrebbe essere utilizzato ti piace questa blog entry discute
public void LoadCustomers()
{
_customerService.GetCustomers()
.SubscribeOn(Scheduler.NewThread)
.ObserveOn(Scheduler.Dispatcher, DispatcherPriority.SystemIdle)
.Subscribe(Customers.Add);
}
... Così, per esempio con un negozio starbucks virtuale, si avrebbe un'entità di dominio che ha qualcosa come una classe di 'Barista', che produce eventi 'CustomerBoughtCappuccino': {costo: "$ 3", timestamp: "2011-01-03 12: 00: 03.334556 GMT + 0100 ', ... ecc.}. Il tuo read-side si iscriverebbe a questi eventi. Il lato di lettura potrebbe essere un modello di dati - per ciascuna delle schermate che presentano i dati - la vista avrebbe una classe ViewModel unica - che sarebbe sincronizzata con la vista in un dizionario osservabile like this. Il repository sarebbe (: IObservable), ei tuoi relatori si iscriveranno a tutto questo, o solo a una parte di esso. In questo modo la vostra interfaccia grafica potrebbe essere:
- Task guidato -> Comando guidato BL, con particolare attenzione alla gestione degli utenti
- Async
- lettura-scrittura-segregato
Dato che il vostro BL richiede solo comandi e non in cima a quello visualizza 'abbastanza buono per tutte le pagine'-tipo di modello di lettura, è possibile rendere la maggior parte delle cose in esso interne, interne protette e private, il che significa che è possibile utilizzare System.Contracts per dimostrare che non ho bug (!). Produrrebbe eventi che il tuo modello di lettura leggerà. È possibile prendere i principi principali da Caliburn Micro sull'orchestrazione dei flussi di lavoro delle attività asincrone cedute (IAsyncResults).
Ci sono alcuni Rx design guidelines che potresti leggere. E cqrsinfo.com su event sourcing e cqrs. Se sei effettivamente interessato ad andare oltre la sfera di programmazione asincrona nella sfera della programmazione simultanea, Microsoft ha rilasciato gratuitamente un po 'di written book, su come programmare tale codice.
Spero che aiuti.
So come si comporta Control.Invoke(), ma la domanda riguarda il modello di progettazione e le migliori pratiche. Quale controllo utilizzo per Control.Invoke() - è consigliabile utilizzare il modulo? Significa che ho bisogno di un riferimento al modulo nel mio relatore o invoco Invoke() dal code-behind del modulo? –
@IIya: Ok, ho capito. Dipende dalle circostanze, ma normalmente si scriverà una logica per aggiornare un controllo e si utilizzerà il controllo target per verificare InvokeRequired e quindi control.Invoke(). Vedi le mie modifiche. –