【问题标题】:Change the selected index of listBox after every 2 seconds using threading使用线程每 2 秒更改一次 listBox 的选定索引
【发布时间】:2012-01-13 11:09:00
【问题描述】:

我想每两秒更改一次列表框选定索引的索引。

public Form1()
{
    InitializeComponent();
    listBox1.Items.Add("A");
    listBox1.Items.Add("B");
    listBox1.Items.Add("C");
    listBox1.Items.Add("D");
    listBox1.Items.Add("E");
    listBox1.Items.Add("F");
}

public void SelectEvery2Sec()
{
    System.Windows.Forms.Timer timer=new System.Windows.Forms.Timer();
    for (int i = 0; i < listBox1.Items.Count; i++)
    {
        timer.Start();
        listBox1.SelectedIndex = i;
        try
        {
            Thread.Sleep(2000);
        }
        catch{}

        if(i == listBox1.Items.Count -1)
            i = 0;
    }
}

但是我们不能停止主线程。然后应用程序运行但我看不到 GUI。这不是正确的方式,所以我尝试下一种方式,即另一个线程。

那我再新建一个Thread但是不允许线程的交叉访问?

【问题讨论】:

    标签: c# .net winforms multithreading timer


    【解决方案1】:

    那我再新建一个Thread,但是不允许线程的交叉访问?

    正确。您不能从非 UI 线程访问 UI 控件。如果你尝试,你会得到一个例外。

    多线程不一定是每种情况下的正确解决方案。对于这种情况,计时器控件可能更简单——你想要的那个叫做System.Windows.Forms.Timer

    或者,您可以使用BackgroundWorker component。您所要做的就是在设计时将其添加到您的表单中,它会为您处理所有繁琐的工作。 MSDN 页面上有一个很好的示例。

    请注意Thread.Sleep is the sign of a poorly-designed program。如果你发现自己在代码中写了这些,那你就错了。几乎肯定有更好的方法。

    这种类型的问题在 Stack Overflow 上被问了很多。您可以通过执行搜索找到更多信息。

    【讨论】:

      【解决方案2】:

      您可以使用TimerBackgroundWorker 来执行此操作。对于Timer,将Interval 设置为2 秒。对于BackgroundWorker,请使用RunWorkerAsync

      对于cross thread access issue 使用

      public static class ControlExtensions
      {
          public static void Invoke(this Control control, Action action)
          {
              if (control.InvokeRequired) control.Invoke(new MethodInvoker(action), null);
              else action.Invoke();
          }
      }
      

      你的旧代码

      listBox1.SelectedIndex = i;
      

      会变成

      listBox1.Invoke(() => { listBox1.SelectedIndex = i; });
      

      【讨论】:

      • 如果您使用Timer,则不需要Invoke。这就是重点。计时器将在 UI 线程上引发事件,这是您想要的。
      【解决方案3】:

      使用System.Threading.Timer 代替System.Windows.Forms.Timer。这可以在工作线程中运行。

      让计时器超时事件处理程序调用一个函数来更改ListBox.SelectedItem,请务必检查Invoke.Required 更改列表框选定项,因为您可能需要Invoke

      【讨论】:

      • 您肯定需要使用Invoke(或BeginInvoke)从非UI线程与UI控件交互。但是,当您可以使用 BackgroundWorker 来处理所有事情时,您自己将所有的胶水放在一起是毫无意义的。
      【解决方案4】:

      将你的定时器对象的Interval设置为2000毫秒,不要让主线程休眠。

      您可以处理 Timer Elapsed 事件并更新控件。

      更新:

      为了通过两个线程实现它,每 2000 毫秒在第二个线程中引发一个事件,并将 Form 中的一个方法连接到它。在该方法中,您可以更改表单的控件。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-04-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多