开发者

WPF C# - Editing a listbox from another thread

开发者 https://www.devze.com 2023-01-25 20:39 出处:网络
I realize what I\'m doing is probably pretty silly, but I\'m in the middle of learning WPF and would like to know how to do this.

I realize what I'm doing is probably pretty silly, but I'm in the middle of learning WPF and would like to know how to do this.

I have a window with a listbox on it. The listbox is being used to deliver status messages about the program while it's running. For example "Server started" "New connection at IP #" etc. I wanted this to be constantly updating in the background, so I spawned a new thread for handling updating this, but when I made the call to add an item I get the error message "The calling thread cannot access this object because a different thread owns it."

Any idea how I can update the listbox from another thread? Or in the background, et开发者_开发技巧c.



UPDATE

If you are using C# 5 and .NET 4.5 or above you can avoid getting on another thread in the first place using async and await, e.g.:

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;
}

Easy:

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

If you are in code-behind. Otherwise you can access the Dispatcher (which is on every UIElement) using:

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

Ok thats a lot in one line let me go over it:

When you want to update a UI control you, as the message says, have to do it from the UI thread. There is built in way to pass a delegate (a method) to the UI thread: the Dispatcher. Once you have the Dispatcher you can either Invoke() of BeginInvoke() passing a delegate to be run on the UI thread. The only difference is Invoke() will only return once the delegate has been run (i.e. in your case the ListBox's new item has been added) whereas BeginInvoke() will return immediately so your other thread you are calling from can continue (the Dispatcher will run your delegate soon as it can which will probably be straight away anyway).

I passed an anonymous delegate above:

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

The bit between the {} is the method block. This is called anonymous because only one is created and it doesnt have a name (usually you can do this using a lambda expression but in this case C# cannot resolve the BeginInvoke() method to call). Or I could have instantiated a delegate:

Action myDelegate = new Action(UpdateListMethod);

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

Then passed that:

Dispatcher.Invoke(myDelegate);

I also used the Action class which is a built in delegate but you could have created your own - you can read up more about delegates on MSDN as this is going a bit off topic..


You can also use the Action delegate with anonymous methods to update the main thread from the worker thread. For more information on the Action class you could look here :

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

If you would like to update the listbox from multiple points I suggest explicitally setting the delegate, however if you just wish to update the thread at a single point in a method with a single call it could be done as follows :

        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.
        }));

Note that I use the Action class as it takes encapsulates a method that has a single parameter (in this case a listItem).


You'll want to use Dispatcher.BeginInvoke. For example, if the listbox is named listbox

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

This will queue up the delegate to be executed on the UI thread that listbox belongs to.

0

精彩评论

暂无评论...
验证码 换一张
取 消