Nella mia applicazione MVVM mio avviso modello prevede 3 diversi metodi di servizio, converte i dati da ciascuno in un formato comune e quindi aggiorna l'interfaccia utente mediante notifica proprietà/collezioni osservabili eccCome continuare dopo più attività senza bloccare il thread dell'interfaccia utente?
Ogni metodo nel livello di servizio inizia una nuova Task
e restituisce Task
al modello di visualizzazione. Ecco un esempio di uno dei miei metodi di servizio.
public class ResourceService
{
internal static Task LoadResources(Action<IEnumerable<Resource>> completedCallback, Action<Exception> errorCallback)
{
var t = Task.Factory.StartNew(() =>
{
//... get resources from somewhere
return resources;
});
t.ContinueWith(task =>
{
if (task.IsFaulted)
{
errorCallback(task.Exception);
return;
}
completedCallback(task.Result);
}, TaskScheduler.FromCurrentSynchronizationContext());
return t;
}
}
Ecco il codice chiamante e in altre parti rilevanti del modello di vista ...
private ObservableCollection<DataItem> Data = new ObservableCollection<DataItem>();
public ICollectionView DataView
{
get { return _dataView; }
set
{
if (_dataView != value)
{
_dataView = value;
RaisePropertyChange(() => DataView);
}
}
}
private void LoadData()
{
SetBusy("Loading...");
Data.Clear();
Task[] tasks = new Task[3]
{
LoadTools(),
LoadResources(),
LoadPersonel()
};
Task.WaitAll(tasks);
DataView = CollectionViewSource.GetDefaultView(Data);
DataView.Filter = FilterTimelineData;
IsBusy = false;
}
private Task LoadResources()
{
return ResourceService.LoadResources(resources =>
{
foreach(var r in resources)
{
var d = convertResource(r);
Data.Add(d);
}
},
error =>
{
// do some error handling
});
}
Questo quasi opere, ma ci sono un paio di piccoli problemi.
Numero 1: nella chiamata a SetBusy
all'inizio, prima di iniziare qualsiasi attività e prima chiamo WaitAll
, ho impostato la proprietà su true. Questo dovrebbe aggiornare l'interfaccia utente e mostrare il controllo BusyIndicator ma non funziona. Ho anche provato ad aggiungere semplici proprietà stringa e legare quelle e non vengono aggiornate neanche. La funzionalità IsBusy fa parte di una classe base e funziona in altri modelli di viste in cui non ho più di una attività in esecuzione, quindi non credo che ci sia un problema con la notifica di proprietà o l'associazione dati in XAML.
Tutte le associazioni di dati sembrano essere aggiornate dopo che l'intero metodo è stato completato. Non vedo alcuna "prima volta eccezioni" o errori di binding nella finestra di output che mi porta a credere che il thread dell'interfaccia utente sia in qualche modo bloccato prima della chiamata a WaitAll.
Numero 2: Mi sembra di restituire le attività sbagliate dai metodi di servizio. Voglio che dopo il WaitAll
venga eseguito dopo che il modello di visualizzazione ha convertito tutti i risultati di tutti i metodi di servizio nei callback. Tuttavia, se restituisco l'attività di continuazione dal metodo di servizio, la continuazione non viene mai chiamata e WaitAll
attende per sempre. La cosa strana è che il controllo dell'interfaccia utente associato a ICollectionView visualizza effettivamente tutto correttamente, presumo che questo sia dovuto al fatto che Data è una raccolta osservabile e che CollectionViewSource è a conoscenza degli eventi modificati dalla raccolta.
Sto rimandando usando async/await perché non sono sicuro che funzioni "solo con i comandi WPF e Prism DelegateCommand. Task.ContinueWhenAll non sembra esistere per me, devo fare riferimento ad alcune librerie di estensioni TPL? – BenCr
@BenCr Sorry -it TaskFactory.ContinueWhenAll. In generale, le cose attese/asincrone funzionano * meglio * rispetto alle continue attività con WPF. La differenza principale è che non devi saltare attraverso i circuiti impazziti per gestire le eccezioni. –
Grazie Reed, sembra che funzioni molto meglio. Spero che qualcuno possa essere in grado di fornire una spiegazione per il blocco prima che fosse chiamato WaitAll, ma questo ha certamente risolto i problemi 1 e 2. Darò le cose asincrone/attese alla prossima iterazione e vedrò come vado avanti. – BenCr