在许多博客、教程和MSDN上,我可以看到从非UI线程访问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?
}
我有一个异步运行的Task
,我想在其中更改我的属性(这将引发PropertyChanged
事件)并向ObservableCollection
添加元素。由于它是以async
方式运行的,所以我本不应该能够这样做,但我没有收到任何异常,并且代码可以正常工作。因此我有疑问和误解:
- 为什么我没有得到异常?
- 在
async Task
中引发PropertyChanged
事件是否可以? - 在
async Task
中修改ObservableCollection
是否可以,还是应该返回Task<ICollection>
,在获取结果后修改ObservableCollection
-清除并填充? - 何时在UI线程上运行
Task
,何时不在? - 在上面的代码中,在
firstButton_Click
中等待Task
后管理UI元素是否正确?我总是回到UI线程吗?
为了进行更多测试,我将我的属性更改和集合修改放在了另一个线程中:
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);
在上面的代码中,我认为我的思路是正确的-就在第一行或第二行后,我遇到了一个异常。但是第一个代码呢?难道我的Task
只是幸运地在UI线程上运行吗?
我怀疑这是非常基础的东西,可能是我的误解,但我需要一些澄清,因此提出了这个问题。
await Job();
从 Click - 因此捕获的 UI 上下文是在之前和之后而不是内部?2. 我对在同一线程上等待返回感到困惑 - 例如 我无法在 Mutex 中等待,因此在返回后,“捕获的上下文可能是任何线程池线程”。3. 如果从异步任务(在不同的线程上)引发属性更改,那么为什么不能使用计时器? - Romasz