简体   繁体   English

在C#Form应用程序中使用BackGroundWorker更新UI线程

[英]updating UI thread using BackGroundWorker in C# Form application

I have a time consuming task that tests a couple of network connections. 我有一个耗时的任务,需要测试几个网络连接。 In my example below I have confined it to one connection. 在下面的示例中,我将其限制为一个连接。 Normally the connection returns quickly but it could happen that the connection cannot be made so that the socket times out. 通常,连接会快速返回,但是可能会发生无法建立连接从而导致套接字超时的情况。 During this time I would like to display an "idler" gif in the Form, when the connection succeeds the app should change the Image in the Form to some green check icon or in case of a failing connection a red icon "stopper" should be displayed. 在此期间,我想在表单中显示一个“ idler” gif,当连接成功时,应用程序应将“表单”中的“图像”更改为一些绿色复选图标,或者在连接失败的情况下,将红色图标“ stopper”更改为显示。

Somehow I cannot get the idler gif become visible and animated. 不知何故,我无法使惰轮gif变得可见并具有动画效果。 To simulate a failing connection one can enter an invalid port # or non existent address. 要模拟失败的连接,可以输入无效的端口号或不存在的地址。

Any clues what I'm missing or doing wrong? 有什么线索我想念或做错了什么吗?

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

    }

If you truly want to use a BackgroundWorker , this (or something close to it), should point you in the right direction. 如果您确实想使用BackgroundWorker ,那么它(或接近它的东西)应该为您指明正确的方向。 You are creating a BackgroundWorker object but then doing nothing with it. 您正在创建BackgroundWorker对象,但是对此不执行任何操作。 BackgroundWorker objects are not allowed to access UI elements as they are owned by the UI thread, but you can pass in UI values, as I do here with a Tuple (you could create your own class to hold these values if you want too) and then modify the UI from the UI thread once the worker is complete. 不允许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
    }
}

Well, I had done this with my own thread. 好吧,我是用自己的线程完成的。 Normally, you run the thread with the long running task, and when needed, call Control.Invoke() with a delegate pointing to a function that will operate over the UI. 通常,您使用长时间运行的任务运行线程,并在需要时调用Control.Invoke()并使用一个指向将在UI上运行的函数的委托。 It looks that you're changing the UI using the background worker thread, which is not allowed. 看来您正在使用后台工作线程更改UI,这是不允许的。

Also, in Winforms is necessary to call Control.Invalidate() to force a re-painting of the UI and show the new icons. 此外,在Winforms中,必须调用Control.Invalidate()来强制重新绘制UI并显示新图标。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM