【问题标题】:While Loop Function after a button is pressed and stop looping when another button is pressed C#按下按钮后的while循环功能并在按下另一个按钮时停止循环C#
【发布时间】:2020-06-01 04:23:35
【问题描述】:

在我的 Windorm Form 应用程序中,我有两个按钮,当按下 button1 时循环函数将开始工作,按下 button2 后停止执行。我怎么能这样做以防止我的 GUI 无响应。 我怎么能插入命令while(button2.clicked != true)

按钮 1 的代码:

private async void EmoStart_Click_1(object sender, EventArgs e)
    {
        //var repeat = "true";
        string imageFilePath = "C:\\Users\\Administrator\\source\\repos\\FaceDetection\\FaceDetection\\test3.jpg";
       while (VoiceStart_Click_2 != "true")
       {
        var image = pictureBox1.Image;
        image = resizeImage(image, new Size(1209, 770));
        image.Save(imageFilePath);
        if (File.Exists(imageFilePath))
        {
            var Emo = await FaceEmotion.MakeAnalysisRequest(imageFilePath);
            if (Emo[0].FaceAttributes.Emotion.Anger >= 0.5)
            {
                EmoBox.Text = "Anger, Bad Driving Condition, Soft Music will be played";
            }
            else if (Emo[0].FaceAttributes.Emotion.Contempt >= 0.5)
            {
                EmoBox.Text = "Contempt, Bad Driving Condition, Soft Music will be played";
            }
            else if (Emo[0].FaceAttributes.Emotion.Disgust >= 0.5)
            {
                EmoBox.Text = "Disgust, Bad Driving Condition, Soft Music will be played";
            }
            else if (Emo[0].FaceAttributes.Emotion.Fear >= 0.5)
            {
                EmoBox.Text = "Fear, Bad Driving Condition, Soft Music will be played";
            }
            else if (Emo[0].FaceAttributes.Emotion.Happiness >= 0.5)
            {
                EmoBox.Text = "Happiness, Good Driving Condition";
            }
            else if (Emo[0].FaceAttributes.Emotion.Neutral >= 0.5)
            {
                EmoBox.Text = "Neutral, Good Driving Condition";
            }
            else if (Emo[0].FaceAttributes.Emotion.Sadness >= 0.5)
            {
                EmoBox.Text = "Sadness, Bad Driving Condition, Rock Music will be played";
            }
            else if (Emo[0].FaceAttributes.Emotion.Surprise >= 0.5)
            {
                EmoBox.Text = "Happiness, Bad Driving Condition, Soft Music will be played";
            }
            else
            {
                EmoBox.Text = "Stable Condition, Good Driving Condition";
            }
        }
    }

而对于我的 button2 代码:

private async void VoiceStart_Click_2(object sender, EventArgs e)
{
    string command = await Voice.RecognizeSpeechAsync();
    VoiceBox.Text = command;
}

谢谢!

【问题讨论】:

  • 使用后台工作者

标签: c#


【解决方案1】:

您必须在单独的线程中运行循环。例如,您可以异步运行它。像这样的:

// start the loop
private async void button1_Click(object sender, EventArgs e)
{
    LoopStopped = false;
    await StartLoopAsync();
}

// put yor while loop here
private Task StartLoopAsync()
{
    return Task.Run(() =>
    {
        while (LoopStopped == false)
        {
            var date = DateTime.Now;
            System.Diagnostics.Debug.WriteLine(date);

        }
        System.Diagnostics.Debug.WriteLine("Thread stopped.");
    });
}

// stop the loop
private void button2_Click(object sender, EventArgs e)
{
    LoopStopped = true;
}

LoopStopped 是全局布尔变量。

【讨论】:

  • 是的,它起作用了,当我按下按钮 1 并停止按钮 2 的循环时,我可以重复循环。但是,当我在多次间隔几个间隔后按下按钮 1 和按钮 2 时,它显示错误。错误代码在我的“Emo[0].faceattribute.emotion”中,错误为“索引超出范围。必须为非负数且小于集合的大小。”
  • 可能面部/情感捕捉并不总是成功,并且 Emo 内部没有任何元素。所以你的Emo[0] 指向一种不存在的情绪。你应该在得到一个之前检查 Emo 是否有任何元素。
  • 为什么不让private void button1_Click 也异步和await StartLoop(); 在里面?
  • 如果我在button1中的loop函数没有运行完但是我按下了button 2,会不会影响输出?可以用上面的方法解决吗(将await loopfunction放在button1中)?
  • @JunWong 我不确定我是否理解这个问题。在开始迭代之前,循环检查它是否可以开始(LoopStopped == false)。然后,如果开始迭代,它会一直运行到结束,无论你是否点击了 button2。并且只有在迭代完成后,循环才会再次检查是否可以开始新的迭代。
【解决方案2】:

您放入EmoStart_Click_1 的所有操作都同步运行,除了:

FaceEmotion.MakeAnalysisRequest(imageFilePath)

因此界面 (UI) 被冻结。

像你所做的那样将方法的签名更改为异步是不够的。您必须告诉编译器,应该等待哪些其他部分。您希望整个 while 函数异步!

private async void EmoStart_Click_1(object sender, EventArgs e)
{
    EmoStart.Enabled = false;           //I assume EmoStart is the name of your button
    await Task.Factory.StartNew(Loop);
    EmoStart.Enabled = true;
}

private void Loop()                     //since this method doesn't have async in its signature "var Emo = await FaceEmotion.MakeAnalysisRequest(imageFilePath);" won't compile, so you should change to the synchronous equivalent "var Emo = FaceEmotion.MakeAnalysisRequest(imageFilePath).Result;" --> note that it won't block due to "Task.Factory.StartNew".
{
    string imageFilePath = "C:\\Users\\Administrator\\source\\repos\\FaceDetection\\FaceDetection\\test3.jpg";
    while (...)
    {
        // do your stuff
    }

然后您可以决定如何取消 while 循环。

选项 1.:您可以使用全局布尔变量:

private bool emotionsShouldBeProcessed;

然后你在EmoStart_Click_1 中设置它为真,这样设置为假:

private async void VoiceStart_Click_2(object sender, EventArgs e)
{
    VoiceStart.Enabled = false;
    emotionsShouldBeProcessed = false;
    // start and await voice stuff 
    VoiceStart.Enabled = true;
}

选项 2.:您可以使用 CancellationToken 来跟踪是否需要取消。

CancellationTokenSource cSource;

private async void EmoStart_Click_1(object sender, EventArgs e)
{
    EmoStart.Enabled = false;
    cSource = new CancellationTokenSource();
    await Task.Factory.StartNew(() => Loop(cSource.Token));
    EmoStart.Enabled = true;
}
private void Loop(CancellationToken cToken)
{
    string imageFilePath = "C:\\Users\\Administrator\\source\\repos\\FaceDetection\\FaceDetection\\test3.jpg";
    while (true)
    {
        if (cToken.IsCancellationRequested)
            break;
        // otherwise do your stuff
    }
    // some clean up here if necessary
}
private async void VoiceStart_Click_2(object sender, EventArgs e)
{
    VoiceStart.Enabled = false;
    cSource.Cancel();
    VoiceStart.Enabled = true;
}

到目前为止一切顺利!但是你的代码会崩溃

只要你想设置EmoBox.Text,它就会崩溃,因为这只会发生在 UI 线程上。为避免这种情况,您需要让 UI 线程中断,直到 Textbox/Label/etc 操作正在进行,如下所示:

this.Invoke((MethodInvoket)delegate
{
    EmoBox.Text = "...";
});

编辑:

我还会检查 Emo 数组是否为空,因为面部和情绪识别并不总是成功!因此,Emo[0] 可能导致“索引超出范围”异常。以下代码确保它不为空:

var Emo = ...;
if (Emo.Length > 0)
{
    if (...)
        // use Emo[0]
    else if (...)
        // use Emo[0] differently
}

如果有什么不清楚的地方请告诉我。

【讨论】:

  • 我能知道voicestart.enabled和emostart.enabled的功能是什么吗?是不是用来避免任务运行时按钮被按下?
  • 没错。您绝对希望避免第二次识别!
  • 为了解决“索引超出范围”,我应该在“var Emo = await FaceEmotion.MakeAnalysisRequest(imageFilePath);”行之间放置一行“if (Emo.Length > 0)”和行“if (Emo[0].FaceAttributes.Emotion.Anger >= 0.5)”?这一行是为了确保当我的 Emo[array] 中有东西时它会执行以下功能?
  • 我无法添加“Emo.Length”,没有长度定义
  • Arrays have Length property 也许您需要将 using System; 写入 .cs 文件的顶部。否则从FaceEmotion.MakeAnalysisRequest 返回的对象不是数组:做两件事。 1: 检查是否有Count 属性(不应是Count() 函数)2: 键入Emo.按 ctrl + 空格后点 以查看可用的内容并选择提供信息的内容。例如:.Succeed.HasItems.ItemCount.IsEmotionCaptured.Any()。 +1(最坏的主意)也许你可以foreach Emo
【解决方案3】:

您可以创建一个布尔变量并在您的变量为真时进行循环。

所以当 button1 被点击时,将变量设置为 true。

那么你的 while 将如下所示:

while(myBoolVariable)

当 button2 被点击时,你可以将值更改为 false,while 将停止。

【讨论】:

  • 如果我按了我的 button1,它只会发送一次 (myBoolVariable = true),当我只按一次 button1 时如何重复循环?
  • @Presi 这行不通。它会使 GUI 反应迟钝。
  • 是的,它起作用了,当我按下按钮 1 并停止按钮 2 的循环时,我可以重复循环。但是,当我按下按钮 1 然后按钮 2 并开始再次按下按钮 1 时,它显示错误。错误代码在我的“Emo[0].faceattribute.emotion”中,错误为“索引超出范围。必须为非负数且小于集合的大小。”
  • @JunWong 您的列表有问题,可能没有任何项目。
  • 但它只发生在我按下按钮1和按钮2几次之后。由于我在按钮1和按钮2之间切换太快,会不会是处理时间的计时问题?
【解决方案4】:

您可以使用全局变量(bool 是一个不错的选择)

当 VoiceStart_Click_2 改变变量时

并在单击 EmoStart_Click_1 时检查变量

if (variable==true)
{
    var Emo = await FaceEmotion.MakeAnalysisRequest(imageFilePath);
    if (Emo[0].FaceAttributes.Emotion.Anger >= 0.5)
    {
       EmoBox.Text = "Anger, Bad Driving Condition, Soft Music will be played";
    }
    ...

}

【讨论】:

    猜你喜欢
    • 2015-07-19
    • 1970-01-01
    • 2012-07-14
    • 2022-01-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多