【问题标题】:updating UI thread using BackGroundWorker in C# Form application在 C# Form 应用程序中使用 BackGroundWorker 更新 UI 线程
【发布时间】:2014-04-19 17:27:09
【问题描述】:

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

不知何故,我无法让闲置 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,但你从不使用它。

标签: c# multithreading user-interface backgroundworker invoke


【解决方案1】:

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

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

【讨论】:

    【解决方案2】:

    如果你真的想使用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
        }
    }
    

    【讨论】:

    • 谢谢。我想采纳您的建议,并在尝试使用以下行时: var connection = e.Argument as Tuple;我收到编译错误:找不到类型或命名空间“元组”。您是否缺少 using 指令或程序集引用?
    • 您使用的是什么版本的 .NET? Tuple 仅在 4.0+ 中可用。正如我上面提到的,您不必使用这个内置类,您可以构建自己的简单类或具有 Address 和 Text 成员的结构。如果您需要更多详细信息,我可以更新答案。
    • 谢谢。我可以使用 .NET 4.0 或 4.5 切换到 VS 2010,但目前,如果您可以更新解决方案并指出传递字符串数组或使用类成员的方法,那将会很有帮助。
    • @Krischu 我已经更新了我的答案以提供一个使用简单的struct 的实现。这适用于具有BackgroundWorker 的任何.NET 版本。
    • 我收到code Error 2 The as operator must be used with a reference type or nullable type ('BlockingUI.Form1.ConnectionProperties' is a non-nullable value type)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-02
    • 1970-01-01
    相关资源
    最近更新 更多