【发布时间】:2020-04-22 22:05:46
【问题描述】:
我想要运行相当简单的代码来编辑 UI。我知道如果我在主线程中运行 UI 会冻结,所以我一直在努力在单独的线程中运行它,但这不起作用。这是我想要发生的事情: 用户使用 UI 填充两个列表。一个列表跟踪屏幕上的内容,另一个跟踪稍后需要在屏幕上显示的内容。当用户单击某个按钮时,它会清除第一个列表和 UI。然后,我使用第二个列表再次在 UI 上显示每个项目,并在每个对象返回之间有一定的时间长度。这是一个简化的形式:
myList = [/*items to be displayed*/];
myMessages = [/*items currently displayed*/]
private void ButtonAnimationRun(object sender, RoutedEventArgs e)
{
Thread thread = new Thread(() =>
{
Run();
});
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
}
public void Run()
{
foreach (Message message in myList)
{
Thread.Sleep(message.Time * 1000);
CreateText(message.Text);
}
}
public void CreateText(string text)
{
Dispatcher.Invoke(() => myGrid.Children.Add(myMessages[myMessages.Count - 1]));
// text is added to the child of myGrid here
Dispatcher.Invoke(() => myScrollBar.ScrollToBottom());
}
这不是我的全部代码,而是与我的问题相关的代码。 如果我使用 await 或 tasks,我会收到一个 Apartment State 错误。 使用上面的代码,我收到此错误:“调用线程无法访问此对象,因为不同的线程拥有它。”在第一个 Invoke 的行上,无论有没有 Invoke 我仍然得到它。 当我注释掉前一个时,第二个 Invoke 工作得很好,但是,或者当然,我没有在 UI 上显示任何内容,因为这是将 UI 元素添加到 UI 的代码。 我已经搜索了 stackoverflow,我找到的所有答案都会导致其他人突然出现或禁止我的应用程序的功能。 如果您需要更多信息,我可以提供。
【问题讨论】:
-
具有合理数据类型的代码应该在不释放 UI 的情况下表现良好...请edit 代码发布minimal reproducible example。特别是,您不应该需要 STA 来显示代码并使用
myList的字符串列表。如果myList实际上是可见控件的列表,则需要将其包含在代码示例中。CreateText也没有使用它的参数......并且由于某种原因有 2 个.Invoke调用 - 你也不需要它来获取正确的样本。
标签: c# wpf multithreading