且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

更新在C#窗体应用程序使用BackgroundWorker的UI线程

更新时间:2023-12-06 12:33:22

如果你真的想使用的BackgroundWorker ,这个(或接近它),应该指向你在正确的方向。您正在创建一个的BackgroundWorker 的对象,但然后什么都不做吧。 的BackgroundWorker 对象是不允许,因为它们是由UI线程拥有访问UI元素,但你可以在UI值传递,因为我有一个元组(你可以创建自己的类,如果你想太多持有这些值),然后修改从UI线程一旦工人完成的UI。

 私人结构的ConnectionProperties 
{
公共字符串地址;
公共字符串端口;
}

私人无效的runTest(对象o,EventArgs五)
{
BackgroundWorker的工人=新System.ComponentModel.BackgroundWorker();

worker.RunWorkerCompleted + = TestComplete;
worker.DoWork + = TestConnection;

p.Visible = TRUE;

//worker.RunWorkerAsync(new元组LT;字符串,字符串>(address.Text,port.Text));
worker.RunWorkerAsync(新ConnectionProperties中{地址= address.Text,端口= port.Text});
}

私人无效TestConnection(对象发件人,DoWorkEventArgs E)
{
BOOL成功= FALSE;
// VAR连接= e.Argument的元组LT;字符串,字符串取代;
VAR连接=(ConnectionProperties中)e.Argument;

如果(空=插座!)
{
socket.Close();
}

Thread.sleep代码(1000);

IPEndPoint myEndpoint =新IPEndPoint(0,0);
IPHostEntry remoteMachineInfo = Dns.GetHostEntry(connection.Address);
IPEndPoint serverEndpoint =新IPEndPoint(remoteMachineInfo.AddressList [0],
int.Parse(connection.Port));

插座=新的Socket(myEndpoint.Address.AddressFamily,SocketType.Stream,ProtocolType.Tcp);


{
socket.Connect(serverEndpoint);
成功= TRUE;
}

{
成功= FALSE;
}

e.Result =成功;
}

//定义其它的方法和类在这里
私人无效TestComplete(对象发件人,RunWorkerCompletedEventArgs E)
{
如果(e.Error = = NULL)
{
VAR成功=(布尔)e.Result;
如果(成功)
{
p.Image =全​​球:: BlockingUI.Properties.Resources.accept;
}
,否则
{
p.Image =全​​球:: BlockingUI.Properties.Resources.stopper;
}
}
,否则
{
//意外的错误,显示消息或任何
}
}


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.

Somehow I cannot get the idler gif become visible and animated. 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. You are creating a BackgroundWorker object but then doing nothing with it. 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.

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
    }
}