代码之家  ›  专栏  ›  技术社区  ›  cost

wpf c-从另一个线程编辑列表框

  •  9
  • cost  · 技术社区  · 14 年前

    我意识到我所做的可能相当愚蠢,但我正在学习WPF,我想知道如何做到这一点。

    我有一扇窗户,上面有一个列表框。列表框用于在程序运行时传递有关该程序的状态消息。例如“server started”、“new connection at ip”等。我希望它在后台不断更新,所以我生成了一个处理更新的新线程,但当我调用添加项时,我收到错误消息“调用线程无法访问此对象,因为其他线程拥有它。”

    知道如何从另一个线程更新列表框吗?或者在背景中,等等。

    3 回复  |  直到 10 年前
        1
  •  25
  •   markmnl    10 年前


    更新

    如果您使用的是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"));
      }));
    

    如果你在代码后面。否则,您可以访问调度器(位于 UIElement )使用:

    Application.Current.MainWindow.Dispatcher.BeginInvoke(...
    

    好吧,这是一行很多,让我来看看:

    当您想要更新一个UI控件时,正如消息所说,您必须从UI线程进行更新。有一种内置的方法可以将委托(方法)传递给UI线程: Dispatcher . 一旦你有了 调度员 你也可以 Invoke() 属于 BeginInvoke() 传递要在UI线程上运行的委托。唯一的区别是 调用() 仅在运行委托后返回(例如,在您的情况下,列表框的新项已添加),而 开始调用() 将立即返回,以便您从中调用的另一个线程可以继续(调度器将尽快运行您的委托,这可能是直接进行的)。

    我在上面传递了一位匿名代表:

    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上阅读更多关于委托的内容,因为这有点偏离主题。

        2
  •  5
  •   Elixir    14 年前

    还可以使用带有匿名方法的操作委托从工作线程更新主线程。有关操作类的更多信息,请查看以下内容:

    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类是因为它封装了一个具有单个参数的方法(在本例中是一个listem)。

        3
  •  2
  •   Logan Capaldo    14 年前

    你会想用的 Dispatcher.BeginInvoke . 例如,如果列表框的名称为 listbox

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

    这将使要在UI线程上执行的委托排队 列表框 属于。