【问题标题】:Button Text, Inconsistent按钮文本,不一致
【发布时间】:2013-01-10 00:46:34
【问题描述】:

为什么我第一次尝试更改此代码中的按钮文本有效,而第三次尝试却有效?

串行端口连接时,我的用户将不得不等待几秒钟。之后,我想提醒他他已经连接(第二次尝试可能会导致问题)。

我想让他知道一切都很好,这样他就不会想“duh”并点击两次。

失败。文本更改永远不会出现。

好的,为什么按钮文本的第三个更改有效,但第一个无效?我不知道第二个是否有效。

 /***********************************************************************
  * Button:  Connect Port                                               *
  ***********************************************************************/

 private void TheConnectPortButton_Click(object sender, EventArgs e) 
 {
     string OldText = TheConnectPortButton.Text;

     TheConnectPortButton.Text = "Busy, Please Wait";  /////// This never happens

     ButtonBoss.ButtonHandler_ConnectPort();

     TheConnectPortButton.Text = OldText;              /////// Not sure if this happens

     if (aUartSemaphoreThatTells.IfWeHaveConnectedToAPort == (int)aValueWhichIndicatesThat.YesWeHaveAGoodPortConnected)
     {
         TheConnectPortButton.Text = "Connected";      /////// This one does happen
     }

 }

aUartSemaphoreThatTells.IfWeHaveConnectedToAPort 也被 ButtonBoss 例程使用,以确保他不会再次连接,以及其他按钮例程(例如,确保我们在 Tx/Rx 之前连接或其他)。

我尝试在例程返回后更改代码,使其看起来像这样......

    if (aUartSemaphoreThatTells.IfWeHaveConnectedToAPort == (int)aValueWhichIndicatesThat.YesWeHaveAGoodPortConnected)
    {
        TheConnectPortButton.Text = "Connected";
    }
    else
    {
        TheConnectPortButton.Text = OldText;
    }

...我仍然得到相同的结果。

我的猜测(仅此而已)是线程以某种方式参与了所有这一切,并且串行端口例程通过一些我目前没有正确遵循的卷积来胜过按钮文本更改例程。

问题:我需要做什么才能在连接内容占用系统之前更改文本?

(如果是这样的话)

问题 2:如果我不能做到这一点,我想我已经阅读过有关“灰显”按钮的信息,或者,我相信我在某个地方看到了我实际上可以让按钮在用户眼前消失这样他就不能再点击了。欢迎提供示例代码的链接。

【问题讨论】:

  • 你更新你的屏幕了吗?变灰 button.enabled = false,隐藏 button.hide,通过 google 查看 msdn
  • 不,我不更新我的屏幕。我要去看看那是什么意思。喜欢的话给我个链接,我会关注的。
  • 这是 WinForms、WebForms、WPF 吗?
  • msdn.microsoft.com/en-us/library/…开始,从那里开始
  • 非常基础的 UI 代码,任何关于它的书都很好地涵盖了。快速修复,每个人都喜欢快速修复而不是读书,是 TheConnectPortButton.Update()。

标签: c# button text


【解决方案1】:

问题在于,您正在使用同一个事件处理程序执行所有操作,因此按钮没有时间更新(重绘)。你可以调用Application.DoEvents();方法,但这根本不是一个好主意,请阅读Use of Application.DoEvents()

我认为通常您应该将耗时的任务推送到单独的线程中,从中获取进度报告并更新您的 GUI。有很多方法可以创建“工作”线程并从中获得一些响应。例如,使用BackgroundWorker Class

public partial class Form1 : Form
{
    public Form1() { InitializeComponent(); }

    private void button1_Click(object sender, EventArgs e)
    {
        BackgroundWorker w = new BackgroundWorker();
        w.WorkerReportsProgress = true;
        w.DoWork += new DoWorkEventHandler(w_DoWork);
        w.ProgressChanged += new ProgressChangedEventHandler(w_ProgressChanged);
        w.RunWorkerCompleted += new RunWorkerCompletedEventHandler(w_RunWorkerCompleted);
        w.RunWorkerAsync();
        button1.Text = "Started";
    }

    //may influence GUI, as this event handler is run on the GUI thread
    void w_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        button1.Text = "Job is done";
    }
    //may influence GUI, as this event handler is run on the GUI thread
    void w_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        button1.Text = e.ProgressPercentage.ToString();
    }
    //runs in the worker thread...should do the actual job
    //may influence GUI through `ReportProgress`
    //or through `Invoke` method
    void w_DoWork(object sender, DoWorkEventArgs e)
    {
        BackgroundWorker worker = sender as BackgroundWorker;
        for (int i = 1; i <= 10; i++)
        {
            Thread.Sleep(500);
            worker.ReportProgress(10 * i);
        }
    }
}

或者你可以使用Task Class:

public partial class Form1 : Form
{
    public Form1() { InitializeComponent(); }

    private void button1_Click(object sender, EventArgs e)
    {
        new Task(DoTask).Start();
    }

    void DoTask()
    {
        for (int i = 1; i <= 10; i++)
        {
            Thread.Sleep(500);
            //here you need to update GUI through `Invoke` method
            //as the GUI may only be influenced from the the thread,
            //where it's created
            this.Invoke(new Action<int>((j) =>
                {
                    button1.Text = j.ToString();
                }), 10 * i);
        }
    }
}

【讨论】:

  • 您对 BackGroundWorker 的建议似乎是处理此问题的好方法。如果我想错了,请修复我的大脑,但看起来我真正想要使用的后台工作人员的唯一部分是 DoWork 和 RunWorkerCompleted。是的 ?不 ?在这一切中最重要的是一个SerialPort.Open() 调用,它正在使用我目前不了解或控制的USB 驱动程序。无论他们在做什么,最多可能需要 30 秒;通常为 5 到 15 秒。
  • 你只需要考虑你要从哪里更新你的用户界面(让它是按钮文本,无论如何)......如果你想从DoWork方法中做到这一点,您需要将所有 GUI 修改包装到 Invoke 方法调用中...另一种方法是调用 ReportProgress 并传递一些预定义的百分比,根据这些百分比您将在 ProgressChanged 事件中设置适当的按钮文本处理程序。
  • @User.1 另一种方法可能是为耗时任务的不同部分启动单独的工作人员并更新 buttontext + 在RunWorkerCompleted 方法中启动下一部分。但是我想这是最不适合您的任务的方法
  • 目前,这只是一项任务,用户必须先完成,然后应用程序的其余部分才能执行任何操作。我们必须先让端口说话,然后才能让应用程序完成其设计的任务。不管怎样,这些看起来都是好主意。谢谢
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-02-22
  • 1970-01-01
  • 2014-04-29
  • 1970-01-01
  • 2018-03-07
相关资源
最近更新 更多