WPF C# – 从另一个线程编辑列表框

我意识到我正在做的事情可能很愚蠢,但我正在学习WPF,并想知道如何做到这一点。

我有一个带有列表框的窗口。 列表框用于在程序运行时传递有关程序的状态消息。 例如“服务器已启动”“IP连接时的新连接”等。我希望在后台不断更新,因此我生成了一个新线程来处理更新,但是当我调用添加项目时,我得到了错误消息“调用线程无法访问此对象,因为另一个线程拥有它。”

知道如何从另一个线程更新列表框吗? 或者在后台等


UPDATE

如果您使用的是C#5和.NET 4.5或更高版本,则可以避免使用asyncawait首先访问另一个线程,例如:

 private async Task 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线程执行此操作。 内置了将委托(方法)传递给UI线程的方法: Dispatcher 。 拥有Dispatcher您可以Invoke() BeginInvoke() Invoke() BeginInvoke()传递一个委托,以便在UI线程上运行。 唯一的区别是Invoke()只会在委托运行后返回(即在你的情况下已经添加了ListBox的新项目),而BeginInvoke()将立即返回,因此你调用的其他线程可以继续(Dispatcher将尽快运行你的代表,无论如何都可以直接运行你的代表。

我通过了一位匿名代表:

 delegate() {myListBox.Items.Add("new item");} 

{}之间的位是方法块。 这称为匿名,因为只创建了一个并且它没有名称(通常可以使用lambda表达式执行此操作,但在这种情况下,C#无法解析要调用的BeginInvoke()方法)。 或者我可以实例化一个委托:

 Action myDelegate = new Action(UpdateListMethod); void UpdateListMethod() { myListBox.Items.Add("new item"); } 

然后通过:

 Dispatcher.Invoke(myDelegate); 

我还使用了Action类,它是一个内置的委托,但你可以创建自己的 – 你可以在MSDN上阅读更多有关委托的信息,因为这有点偏离主题。

您还可以使用具有匿名方法的Action委托来更新工作线程中的主线程。 有关Action类的更多信息,请参阅此处:

http://msdn.microsoft.com/en-us/library/018hxwa8.aspx

如果您想从多个点更新列表框,我建议明确设置委托,但是如果您只希望在单个调用的方法中的单个点更新线程,则可以按如下方式完成:

  listbox.Dispatcher.BeginInvoke(new Action(delegate() { listbox.Items.Add(item); //where item is the item to be added and listbox is the control being updated. })); 

请注意,我使用Action类,因为它封装了一个具有单个参数的方法(在本例中为listItem)。

您将要使用Dispatcher.BeginInvoke 。 例如,如果列表框名为listbox

  // On worker thread listbox.Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.Normal, new Action(delegate() { listbox.Items.Add("Server started") }); 

这将排队委托以在listbox所属的UI线程上执行。