Приложение фризит после подключения DataTable к DataGridView
Мой код ищет файлы по названию в путях и и в таблицу добавляет результат. Для этого я использую Task, но после подключения DataTable к DataGridView, приложение фризит даже в Task'е и перестаёт отвечать хотя до подключения DataTable такого не было.
DataTable dt = new DataTable();
public Main()
{
InitializeComponent();
found_datagridview.DataSource = dt;
dt.Columns.Add("Type");
dt.Columns.Add("Date");
dt.Columns.Add("Size");
dt.Columns.Add("Location");
found_datagridview.Columns[0].Width = 60;
found_datagridview.Columns[1].Width = 141;
found_datagridview.Columns[2].Width = 130;
found_datagridview.Columns[3].Width = 418;
}
async Task FindFiles(CancellationToken ct)
{
await Task.Run(() =>
{
path = path_textbox.Text;
name = name_textbox.Text;
dt.Rows.Clear();
try
{
ct.ThrowIfCancellationRequested();
if (path == "\\\\")
{
int any = 0;
timer.Start();
foreach (DriveInfo drive in DriveInfo.GetDrives())
{
IEnumerable<string> dirs = Directory.EnumerateDirectories(drive.RootDirectory.ToString(), $"*{name}*", new EnumerationOptions { IgnoreInaccessible = true, RecurseSubdirectories = true });
IEnumerable<string> files = Directory.EnumerateFiles(drive.RootDirectory.ToString(), $"*{name}*", new EnumerationOptions { IgnoreInaccessible = true, RecurseSubdirectories = true });
if (dirs.Any() || files.Any())
{
if (dirs.Any())
{
foreach (string dir in dirs)
{
DirectoryInfo info = new DirectoryInfo(dir);
string time = info.CreationTime.ToString("dd.MM.yyyy HH:mm:ss");
string size = Directory.EnumerateFiles(dir, $"*", new EnumerationOptions { IgnoreInaccessible = true, RecurseSubdirectories = true }).Sum(file => new FileInfo(file).Length).ToString("N0");
ct.ThrowIfCancellationRequested();
dt.Rows.Add(new object[] { "<DIR>", time, $"{size} bytes", info.FullName });
}
}
if (files.Any())
{
foreach (string file in files)
{
FileInfo info = new FileInfo(file);
string time = info.CreationTime.ToString("dd.MM.yyyy HH:mm:ss");
string size = info.Length.ToString("N0");
ct.ThrowIfCancellationRequested();
dt.Rows.Add(new object[] { "<FILE>", time, $"{size} bytes", info.FullName });
}
}
any++;
}
else
{
if (any == 0)
{
MessageBox.Show($"No matches found", "Nothing found", MessageBoxButtons.OK, MessageBoxIcon.Information);
break;
}
}
}
timer.Stop();
}
else
{
timer.Start();
IEnumerable<string> dirs = Directory.EnumerateDirectories(path, $"*{name}*", new EnumerationOptions { IgnoreInaccessible = true, RecurseSubdirectories = true });
IEnumerable<string> files = Directory.EnumerateFiles(path, $"*{name}*", new EnumerationOptions { IgnoreInaccessible = true, RecurseSubdirectories = true });
if (dirs.Any() || files.Any())
{
if (dirs.Any())
{
foreach (string dir in dirs)
{
DirectoryInfo info = new DirectoryInfo(dir);
string time = info.CreationTime.ToString("dd.MM.yyyy HH:mm:ss");
string size = Directory.EnumerateFiles(dir, $"*", new EnumerationOptions { IgnoreInaccessible = true, RecurseSubdirectories = true }).Sum(file => new FileInfo(file).Length).ToString("N0");
ct.ThrowIfCancellationRequested();
dt.Rows.Add(new object[] { "<DIR>", time, $"{size} bytes", info.FullName });
}
}
if (files.Any())
{
foreach (string file in files)
{
FileInfo info = new FileInfo(file);
string time = info.CreationTime.ToString("dd.MM.yyyy HH:mm:ss");
string size = info.Length.ToString("N0");
ct.ThrowIfCancellationRequested();
dt.Rows.Add(new object[] { "<FILE>", time, $"{size} bytes", info.FullName });
}
}
}
else
{
MessageBox.Show("No matches found", "Nothing found", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
timer.Stop();
}
}
catch (OperationCanceledException) { }
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}, ct);
}
Ответы (1 шт):
Некоторые участки кода у вас дублируются - их можно вынести в отдельные методы.
Также можно вынести в отдельные методы логически связанные части кода.
Внутри таски оставляем только код перебора директорий и файлов.
Саму задачу оборачиваем в try-catch.
Также выносим лишний код из конструктора формы в событие Load.
Предлагаю посмотреть на такой вариант:
private void Form1_Load(object sender, EventArgs e)
{
dt.Columns.Add("Type");
dt.Columns.Add("Date");
dt.Columns.Add("Size");
dt.Columns.Add("Location");
found_datagridview.DataSource = dt;
SetColumnsSize();
}
private void SetColumnsSize()
{
found_datagridview.Columns[0].Width = 60;
found_datagridview.Columns[1].Width = 141;
found_datagridview.Columns[2].Width = 130;
found_datagridview.Columns[3].Width = 418;
// вместо ручного задания размеров:
//found_datagridview.AutoResizeColumns(DataGridViewAutoSizeColumnsMode.AllCells);
}
async Task FindFiles(CancellationToken ct = default)
{
found_datagridview.DataSource = null;
try
{
await Task.Run(() =>
{
string path = path_textbox.Text;
string name = name_textbox.Text;
dt.Rows.Clear();
if (path == "\\\\")
{
foreach (DriveInfo drive in DriveInfo.GetDrives())
{
FindFiles(drive.RootDirectory.Name, name, ct);
}
}
else
{
FindFiles(path, name, ct);
}
}, ct);
}
catch (OperationCanceledException) { }
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
if (dt.Rows.Count == 0)
{
MessageBox.Show("No matches found", "Nothing found", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
found_datagridview.DataSource = dt;
SetColumnsSize();
}
private void FindFiles(string path, string name, CancellationToken ct = default)
{
var options = new EnumerationOptions { IgnoreInaccessible = true, RecurseSubdirectories = true };
var dirs = Directory.EnumerateDirectories(path, $"*{name}*", options);
var files = Directory.EnumerateFiles(path, $"*{name}*", options);
foreach (string dir in dirs)
{
ct.ThrowIfCancellationRequested();
DirectoryInfo info = new DirectoryInfo(dir);
string time = info.CreationTime.ToString("dd.MM.yyyy HH:mm:ss");
string size = Directory.EnumerateFiles(dir, $"*", options).Sum(file => new FileInfo(file).Length).ToString("N0");
dt.Rows.Add(new object[] { "<DIR>", time, $"{size} bytes", info.FullName });
}
foreach (string file in files)
{
ct.ThrowIfCancellationRequested();
FileInfo info = new FileInfo(file);
string time = info.CreationTime.ToString("dd.MM.yyyy HH:mm:ss");
string size = info.Length.ToString("N0");
dt.Rows.Add(new object[] { "<FILE>", time, $"{size} bytes", info.FullName });
}
}
Проверки dirs.Any(), files.Any() не нужны, т. к. цикл foreach не выполнит ни одной итерации в случае пустых коллекций.
От переменной any тоже можно избавиться, проверяя свойство dt.Rows.Count.
Я явно указываю дефолтный параметр CancellationToken ct = default. Таково требование Framework Design Guidelines.
Вы стартуете и останавливаете какой-то таймер. Я не знаю, что он делает, поэтому просто убрал эти строки. Верните их на место, если необходимо.