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

cos*_*ost 9 c# wpf multithreading

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

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

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

mar*_*mnl 25


UPDATE

如果您使用的是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;
}
Run Code Online (Sandbox Code Playgroud)

简单:

Dispatcher.BeginInvoke(new Action(delegate() 
  {
     myListBox.Items.Add("new item"));
  }));
Run Code Online (Sandbox Code Playgroud)

如果你在代码隐藏.否则,您可以使用以下命令访问Dispatcher(每个UIElement)

Application.Current.MainWindow.Dispatcher.BeginInvoke(...
Run Code Online (Sandbox Code Playgroud)

好吧,在一行中有很多让我重复一遍:

当您想要更新UI控件时,正如消息所示,您必须从UI线程执行此操作.内置了将委托(方法)传递给UI线程的方法:Dispatcher.一旦你的Dispatcher,你可以Invoke()BeginInvoke()传递代表要在UI线程上运行.唯一的区别是Invoke()只有在委托运行后才会返回(即在你的情况下已经添加了ListBox的新项目),而是BeginInvoke()立即返回,这样你调用的其他线程就可以继续(Dispatcher会尽快运行你的委托)无论如何,它可能会立即.)

我通过了一位匿名代表:

delegate() {myListBox.Items.Add("new item");}
Run Code Online (Sandbox Code Playgroud)

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

Action myDelegate = new Action(UpdateListMethod);

void UpdateListMethod() 
{
  myListBox.Items.Add("new item");
}
Run Code Online (Sandbox Code Playgroud)

然后通过:

Dispatcher.Invoke(myDelegate);
Run Code Online (Sandbox Code Playgroud)

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

  • 我喜欢怎么样,回顾这三年之后,我实际上知道什么是调度员,调用,委托,以及所有其他的东西(实际上知道如何使用它!):) (3认同)

Eli*_*xir 5

您还可以使用具有匿名方法的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.
        }));
Run Code Online (Sandbox Code Playgroud)

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