C#跨线程操作在BackgroundWorker中无效。

当主窗体被加载时,我正在向列表框中添加项目,然后我试图在BackgroundWorker中获取所选项目的值,但失败了。

private void MainForm_Load(object sender, EventArgs e)
{
    Dictionary<string, string> item = new Dictionary<string, string>();
    item.Add("Test 1", "test1");
    item.Add("Test 2", "test 2");

    cmbTest.DataSource = new BindingSource(item, null);
    cmbTest.DisplayMember = "Key";
    cmbTest.ValueMember = "Value";
}

然后我试图在BackgroundWorker中获取所选项目的值,但失败了。

private void TestWorker_DoWork(object sender, DoWorkEventArgs e)
{
    string test = ((KeyValuePair<string, string>)cmbTest.SelectedItem).Value;
    MessageBox.Show(test);
}

解决方案:

后台工作者不应该试图对UI做任何事情。该线程唯一能做的就是通知那些感兴趣的人,后台工作者计算出了一些值得注意的事情。

这个通知是使用事件ProgressChanged来完成的。

  • 使用Visual Studio Designer创建一个BackGroundWorker。
  • 让设计者为DoWork、ProgressChanged以及如果需要的话为RunWorkerCompleted添加事件处理程序。
  • 如果BackGroundWorker想通知表单应该显示什么,请使用ProgressChanged

你可能简化了你的问题,但背景工作程序不应该读取组合框的选定值。如果组合框发生变化,Form应该启动背景工作程序,同时传递所选组合框项的值。

因此,让我们把问题弄得更有趣一些:如果用户在comboBox1中选择了一个项目,背景工作程序被命令用所选的comboobox值来计算一些东西。

在计算过程中,BackGroundWorker会定期通知表单有关进度和中间计算值。当它完成后,返回最终结果。

代码将是这样的。

private void InitializeComponent()
{
    this.backgroundWorker1 = new System.ComponentModel.BackgroundWorker();
    this.SuspendLayout();
    this.backgroundWorker1.DoWork += new DoWorkEventHandler(this.DoBackgroundWork);
    this.backgroundWorker1.ProgressChanged += new ProgressChangedEventHandler(this.NotifyProgress);
    this.backgroundWorker1.RunWorkerCompleted += new RunWorkerCompletedEventHandler(
                                                 this.OnBackgounrWorkCompleted);
    ...
}

当一个项目被选中comboBox1时,背景工作程序就会使用所选的值开始工作。当背景工作程序启动时,用户不能再改变comboBox1,因为我们不能在它还在忙碌时启动同一个背景工作程序。

因此,combobox被禁用,并显示一个进度条。在计算过程中,进度条被更新,中间结果显示在Label1中。当背景工作程序完成后,进度条被移除,最终结果显示在Lable1中,组合框再次被启用。

请注意,在后台工作程序计算时,表单的其他部分仍在工作。

private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
    ComboBox comboBox = (ComboBox)sender;

    // disable ComboBox, show ProgressBar:
    comboBox.Enabled = false;
    this.progressBar1.Minimum = 0;
    this.progressBar1.Maximum = 100;
    this.progressBar1.Value = 0;
    this.progressBar1.Visible = true;

    // start the backgroundworker using the selected value:
    this.backgroundWorker1.RunWorkerAsync(comboBox.SelectedValue);
}

后台工作。

private void DoBackgroundWork(object sender, DoWorkEventArgs e)
{
    // e.Argument contains the selected value of the combobox
    string test = ((KeyValuePair<string, string>)e.Argument;

    // let's do some lengthy processing:
    for (int i=0; i<10; ++i)
    {
        string intermediateText = Calculate(test, i);

        // notify about progress: use a percentage and intermediateText
        this.backgroundWorker1.ReportProgress(10*i, intermediateText);
    }

    string finalText = Calculate(test, 10);

    // the result of the background work is finalText
    e.Result = finalText;
}

定期让你的表单得到进度通知:让它更新ProgressBar,并在Label1中显示中间文本。

private void NotifyProgress(object sender, ProgressChangedEventArgs e)
{
    this.progressBar1.Value = e.ProgressPercentage;
    this.label1.Text = e.UserState.ToString();
}

当BackgroundWorker完成后,最后的文本显示在label1中,进度条消失,Combobox再次启用。

private void OnBackgoundWorkCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    this.label1.Text = e.Result.ToString();
    this.progressBar1.Visible = false;
    this.comboBox1.Enabled = true;
}

给TA打赏
共{{data.count}}人
人已打赏
未分类

使用sklearn进行线性回归

2022-9-9 4:24:20

未分类

使用Instant.parse解析2018-05-01T00:00:00日期时出错。

2022-9-9 4:35:16

0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧
个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索