Reed_redd 2023-02-02 11:31 采纳率: 100%
浏览 61
已结题

关于#c##的问题:winform中利用delegate更新ui的顺序错误

在做一个简单地winform工控机,主要使用TCP连接。但不知道为说明在调用delegate时会产生错序的情况。

我在主界面上面设置了一个Status Strip来作为状态提示。然后在全局变量中声明委托,这样我就可以在异步创建Tcp连接时去更新主界面的状态提示。

namespace RsmiMonitorForWifi
{
    ///全局delegate
    public delegate void StatusUpdate(string infor);

    internal static class Program
    {
        /// 
        /// 应用程序的主入口点。
        /// 
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new frmModelSelect());
        }
    }
}
frmMain.cs(1/2)
public static StatusUpdate statusUpdate = null;

public frmMain()
        {
            InitializeComponent();
  
            statusUpdate = new StatusUpdate(StatusUpdate);
            tcpMethod = new tcpMethod("192.168.1.39",8080);
            TcpClient tcpClient = tcpMethod.TcpCreateAsync();
        }

TcpMethod.cs
public TcpClient TcpCreateAsync()
        {
            tcpClient = new TcpClient();
            try
            {
                tcpClient.BeginConnect(iP, iPort, new AsyncCallback(ConnectedAsync), tcpClient);
                _tcpBusy = true;
                frmMain.statusUpdate("正在尝试连接网络...");
            }
            catch (Exception e)
            {
                frmMain.statusUpdate(e.Message);
            }
            return tcpClient;
        }

        //连接回调
        private void ConnectedAsync(IAsyncResult asyncResult)
        {
            tcpClient = asyncResult.AsyncState as TcpClient;
            if (tcpClient != null)
            {
                try
                {
                    tcpClient.EndConnect(asyncResult);
                    frmMain.statusUpdate("连接成功");
                }
                catch (SocketException e)
                {
                    frmMain.statusUpdate(e.Message);
                }
            }
            _tcpBusy = false;
        }

问题出在下面这一段,因为发现单个statuslabel的显示效果不好,我想要让statuslabel1储存statuslabel2的内容,用stauslabel2去显示最新的状态信息,如图:

img

frmMain.cs(2/2)
private void StatusUpdate(string infor)
        {
            string currentTime = DateTime.Now.ToString("HH:mm:ss");
            //不知道为什么delegate的调用顺序会出问题,暂时只使用一个text
            //statuslb_currentstate1.Text = statuslb_currentstate2.Text;
            statuslb_currentstate2.Text = $"{currentTime} {infor}";
        }

测试下来在第一次连接时表现良好,但当我第二次创建连接时,理论上应该更新两次时实际只更新了一次,表现正常的情况下label1的text应为11:08分的 "正在尝试连接", label2的text应为11:08分后的 "连接成功"

img

Debug后发现主页面更新时,先更新了"连接成功"

img


然后label1的text没有被更新,紧接着label2的值被更新成 "正在尝试连接",造成了看上去只有label2被更新了一次的假象。

之后我发现debug时情况会有所不同,有时可以又是不行。我的猜测是我对线程运作的理解有误,导致主线程更新控件时的执行顺序随机。怎么样才能稳定的实现我想要的效果呢

  • 写回答

4条回答 默认 最新

  • 2301_76247172 2023-02-02 16:31
    关注

    在主线程里
    tcpClient.BeginConnect(iP, iPort, new AsyncCallback(ConnectedAsync), tcpClient);
    _tcpBusy = true;
    frmMain.statusUpdate("正在尝试连接网络...");

    BeginConnect里使用了new AsyncCallback(ConnectedAsync),系统就会另起一个线程执行回调函数,这里就有 主线程和 执行回调ConnectedAsync的单独线程,如果当主线程刚刚把 _tcpBusy = true;执行完,还没来得及执行 frmMain.statusUpdate("正在尝试连接网络...");,就暂停了,这时系统执行 回调ConnectedAsync的线程,自然 先执行 frmMain.statusUpdate("连接成功"),这时状态更新就错误了,
    所以 _tcpBusy = true;
    frmMain.statusUpdate("正在尝试连接网络..."); 这两句应该加载 回调函数 tcpClient.EndConnect(asyncResult);的前面

    _tcpBusy = true;
    frmMain.statusUpdate("正在尝试连接网络...");
    tcpClient.EndConnect(asyncResult);
    frmMain.statusUpdate("连接成功");
    
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(3条)

报告相同问题?

问题事件

  • 系统已结题 2月10日
  • 已采纳回答 2月2日
  • 赞助了问题酬金15元 2月2日
  • 创建了问题 2月2日

悬赏问题

  • ¥20 机器学习能否像多层线性模型一样处理嵌套数据
  • ¥20 西门子S7-Graph,S7-300,梯形图
  • ¥50 用易语言http 访问不了网页
  • ¥50 safari浏览器fetch提交数据后数据丢失问题
  • ¥15 matlab不知道怎么改,求解答!!
  • ¥15 永磁直线电机的电流环pi调不出来
  • ¥15 用stata实现聚类的代码
  • ¥15 请问paddlehub能支持移动端开发吗?在Android studio上该如何部署?
  • ¥20 docker里部署springboot项目,访问不到扬声器
  • ¥15 netty整合springboot之后自动重连失效