使用线程每隔2秒更改listBox的选定索引

本文关键字:listBox 索引 线程 2秒 | 更新日期: 2023-09-27 18:20:07

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

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。这是不正确的方式,所以我尝试下一种方式,即另一个线程。

然后我将创建一个新的线程,但线程的交叉访问是不允许的?

使用线程每隔2秒更改listBox的选定索引

然后我将创建一个新的线程,但线程的交叉访问是不允许的?

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

在任何情况下,多线程都不一定是正确的解决方案。对于这种情况,计时器控件可能更简单——您想要的控件称为System.Windows.Forms.Timer

或者,您可以使用BackgroundWorker组件。你所要做的就是在设计时将它添加到你的表单中,它会为你处理所有的脏活。MSDN页面上有一个很棒的示例。

请注意,Thread.Sleep是程序设计不佳的标志。如果你发现自己在代码中写了这些,那你就错了。几乎可以肯定有更好的方法。

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

您可以使用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; });

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

让计时器超时事件处理程序调用一个函数来更改ListBox.SelectedItem,确保在更改ListBox所选项目时检查Invoke.Required,因为您可能需要Invoke

将定时器对象的Interval设置为2000ms,不使主线程休眠。

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

更新:

要让它由两个线程组成,请每隔2000毫秒在第二个线程中引发一个事件,并将Form中的一个方法连接到它。在该方法中,您可以更改窗体的控件。