2017-08-07 54 views
1

我在C#中创建一个代码,其中我从Access数据库中提取一些记录,但我需要一段时间去下一个迭代以取决于点击一个按钮。我尝试了一些线程或任务,但它没有工作,因为它阻止了我需要它看到和点击的UI。C# - 使用UI功能,像一个无限循环,直到按下按钮

下面的代码:

bool nextClick = false ; 

       while (readerSelect.Read()) 
       { 

        // show the correct panel 
        if (string.Compare(readerSelect[2].ToString(), "P1") == 0) 
        { 
         // panel with type 1 
         textBoxP1Text1.Text = readerSelect[3].ToString(); 
         textBoxP1Text2.Text = readerSelect[4].ToString(); 
         pictureBoxP1Image.ImageLocation = readerSelect[6].ToString(); 

        } 
        else 
        { 
         // panel with type 2 
         textBoxP1Text2.Text = readerSelect[5].ToString(); 
        } 

    //this while need to be kind of infinite so the interation can't be processed and 
    //so when i need to change iteration i click the buttonNext 
        while (!nextClick) { 
        startWhile:; 
         MethodInvoker mi = delegate() { 
          if (nextClick) 
          { 
           Application.DoEvents(); 
           // System.Windows.Forms.Application.Run(); 
          } 

         }; 
         this.Invoke(mi); 
         //break; 
         goto startWhile; 
        } 

private void buttonNext_Click(object sender, EventArgs e) 
    { 
     // click on the next button 
     nextClick = true; 
    } 
+1

如果您只需点击一下即可转到下一个项目,请不要使用while循环...只需在每次点击时执行一次... – Milney

+0

这将对我们的连接产生重大影响,差,但谢谢你回答 –

+0

你是什么意思'对你的连接有重大影响'?这只是不正确的。你现在和现在这样做的方式只会读取有多少记录。你误会了。我建议阅读DataReader文档,直到你更好地理解它作为第一点 – Milney

回答

2

虽然达克斯Fohl的答案的作品,好像你已经得到了你的设计有问题。我认为你在Form课上有太多的商业逻辑正在违反Single Responsibility Principle

我建议将业务逻辑分解为它自己的类。然后,而不是遍历循环中的所有内容,只需按下按钮单击事件即可处理下一条记录并显示结果。这里是我的意思的一个例子:

public partial class Form1 : Form 
{ 
    private readonly DataProcessor dataProcessor = new DataProcessor(); 

    public Form1() 
    { 
     this.InitializeComponent(); 
    } 

    private void button1Next_Click(object sender, EventArgs e) 
    { 
     this.buttonNext.Enabled = false; 
     this.ProcessNext(); 
    } 

    private async void ProcessNext() 
    { 
     string s = await this.dataProcessor.ProcessNext(); 
     this.textBoxP1Text1.Text = s; 
     this.buttonNext.Enabled = true; 
    } 
} 

public class DataProcessor 
{ 
    private readonly Random r = new Random(); // Or reader or whatever. 

    public async Task<string> ProcessNext() // Just using `string` as an example. 
    { 
     await Task.Delay(1000); 
     return this.r.Next().ToString(); 
    } 
} 

我认为这将会更容易理解,并在将来更易于维护。当一个新的团队成员查看信号量(或未来的自我)时,很难理解/记住所有这一切的重点。在这里,你只需要一个本地功能来完成一件事,而且很容易就能完成。

3

您可以使用异步任务内的信号,有按钮Release它每一次点击中,并有while循环通过每一次等待着它。这里有一个简单的例子,使用具有button1形式和label1添加到它:

public partial class Form1 : Form 
{ 
    private readonly SemaphoreSlim signal = new SemaphoreSlim(0, int.MaxValue); 

    public Form1() 
    { 
     this.InitializeComponent(); 
     this.RunLoop(); 
    } 

    private async void RunLoop() 
    { 
     var i = 0; 
     while (true) 
     { 
      this.label2.Text = $"Enqueued: {this.signal.CurrentCount}"; 
      await this.signal.WaitAsync(); // Wait button click async 
      await Task.Delay(1000); // Simulate work 
      this.label1.Text = $"Completed: {++i}"; 
     } 
    } 

    private void button1_Click(object sender, EventArgs e) 
    { 
     this.signal.Release(); 
     this.label2.Text = $"Enqueued: {this.signal.CurrentCount + 1}"; 
     // Or if you want to limit the # people can queue up, then put this whole 
     // thing in an `if (signal.CurrentCount < myLimit)` block, and optionally 
     // disable the button once limit has been reached, and re-enable it right 
     // before the `WaitAsync` call above. 
    } 
} 
+0

如果用户在运行循环完成时单击多次,是否可能导致SemaphoreFullException?我曾想过其中一个EventWaitHandle类会更合适。 –

+0

@MartinBrown是的,刚刚更新的答案说明了这一点。 –

+0

非常感谢,这对我来说很有效:) –