【问题标题】:Windows Form Embedded Progress Bar Background WorkerWindows 窗体嵌入式进度条后台工作者
【发布时间】:2018-02-20 11:38:46
【问题描述】:

我想在表单中使用进度条,但遇到了问题。

在表单加载时,进度条完成,列表视图中填充了“已连接”设备的图标。

当我尝试在网络适配器列表中选择另一个索引时,进度条和列表视图会清除,但会引发异常并且 GUI 中没有任何反应。

抛出异常:System.Windows.Forms.dll 中的“System.InvalidOperationException”

我假设这是一个线程问题,但我不知道。

这里是代码,非常感谢任何帮助或建议。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Net.NetworkInformation;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace WindowsFormsApplication1
{
    public partial class ConnectDialog : Form
    {
        BackgroundWorker bkgndWorker = null;
        Dictionary<string, int> dictionary = new Dictionary<string, int>();
        ImageList deviceImageList = new ImageList();

        public ConnectDialog()
        {
            InitializeComponent();       
        }

        public ConnectDialog(List<String> ipAddr)
        {
            InitializeComponent();
            cboNetworkAdapter.Items.AddRange(ipAddr.ToArray());
            cboNetworkAdapter.SelectedIndex = 0;
        }

        private void ConnectDialog_Load(object sender, EventArgs e)
        {
            Bitmap devImage = Properties.Resources.devIcon;
            deviceImageList.Images.Add(devImage);
            deviceImageList.ImageSize = new Size(30, 30);
        }

        private void cboNetworkAdapter_SelectedIndexChanged(object sender, EventArgs e)
        {
            StartWorking();
        }

        private void StartWorking()
        {
            prgBarConnect.Value = 0;
            dictionary.Clear();
            lstvwDevIds.Clear();
            bkgndWorker = new BackgroundWorker();

            bkgndWorker.DoWork += new DoWorkEventHandler(bkgndWorker_DoWork);
            bkgndWorker.ProgressChanged += new ProgressChangedEventHandler(bkgndWorker_ProgressChanged);
            bkgndWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bkgndWorker_RunWorkerCompleted);
            bkgndWorker.WorkerReportsProgress = true;
            bkgndWorker.RunWorkerAsync();
            bkgndWorker.Dispose();
        }

        private void bkgndWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            int numDevs = 0;
            switch (cboNetworkAdapter.SelectedIndex)
            {
                case 0:
                    numDevs = 4;
                    break;
                case 1:
                    numDevs = 1;
                    break;
                case 2:
                    numDevs = 10;
                    break;
            }
            populateImages(numDevs);
        }

        void bkgndWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            prgBarConnect.Value = e.ProgressPercentage;
        }

        void bkgndWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            foreach (KeyValuePair<String, int> entry in dictionary)
            {
                ListViewItem lstViewDevImage = new ListViewItem(entry.Key, entry.Value);
                lstvwDevIds.Items.Add(lstViewDevImage);
            }

            if (lstvwDevIds.SelectedItems.Count > 0)
                Console.WriteLine(String.Format("Device id: {0}", lstvwDevIds.Items.IndexOf(lstvwDevIds.SelectedItems[0])));

            lstvwDevIds.LargeImageList = deviceImageList;
        }

        private void populateImages(int numDevs)
        {
            for (int i = 1; i <= numDevs; i++)
            {
                System.Threading.Thread.Sleep(100);
                int percents = (i * 100) / numDevs;

                String lstVwItemDesc = String.Format("Dev {0}", i - 1);
                dictionary.Add(lstVwItemDesc, deviceImageList.Images.Count - 1);
                bkgndWorker.ReportProgress(percents, i);
            }
        }
    }
}

【问题讨论】:

  • 您是否在启动后台工作程序后立即对其进行处理? DoWorkAsync异步运行,所以它会在DoWork完成之前执行dispose命令。

标签: c# multithreading user-interface backgroundworker


【解决方案1】:

不要在要运行的 BackGroundWorker 上调用 Dispose。改为这样做:

// if we have an instance of a backgroundworker ...
// Cancel and Dispose that one
if (bkgndWorker !=null) 
{
    // in case you want to end the DoWork nicely
    bkgndWorker.CancelAsync(); 
    bkgndWorker.Dispose();
}

// start again
bkgndWorker = new BackgroundWorker();

bkgndWorker.DoWork += new DoWorkEventHandler(bkgndWorker_DoWork);
bkgndWorker.ProgressChanged += new ProgressChangedEventHandler(bkgndWorker_ProgressChanged);
bkgndWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bkgndWorker_RunWorkerCompleted);
bkgndWorker.WorkerReportsProgress = true;
bkgndWorker.RunWorkerAsync();
// removed the call to Dispose

您可能还想在表单上实现 Dispose 以对 BackgroundWorker 实例进行相同的清理。

【讨论】:

    猜你喜欢
    • 2011-10-07
    • 2015-02-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-09-04
    • 1970-01-01
    • 2011-05-18
    • 1970-01-01
    相关资源
    最近更新 更多