C#随机数发生器卡在循环中

时间:2014-09-16 13:40:08

标签: c# user-interface

我刚开始编程,经过长时间的休息后遇到了一个小问题。

我正在使用VS2013桌面,并将其创建为GUI程序。

我的问题是,当用于调用逻辑方法的方法运行一次时,我创建了一个工作随机数生成器。生成的数字,文本更新,一切都很好。当它进入循环时,它不会更新我正在修改的对象的text属性,直到它完成整个循环或被破坏。当循环执行时我运行它时,程序基本上会挂起,我必须强制它关闭。

目前我想将发电机设置为在后台无限运行,直到我按下另一个按钮停止它。

我是编程新手,这可能有各种各样的问题,所以如果有任何问题,我会很感激任何有关结构和其他实践的反馈。

以下是代码:

Form1.cs的

    // Global
    bool boolLooper;

    // Setting up the random number generator
    private string RandomNumber()
    {
        RandomNumber rndNumber = new RandomNumber();

        string strRandNumber = Convert.ToString(rndNumber.RandomInt(1000, 9999999));

        return strRandNumber;
    }

    // TEST - used in buttonclick event
    private void TextUpdates()
    {
        while (BoolLooper == true)
        {
            txtID1.Text = RandomNumber();
            //txtName1.Text = RandomNumber();
            //txtSize1.Text = RandomNumber();
            //txtKey1.Text = RandomNumber();
            //txtType1.Text = RandomNumber();
        }
    }

    //-----------------------------
    // Form - Button Clicks
    //-----------------------------

    // Button - Activate
    private void btnActivate_Click(object sender, EventArgs e)
    {
        BoolLooper = true;

        TextUpdates();

        //// Update text once
        //txtID1.Text = RandomNumber();
        //txtName1.Text = RandomNumber();
        //txtSize1.Text = RandomNumber();
        //txtKey1.Text = RandomNumber();
        //txtType1.Text = RandomNumber();

    }

    // Button - Stop/Deactivate
    private void btnDeactivate_Click(object sender, EventArgs e)
    {
        BoolLooper = false;
    }

    //-----------------------------
    // Properties
    //-----------------------------

    public bool BoolLooper
    {
        get { return boolLooper; }
        set { boolLooper = value; }
    }

RandomNumber.cs

    private static readonly Random intRandom = new Random();
    private static readonly object syncLock = new object();

    public int RandomInt(int minNum, int maxNum)
    {
        lock (syncLock)
        {   
            // synchronize
            return intRandom.Next(minNum, maxNum);
        }
    }

对于RandomNumber课程,我在这个网站上找到了一篇很棒的帖子,我将在这篇文章中给予作者:https://stackoverflow.com/a/768001

5 个答案:

答案 0 :(得分:2)

您在与UI相同的线程上运行此代码。由于它是单线程的,因此用户界面无法响应,因为它正在忙着运行你的循环。您将要将其卸载到单独的线程或以某种方式作为单独的异步操作。然后,该线程/操作只需要在获取更新时告知UI。

一个简单的例子就是使用a BackgroundWorker object

请注意该页面上的示例BackgroundWorker公开可用于更新UI元素的事件:

private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
    resultLabel.Text = (e.ProgressPercentage.ToString() + "%");
}

还有其他可能的方法。您可以手动创建Thread并尝试手动同步它,但这也带来了其他潜在问题。而且这里确实没有必要让这个复杂。

您是否需要TextBox 不断更新?或者只是偶尔更新一次?如果更新之间有一些明显的时间段(一秒钟?),那么您可以使用a Timer来安排定期进行的代码。该结构类似于BackgroundWorker,因为它会暴露一个事件,用于更新UI。

答案 1 :(得分:1)

您的所有代码都在UI线程上执行。因此,您已停留在while循环中,并且表单不响应按钮单击(将您的while循环标志设置为false)。这就是我们所说的blocking call。它会阻止用户界面继续。

通常在这种情况下,您需要查看线程。但是,根据您的代码。我会查看一个计时器,并让它每隔一秒左右打勾。它们非常容易实现,您可以消除while循环的复杂性,只需执行随机数生成并将其分配给UI控件。 (这也使得你不必将后台线程编组回你的UI线程。)

有关计时器的更多信息: System.Windows.Forms.Timer

答案 2 :(得分:0)

您基本上需要运行每个调用以异步生成新数字。使用.NET Framework,有几种方法可以实现,但我更喜欢使用Task class。你可以这样做:

public Task RunAsynchronously(Action method)
{
    return Task.Factory.StartNew(method);
}

...

RunAsynchronously(() => MethodThatGeneratesRandomNumber());

每次调用此方法时,方法执行都将异步运行。

答案 3 :(得分:0)

您每次都在创建RandomNumber课程的新实例。只要让它成为你班上的一员。喜欢:

// Global
bool boolLooper;
//Random number generator
RandomNumber rndNumber = new RandomNumber();

并且不需要在方法RandomNumber中创建新实例,只需将其更改为:

private string RandomNumber()
{   
    string strRandNumber = Convert.ToString(rndNumber.RandomInt(1000, 9999999));

    return strRandNumber;
}

更新:我在评论后读了一下Application.DoEvents(),所以使用Invokes,等待任务调用,其他人,但不是这个。

答案 4 :(得分:0)

如果您使用的是.NET 4.5,请更新TextUpdates方法以使用async / await调用,如下例所示

private async void TextUpdates()
{
    await Task.Run(() =>
    {
        while (BoolLooper)
        {
            txtID1.Invoke((MethodInvoker)(() => txtID1.Text = RandomNumber()));
            //txtName1.Text = RandomNumber();
            //txtSize1.Text = RandomNumber();
            //txtKey1.Text = RandomNumber();
            //txtType1.Text = RandomNumber();
        }
    });
}