Зависает вся форма кроме listbox
Использовал async. Виснет всё, кроме listbox, кнопки не нажимаются. Посидел подумал и пришёл к выводу - форма зависает при обработке pdf и docx файлов.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO;
using System.Threading;
using System.Diagnostics;
using TikaOnDotNet.TextExtraction;
namespace diplom
{
public partial class Form1 : Form
{
public string target_word;
public Form1()
{
InitializeComponent();
}
public void listBox1_SelectedIndexChanged(object sender, EventArgs e)
{
}
public void button1_Click(object sender, EventArgs e)
{
FolderBrowserDialog q=new FolderBrowserDialog();
if(q.ShowDialog() == DialogResult.OK)
{
textBox1.Text = q.SelectedPath;
}
}
public void button2_Click(object sender, EventArgs e)
{
if (Directory.Exists(textBox1.Text)==false)
{
MessageBox.Show("Директория не найдена","Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
else
{
on_click_search(textBox1.Text);
}
}
void on_click_search(string directory)
{
listBox1.Items.Clear();
string[] alltxt = Directory.GetFiles(directory, "*.txt", SearchOption.AllDirectories);
string[] allpdf = Directory.GetFiles(directory, "*.pdf", SearchOption.AllDirectories);
string[] alldocx = Directory.GetFiles(directory, "*.docx", SearchOption.AllDirectories);
if (alltxt.Length + allpdf.Length + alldocx.Length== 0)
{
MessageBox.Show("Совпадений нет", "Результат поиска файлов", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
else
{
if (alltxt.Length != 0)
{
'search_txt(alltxt);'
}
if (allpdf.Length != 0)
{
'search_pdf(allpdf);'
}
if (alldocx.Length != 0)
{
'search_docx(alldocx);'
}
}
}
private void Form1_Load(object sender, EventArgs e)
{
textBox1.Text=Directory.GetCurrentDirectory();
}
async void search_txt(string[] alltxt)
{
target_word = textBox2.Text;
target_word=target_word.ToLower();
await Task.Run(() => { Action ac = () => {
foreach (string file in alltxt)
{
using (StreamReader sr = new StreamReader(file, Encoding.UTF8))
{
string str = sr.ReadToEnd();
string str1 = str.ToLower();
bool b = str1.Contains(target_word);
if (b == true)
{
listBox1.Items.Add(file);
}
}
}
}; if (InvokeRequired) Invoke(ac); else ac(); });
}
private void listBox1_DoubleClick(object sender, EventArgs e)
{
try
{
string str = listBox1.SelectedItem.ToString();
Process.Start(str);
listBox1.SetSelected(listBox1.SelectedIndex, false);
}
catch
{
}
}
async void search_pdf(string[] allpdf)
{
target_word = textBox2.Text;
target_word = target_word.ToLower();
SautinSoft.PdfFocus f = new SautinSoft.PdfFocus();
await Task.Run(() => { Action ac = () => {
foreach (string file in allpdf)
{
f.OpenPdf(file);
string str = f.ToText();
string str1 = str.ToLower();
bool b = str1.Contains(target_word);
if (b == true)
{
listBox1.Items.Add(file);
}
}
}; if (InvokeRequired) Invoke(ac); else ac(); });
}
async void search_docx(string[] alldocx)
{
target_word = textBox2.Text;
target_word = target_word.ToLower();
var textExtractor = new TextExtractor();
await Task.Run(() => { Action ac = () => {
foreach (string file in alldocx)
{
string text = textExtractor.Extract(file).Text;
text = text.ToLower();
bool b = text.Contains(target_word);
if (b == true)
{
listBox1.Items.Add(file);
}
}
}; if (InvokeRequired) Invoke(ac); else ac(); });
}
private void button3_Click(object sender, EventArgs e)
{
}
}
}
Ответы (1 шт):
async void search_pdf(string[] allpdf)
Никаких async void! Это только для событий, таких как button1_Click. Обычные функции должны быть типа Task:
async Task search_pdf(string[] allpdf)
search_pdf(allpdf);
А где await соответственно? Должно быть так:
await search_pdf(allpdf);
И Invoke тоже не нужен, насколько я понимаю вот этот:
if (InvokeRequired) Invoke(ac); else ac();
Продолжение асинхронной задачи по умолчанию делается в том же потоке, у вас и так всё происходит в потоке GUI. Хотя тут могу всех тонкостей не знать.
Есть и ещё проблемы в коде, но нужно начать с базовых вещей каких-то.
Примерно так это должно выглядеть, здесь только методы, которые я изменил.
private async void button2_Click(object sender, EventArgs e)
{
if (!Directory.Exists(textBox1.Text))
{
MessageBox.Show("Директория не найдена", "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
else
{
await OnClickSearch(textBox1.Text);
MessageBox.Show("Поиск завершен", "Готово");
}
}
private async Task OnClickSearch(string directory)
{
listBox1.Items.Clear();
string[] alltxt = Directory.GetFiles(directory, "*.txt", SearchOption.AllDirectories);
string[] allpdf = Directory.GetFiles(directory, "*.pdf", SearchOption.AllDirectories);
string[] alldocx = Directory.GetFiles(directory, "*.docx", SearchOption.AllDirectories);
if (alltxt.Length + allpdf.Length + alldocx.Length == 0)
{
MessageBox.Show("Совпадений нет", "Результат поиска файлов", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
else
{
if (alltxt.Length != 0)
{
await SearchTxt(alltxt);
}
if (allpdf.Length != 0)
{
await SearchPdf(allpdf);
}
if (alldocx.Length != 0)
{
await SearchDocx(alldocx);
}
}
}
private void listBox1_DoubleClick(object sender, EventArgs e)
{
try
{
string str = listBox1.SelectedItem.ToString();
Process.Start(new ProcessStartInfo(str) { UseShellExecute = true });
listBox1.SetSelected(listBox1.SelectedIndex, false); // зачем? чтобы я забыл, какой файл я выбирал?
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, ex.GetType().Name);
}
}
private async Task SearchTxt(string[] alltxt)
{
string target_word = textBox2.Text;
foreach (string file in alltxt)
{
using (StreamReader sr = new StreamReader(file))
{
while (!sr.EndOfStream)
{
string str = await sr.ReadLineAsync();
if (str.Contains(target_word, StringComparison.CurrentCultureIgnoreCase))
{
listBox1.Items.Add(file);
break;
}
}
}
}
}
private Task SearchPdf(string[] allpdf)
{
string target_word = textBox2.Text;
return Task.Run(() =>
{
SautinSoft.PdfFocus f = new SautinSoft.PdfFocus();
foreach (string file in allpdf)
{
f.OpenPdf(file);
string str = f.ToText();
if (str.Contains(target_word, StringComparison.CurrentCultureIgnoreCase))
{
Invoke(() => listBox1.Items.Add(file));
}
}
});
}
private Task SearchDocx(string[] alldocx)
{
string target_word = textBox2.Text;
return Task.Run(() =>
{
var textExtractor = new TextExtractor();
foreach (string file in alldocx)
{
string str = textExtractor.Extract(file).Text;
if (str.Contains(target_word, StringComparison.CurrentCultureIgnoreCase))
{
Invoke(() => listBox1.Items.Add(file));
}
}
});
}
Стоит еще проверить на использование IDisposable (документация), так как механизмы работы TextExtractor и SautinSoft.PdfFocus мне не известны, я не уверен, будет ли оно своевременно закрывать файлы.