我意识到我正在做的事情可能很愚蠢,但我正在学习 WPF 并且想知道如何做到这一点。
我有一个带有列表框的窗口。列表框用于在程序运行时传递有关程序的状态消息。例如“服务器已启动”“IP # 的新连接”等。我希望它在后台不断更新,所以我生成了一个新线程来处理更新它,但是当我调用添加项目时,我得到了错误消息“调用线程无法访问此对象,因为另一个线程拥有它。”
知道如何从另一个线程更新列表框吗?或者在后台等。
最佳答案
更新
如果您使用的是 C# 5 和 .NET 4.5 或更高版本,您可以首先使用 async
和 await
避免进入另一个线程,例如:
private async Task<string> SimLongRunningProcessAsync()
{
await Task.Delay(2000);
return "Success";
}
private void Button_Click(object sender, RoutedEventArgs e)
{
button.Content = "Running...";
var result = await SimLongRunningProcessAsync();
button.Content = result;
}
简单:
Dispatcher.BeginInvoke(new Action(delegate()
{
myListBox.Items.Add("new item"));
}));
如果您处于代码隐藏状态。否则,您可以使用以下方法访问 Dispatcher(在每个 UIElement
上):
Application.Current.MainWindow.Dispatcher.BeginInvoke(...
好的,一行就这么多了,让我过一遍:
如消息所述,当您想要更新 UI 控件时,必须从 UI 线程执行此操作。有一种内置方式可以将委托(delegate)(一种方法)传递给 UI 线程:Dispatcher
。拥有 Dispatcher
后,您可以通过 Invoke()
或 BeginInvoke()
传递要在 UI 线程上运行的委托(delegate)。唯一的区别是 Invoke()
只会在委托(delegate)运行后返回(即在您的情况下,已添加 ListBox 的新项目),而 BeginInvoke()
将立即返回因此您调用的其他线程可以继续(Dispatcher 将尽快运行您的委托(delegate),无论如何可能会立即运行)。
我在上面传递了一个匿名委托(delegate):
delegate() {myListBox.Items.Add("new item");}
{} 之间的位是方法 block 。这称为匿名,因为只创建了一个并且没有名称(通常您可以使用 lambda 表达式执行此操作,但在这种情况下 C# 无法解析要调用的 BeginInvoke() 方法)。或者我可以实例化一个委托(delegate):
Action myDelegate = new Action(UpdateListMethod);
void UpdateListMethod()
{
myListBox.Items.Add("new item");
}
然后通过那个:
Dispatcher.Invoke(myDelegate);
我还使用了 Action 类,它是一个内置的委托(delegate),但您可以创建自己的 - 您可以在 MSDN 上阅读更多关于委托(delegate)的信息,因为这有点偏离主题..
关于c# - WPF C# - 从另一个线程编辑列表框,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4191325/