In molti blog, tutorial e MSDN posso leggere che l'accesso agli elementi dell'interfaccia utente dal thread non-UI è impossibile - ok, otterrò un'eccezione non autorizzata. Per provarlo ho scritto un esempio molto semplice:Raising PropertyChanged in Task asincroni e thread UI
// simple text to which TextBlock.Text is bound
private string sample = "Starting text";
public string Sample
{
get { return sample; }
set { sample = value; RaiseProperty("Sample"); }
}
private async void firstButton_Click(object sender, RoutedEventArgs e)
{
await Job(); // asynchronous heavy job
commands.Add("Element"); // back on UI thread so this should be ok?
}
private async Task Job()
{
// I'm not on UI Thread ?
await Task.Delay(2000); // some other job
Sample = "Changed"; // not ok as not UI thread?
commands.Add("Element from async"); // also not ok?
}
Ho un compito che è in esecuzione asincrona, in questo compito voglio: cambiare la mia proprietà (che consentirà di accrescere PropertyChanged) e aggiungere elementi alla ObservableCollection. Poiché viene eseguito async, non dovrei riuscire a farlo, ma non ottengo eccezioni e il codice funziona correttamente. Quindi i miei dubbi e incomprensioni:
- perché non ottengo eccezione?
- è ok per aumentare PropertyChanged in attività asincrona?
- ok è possibile modificare ObservableCollecition in async Task, oppure devo restituire Task e dopo aver ottenuto il risultato modificare Observable - Clear it e Fill it?
- quando sono in Attività sul thread dell'interfaccia utente e quando no?
- nel codice sopra riportato in
firstButton_Click
è possibile gestire gli elementi dell'interfaccia utente dopo aver atteso l'attività? Sono sempre tornato sul thread dell'interfaccia utente?
Per provare più ho messo il mio cambiamento di proprietà e la modifica di raccolta in altro thread:
System.Threading.Timer newThreadTimer = new System.Threading.Timer((x) =>
{
Sample = "Changed"; // not UI thread - exception
commands.Add("Element from async"); // not UI thread - exception
}, null, 1000, Timeout.Infinite);
Nel codice di cui sopra il mio pensiero è ok - subito dopo la prima o la seconda linea ottengo un'eccezione . Ma cosa con il primo codice? È solo una fortuna che il mio compito sia stato eseguito sul thread dell'interfaccia utente?
Sospetto che questa sia una cosa fondamentale e il mio fraintendimento, ma ho bisogno di chiarimenti e quindi di questa domanda.
Vorrei fare +1 se non questa affermazione: * "La Libreria parallela attività utilizza un' TaskScheduler' per implicitamente (o esplicitamente ...) cattura l'attuale 'SynchronizationContext' ..." * Questo non è del tutto corretto per le continuazioni 'await': http://stackoverflow.com/q/23071609/1768303 – Noseratio
Risposta lunga (grazie per questo), ma ho alcuni dubbi: 1. Guarda che il mio lavoro è eseguito come asincrono 'Attendi Job();' da Click - il contesto dell'interfaccia utente così catturato è prima e dopo non dentro? 2. Sono confuso dal ritorno dallo stesso thread - per esempio [Non posso aspettare dentro Mutex] (http://stackoverflow.com/q/23153155/2681948), quindi dopo aver restituito "il contesto catturato potrebbe significare qualsiasi thread thread-pool" 3. Se è ok per sollevare la proprietà modificata da async Task (su thread diversi), quindi perché non il Timer? – Romasz
@Romasz si confondono i relativi concetti differenti di 'asincrono' /' sincrono' e 'concorrente'. Tutto il codice che hai scritto è SINGOLO FILETTATO, il che significa che non hai problemi. L'errore da principiante con 'async' /' await' è pensare, giusto ... re asincrono, significa thread giusto? I thread significano 'concurrent', e in passato era l'unico modo per ottenere' asincrono'. – Aron