避免跨线程操作

时间:2015-04-27 18:41:52

标签: c# multithreading winforms

我想从我的后台工作人员访问GUI上的列表框中的选择。没有任何其他更改尝试这样做会抛出此错误

Cross-thread Operation Not Valid: Control '_ListBox1' accessed from a thread other than the thread it was created on

我看到避免这种情况的选项是通过以下语法使用Invoke,但.Net 4(或更高)是否可以接受?

var selectedItems = (IList)this.Invoke(new Func<IList>(() => Listbox1.SelectedItems.Cast<object>().ToList()));

为了更清晰的图片,这就是我想从我的backgroundworker访问列表框项目的方式

namespace clown
{
  public partial class Form1 : Form1
  {
    public Form1()
    {
      ListBox1.Items.Add("Firefly");
      ListBox1.Items.Add("Hellfire");
    }

    private void btn1234_Click()
    {
      backgroundworker1.RunWorkerAsync();
    }

    private void backgroundworker1_DoWork(object sender, DoWorkEventArgs e)
    {
      //Long Running Process taking place here 
      //then we hit this
      if (ListBox1.SelectedItems.Contains("Firefly")) { //take this course }
      if (ListBox1.SelectedItems.Contains("Hellfire)) { //take this course }
    }
   }
}

2 个答案:

答案 0 :(得分:6)

微软不赞成fun isTrue (n,tup) = if #2 (tup) then true else false; Invoke事件处理程序中的

Backgroundworker's。您应该考虑使用DoWork Backgroundworker'sProgressChanged事件。

请参阅MSDN Help Here

请参阅本文的第一个注释:

  

您必须小心不要操纵任何用户界面对象   你的DoWork事件处理程序。而是与用户界面进行通信   通过ProgressChanged和RunWorkerCompleted事件。

如果您实际发布了更多代码,可能会给出更全面的答案。

修改1:更多代码

由于OP更新了他的帖子以包含更多代码,我也做了同样的事情。

RunWorkerCompleted

答案 1 :(得分:0)

这是“可接受的”,但现在不是一个好习惯。 BackgroundWorker被认为是过时的,应该使用带异步/等待的任务。

下面是一个示例,说明如何实现一个方法在另一个线程上执行某些操作,保持UI响应并在执行完成后更新UI(使用WPF和MVVM模式):

public class ViewModel : INotifyPropertyChanged
{
    ...

    public string PathInfo { ... } // raises INotifyPropertyChanged.PropertyChanged event from the setter
    public RelayCommand ProcessPathsCommand { get; set; }

    public ViewModel()
    {
        ProcessPathsCommand = new RelayCommand(ProcessPaths);
    }

    public async void ProcessPaths()
    {
        // disable the command, which will lead to disabling a button bound to the command
        ProcessPathsCommand.IsEnabled = false;

        try
        {
            string result = null;
            // run processing on another thread
            await Task.Run(() =>
            {
                // emulate hard-work
                Thread.Sleep(5000);
                result = "Here are the results: bla bla bla";
            });

            // update the property on the view model, which will lead to updating a textblock bound to this property                
            // thanks to the "await" keyword, this line of code will be executed only when the task finishes
            // and it will be executed on UI thread
            PathInfo = result;
        }
        finally
        {
            ProcessPathsCommand.IsEnabled = true;
        }
    }

如果您需要更多详细信息,请随时与我们联系。