winforms 由于Windows窗体应用程序.Exit()不立即关闭UI线程,因此可以使用其他方法?

llmtgqce  于 2023-03-31  发布在  Windows
关注(0)|答案(1)|浏览(174)

我有我的个人代码的这一部分,我想改进,在总结程序的一般结构是这样的:

// This form is just an UI onscreen label that I want to display.
var task = Task.Run(() => Application.Run(new Form1()));
// Just toggle microphone and listening here.
using (Speechrecognition....)
{
    while (loop for 5 seconds)
        {
            // Do something.
        }
}
Application.Exit();
// More things down here.

现在这段代码可以被反复调用,这意味着当我需要它的时候,它会显示并关闭表单Application.Exit(),到目前为止,除了这个意外的行为之外,它做得非常出色。
每当我启动程序并第一次调用它时,它总是出现并等待整整5秒,因为循环然后关闭自己。然而,如果我立即再次调用程序的这一部分,它可能给予意想不到的行为,这是一个60/40,60%的机会坐在循环中,像正常一样等待,然后关闭自己。虽然有40%的机会UI只是弹出和关闭后的权利,线程的任务仍然运行,直到应用程序退出,但我注意到UI图标的外观在任务栏上在我的第二个监视器,所以我知道它开始和关闭,只是不显示。
然而,只有当我立即再次调用这部分代码时,它才会这样做,但不是在一段时间之后,我发现的证据是在Application.Exit()之后,我注意到调试控制台说:

The thread 0x522c has exited with code 0 (0x0).

15-20秒后:

The thread 0x4af8 has exited with code 0 (0x0).
The thread 0x162c has exited with code 0 (0x0).
The thread 0x5f4c has exited with code 0 (0x0).
The thread 0x66a4 has exited with code 0 (0x0).

如果我等待并在第二部分出现后调用它,问题就不会发生(10/10测试)但在第一个测试之后完全可能,我尝试过form & environment closeawait 2 tasks...等来完成,然后再继续,但这些似乎不是解决方案,因为它们与程序结构相冲突,或者只是Application.Exit()提供了更好的体验。还有其他方法可以改进吗?谢谢!
编辑:这里是最小可重复的示例,它在第一次调用后立即随机打开和关闭:
在程序.cs中:

using minimalproblem;
namespace Minimal_reporduce
{
    internal static class Program
    {
        /// <summary>
        ///  The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main()
        {
            // To customize application configuration such as set high DPI settings or default font,
            // see https://aka.ms/applicationconfiguration.
            ApplicationConfiguration.Initialize();
            Class1.Method1();
        }
    }

}

在负责调用UI的后端代码中:

using Minimal_reporduce;//project name

namespace minimalproblem {
    public class Class1
    {
        public static void Method1()
        {
            while (true) { 
            // This form is just an UI onscreen label that I want to display.
            var task = Task.Run(() => Application.Run(new Form1()));
            // Just toggle microphone and listening here.
            DateTime startTime = DateTime.Now;
            DateTime endTime = startTime.AddSeconds(5);
            Console.WriteLine("Enter Command");
            while (DateTime.Now <= endTime)
            {
                
            }
            Application.Exit();
            }
        
        }
    }
    }

补充问题:我在某个地方读到过,在程序的生命周期中多次调用和破坏UI可能是不好的,这一次是不是这样,我做错了?
Edit 2:只是为了给这个问题添加更多的信息,我几乎可以保证线程与它的行为有一定的关系,因为它并不总是需要那么长的时间来退出所列出的那么多线程,有时候所有的线程几乎都是在执行Application.exit()之后显示的,如果我在那时调用它,显示就可以工作了!

fgw7neuy

fgw7neuy1#

根据您的评论,我建议将语音识别表单包含在主表单中。这将允许以您提到的方式重新触发语音表单。这可能不是您想要的 * 确切 * 行为,但我希望它可以作为一个起点。
Application.Run方法应该只在program.cs入口点中调用一次,以启动应用程序的主消息循环。

internal static class Program
{
    /// <summary>
    /// The main entry point for the application.
    /// </summary>
    [STAThread]
    static void Main()
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new MainForm());
    }
}

主窗体

public partial class MainForm : Form
{
    public MainForm()
    {
        InitializeComponent();
        buttonShowSpeech.Click += onClickShowSpeech;
    }

    SpeechForm _speechForm = new SpeechForm();
    private void onClickShowSpeech(object sender, EventArgs e)
    {
        Task
            .Delay(TimeSpan.FromSeconds(5))
            .GetAwaiter()
            .OnCompleted(() => _speechForm.Close());
        _speechForm.ShowDialog();
    }
}

单击按钮后,SpeechForm将显示5秒,然后关闭。此过程可以重复任意次数。

演讲形式

public partial class SpeechForm : Form
{
    public SpeechForm()
    {
        InitializeComponent();
        StartPosition = FormStartPosition.CenterParent;

        // https://learn.microsoft.com/en-us/dotnet/api/system.speech.recognition.speechrecognizer.loadgrammar?view=netframework-4.8.1
        SRE = new SpeechRecognitionEngine();
        SRE.SpeechRecognized += onSpeechRecognized;
        Grammar testGrammar =
          new Grammar(new GrammarBuilder("testing"));
        testGrammar.Name = "Test Grammar";
        SRE.LoadGrammar(testGrammar);
        SRE.SetInputToDefaultAudioDevice();
        SRE.RecognizeAsync(RecognizeMode.Multiple);
    }
    protected override void OnVisibleChanged(EventArgs e)
    {
        base.OnVisibleChanged(e);
        if(Visible)
        {
            textBox1.Text = "Listening...";
            textBox1.Select(0, 0);
        }
    }

    private void onSpeechRecognized(object sender, SpeechRecognizedEventArgs e)
    {
        BeginInvoke(new Action(() => textBox1.Text = e.Result.Text));
    }
    SpeechRecognitionEngine SRE { get; }
}

相关问题