winforms 由于文本框操作,Winform Ui仍然阻塞

nkcskrwz  于 2023-02-19  发布在  其他
关注(0)|答案(2)|浏览(174)

我将建立一个字典。一切都很好。但是有一个小问题。为了停止阻塞我的winform的UI,我在一个线程内运行了我的长代码。正如我所知,当我为一个工作线程给予操作时,UI没有被阻塞。但是当我运行项目时,它仍然阻塞了毫秒。我做了很多事情来找出它。问题是代码有一个文本框

textBox2.Invoke((MethodInvoker)((() => textBox2.Text += aa[i].Trim() + Environment.NewLine + foundwords + Environment.NewLine+ Environment.NewLine)));

如果我运行项目2秒,它会阻塞UI 200ms ...以下是按钮单击事件中的完整代码

private void button1_Click_2(object sender, EventArgs e)
{
    textBox2.Text = "";
    Thread btthread = new Thread(() => {
        foundwords = "";
        string words = "";
        textBox1.Invoke((MethodInvoker)(() =>  words = textBox1.Text));
        string[] aa = words.Trim().Split('\n');

        for (int i = 0; i < aa.Length; i++)
        {
            string authors = DictionaryWords;
            foundwords = "";
            while (authors.Contains("\n"+aa[i].Trim().ToLower()+"\t"))
            {
                int index = authors.IndexOf("\n" + aa[i].Trim().ToLower() + "\t");// find where 1st hello is
                string sub = authors.Substring(index + ("\n" + aa[i].Trim().ToLower() + "\t").Length);// remove all before hello get string we named it sub
                int indexx = sub.IndexOf("\n"); // find \n index
                int final = index + ("\n" + aa[i].Trim().ToLower() + "\t").Length; // find the index after 1st hello
                string substr = authors.Substring(index + ("\n" + aa[i].Trim().ToLower() + "\t").Length, indexx); // select string after hello and before \n
                authors = sub.Substring(indexx);// remove all after
                foundwords += substr.Trim() + " ,";
            }
            textBox2.Invoke((MethodInvoker)((() => textBox2.Text += aa[i].Trim() + Environment.NewLine + foundwords + Environment.NewLine+ Environment.NewLine)));
        }
    });
    btthread.Start();
}

DictionarywWords是一个大文件,它对僧伽罗语有意义我想停止阻止UI。有人能告诉我,我应该怎么做吗?

mzillmmw

mzillmmw1#

忘记线程,拥抱Tasksasyncawait
将长时间运行的代码放在一个额外的方法中,该方法返回稍后用于填充控件的数据。

private WhatEverDataTypeSuitsYou CreateData()
{
    WhatEverDataTypeSuitsYou returnValue;

    // here goes your long running code
    return returnValue;
}

现在你可以让你的click事件处理器异步并等待结果。2因为方法createData在UI线程上返回,所以不需要调用。3你可以简单地用你认为合适的数据填充控件

private async void button1_Click_2(object sender, EventArgs e)
{

    var result = await Task.Run(CreateData);
    // now fill the controls without invoke
}

编辑:实际上,在第二眼看你的代码时,我建议使用StringBuilder而不是连接字符串。这可能是你的代码需要这么多时间的原因。
这句话是邪恶的:

foundwords += substr.Trim() + " ,";
iklwldmw

iklwldmw2#

如果我已经理解了你想做什么,那么我想我已经有了一个解决方案,它将比你的方法运行得快得多。
您正在构建一个在搜索文本DictionaryWords中出现的单词时破坏许多字符串的程序。
我认为DictionaryWords的文件看起来有点像这样:

apple\ta fruit\n
Apple\ta computer\n
Banana\t\a fruit\n
fan\tone who follows a celebrity\n
Fan\ta device that moves air\n

NB:如果你在PC上,那么行尾是\r\n,但是我假设你在Linux上。
处理此数据的更好的数据结构如下所示:

ILookup<string, string> dictionary =
    File
        .ReadLines(@"Path_to_DictionaryWords.txt")
        .Select(x => x.Split('\t'))
        .ToLookup(x => x[0].ToLower(), x => x[1]);

因此,根据我上面的数据,这看起来像:

现在如果你用textBox1我们可以这样做得到一个单词列表:

string[] words =
    textBox1
        .Text
        .ToLower()
        .Split(
            Environment.NewLine,
            StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);

因此,如果用户输入以下内容:

banana
apple

然后你会得到这个

现在,很容易得到匹配的值:

string output =
    String.Join(
        Environment.NewLine + Environment.NewLine,
        from word in words
        where dictionary[word].Any()
        select $"{word}{Environment.NewLine}{String.Join(", ", dictionary[word])}");

这看起来像:

banana
a fruit

apple
a fruit, a computer

该代码的运行速度比您的代码快得多,并且可以一次性生成整个输出。
使用此方法可能不需要任务或线程。
如果你这样做,试试这个:

private async void button1_Click_2(object sender, EventArgs e)
{
    ILookup<string, string> dictionary = await Task.Run(() =>
        File
            .ReadLines(@"Path_to_DictionaryWords.txt")
            .Select(x => x.Split('\t'))
            .ToLookup(x => x[0].ToLower(), x => x[1]));
            
    string[] words =
        textBox1
            .Text
            .ToLower()
            .Split(
                Environment.NewLine,
                StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
    
    string output = await Task.Run(() =>
        String.Join(
            Environment.NewLine + Environment.NewLine,
            words.Select(w => $"{w}{Environment.NewLine}{String.Join(", ", dictionary[w])}")));

    textBox2.Text = output;
}

相关问题