在c#表单应用中使用BackGroundWorker更新UI线程



我有一个耗时的任务,测试几个网络连接。在下面的例子中,我将其限制为一个连接。正常情况下,连接会很快返回,但也有可能无法建立连接,从而导致套接字超时。在此期间,我想在表单中显示一个"空闲"gif,当连接成功时,应用程序应该将表单中的图像更改为一些绿色检查图标,如果连接失败,应显示红色图标"stopper"。

不知何故,我不能得到空闲gif变成可见和动画。要模拟失败的连接,可以输入无效的端口号#或不存在的地址。

有什么线索我错过或做错了吗?

    partial class Form1
    {
        /// <summary>
        /// Required designer variable.
        /// </summary>
        ///         
     #region BackgroundWorker
        private System.ComponentModel.BackgroundWorker backgroundWorker = new System.ComponentModel.BackgroundWorker();
        private delegate void SomeLongRunningMethodHandler(object sender, EventArgs e);
     #endregion
        private System.ComponentModel.IContainer components = null;
        Button button,button2;
        static Socket socket;
        static bool success;
        private static bool done;
        private Label lbl1;
        private Label lbl2;
        private TextBox address;
        private TextBox port;
        private PictureBox p;
        private static String port_number,host;

        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }
        private void RunTest(object o,EventArgs e)
        {
            p.Visible = true;
            SomeLongRunningMethodHandler synchronousFunctionHandler =
                default(SomeLongRunningMethodHandler);
            synchronousFunctionHandler = 
                TestConnection;
            synchronousFunctionHandler.Invoke(o, e);
        }
        private void TestConnection(object o, EventArgs e)
        {
            host = address.Text;
            port_number = port.Text;
           if (null != socket)
            {
                socket.Close();
            }
             Thread.Sleep(1000);
             IPEndPoint myEndpoint = new IPEndPoint(0, 0);

            IPHostEntry remoteMachineInfo = Dns.GetHostEntry(host);
            IPEndPoint serverEndpoint = new IPEndPoint(remoteMachineInfo.AddressList[0],
                int.Parse(port_number));

            socket = new Socket(myEndpoint.Address.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
            try
            {
                socket.Connect(serverEndpoint);
                success = true;
                p.Image = global::BlockingUI.Properties.Resources.accept;
            }
            catch
            {
                success = false;
                p.Image = global::BlockingUI.Properties.Resources.stopper;
            }
            done = true;
        }  

        private void ExitApp(object o, EventArgs e)
        {
            Application.Exit();
        }
    }

如果您真的想使用BackgroundWorker,那么这个(或类似的东西)应该会为您指明正确的方向。您正在创建一个BackgroundWorker对象,但随后对其不做任何操作。BackgroundWorker对象不允许访问UI元素,因为它们是由UI线程拥有的,但是你可以传递UI值,就像我在这里用Tuple做的那样(你可以创建自己的类来保存这些值,如果你想的话),然后从UI线程修改UI,一旦工作完成。

private struct ConnectionProperties
{
    public string Address;
    public string Port;
}
private void RunTest(object o, EventArgs e)
{
    BackgroundWorker worker = new System.ComponentModel.BackgroundWorker();
    worker.RunWorkerCompleted += TestComplete;
    worker.DoWork += TestConnection;
    p.Visible = true;
    //worker.RunWorkerAsync(new Tuple<string, string>(address.Text, port.Text));
    worker.RunWorkerAsync(new ConnectionProperties{ Address = address.Text, Port = port.Text });
}
private void TestConnection(object sender, DoWorkEventArgs e)
{
    bool success = false;
    //var connection = e.Argument as Tuple<string, string>;
    var connection = (ConnectionProperties)e.Argument;
    if (null != socket)
    {
        socket.Close();
    }
    Thread.Sleep(1000);
    IPEndPoint myEndpoint = new IPEndPoint(0, 0);
    IPHostEntry remoteMachineInfo = Dns.GetHostEntry(connection.Address);
    IPEndPoint serverEndpoint = new IPEndPoint(remoteMachineInfo.AddressList[0],
      int.Parse(connection.Port));
    socket = new Socket(myEndpoint.Address.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
    try
    {
        socket.Connect(serverEndpoint);
        success = true;
    }
    catch
    {
        success = false;
    }
    e.Result = success;
}
// Define other methods and classes here
private void TestComplete(object sender, RunWorkerCompletedEventArgs e)
{
    if (e.Error == null)
    {
        var success = (bool)e.Result;
        if (success)
        {
            p.Image = global::BlockingUI.Properties.Resources.accept;
        }
        else
        {
            p.Image = global::BlockingUI.Properties.Resources.stopper;
        }
    }
    else
    {
        //unexpected error, show message or whatever
    }
}

好吧,我已经用我自己的线程做了这个。通常,您使用长时间运行的任务运行线程,并在需要时调用Control.Invoke(),并使用指向将在UI上操作的函数的委托。看起来你正在使用后台工作线程更改UI,这是不允许的。

另外,在Winforms中,需要调用control . validate()来强制重新绘制UI并显示新图标。

相关内容

  • 没有找到相关文章

最新更新