Проблема с замерзанием окна была в том, что считывание файла через new XLWorkbook(xlsxpath) необходимо размещать в DoWork событии.
Следующий нюанс - это считывание прогресса чтения файла, так как я не уверен, что это возможно или же недостаточно компетентен для работы с потоками, то я решил отобразить ProgressBar с бесконечной загрузкой (IsIndeterminate="True", так как мы не знаем сколько времени будет считываться файл).
Весь код я решил вынести в отдельное окно. Получилось следующее, на правильность не претендую:
// ImportWindow.xaml.cs
public partial class ImportWindow : Window
{
XLWorkbook Workbook = new XLWorkbook();
public ImportWindow()
{
InitializeComponent();
}
// Кнопка Обзор, при помощи которой мы выбираем необходимый файл
private void ChooseButton_Click(object sender, RoutedEventArgs e)
{
// Системный диалог для выбора файла
Microsoft.Win32.OpenFileDialog dialog = new Microsoft.Win32.OpenFileDialog
{
// Ограничиваем расширения для выбора
DefaultExt = ".xlsx",
Filter = "Excel Files|*.xls;*.xlsx;*.xlsm"
};
if (dialog.ShowDialog() == true)
{
string path = dialog.FileName;
PathTextBox.Text = path; // Поле ввода для отображения пути файла
// Передаём в конструктор системный путь к файлу
LoadingWindow loadingWindow = new LoadingWindow(path);
// Событие, через которое мы будем получать результат из дочернего окна
loadingWindow.DataChanged += ImportWindow_DataChanged;
// Открываем дочернее окно в модальном режиме
loadingWindow.ShowDialog();
}
}
// Обработка данных полученных из дочернего окна
private void ImportWindow_DataChanged(object sender, XLWorkbook workbook)
{
Workbook = workbook;
// Наполним выпадающий список страницами файла
// В будущем здесь будет ObservableCollection, которую можно забиндить на выпадающий список
PageComboBox.ItemsSource = workbook.Worksheets.ToList();
}
}
//LoadingWindow.xaml.cs
public partial class LoadingWindow : Window
{
BackgroundWorker worker = new BackgroundWorker();
public delegate void DataChangedEventHandler(object sender, XLWorkbook e);
public event DataChangedEventHandler DataChanged;
public LoadingWindow(string filepath)
{
InitializeComponent();
// Здесь мы создаём сам воркер и привязываем к нему события
worker = new BackgroundWorker();
worker.DoWork += DoWork; // событие для чтения файла в асинхронном потоке
worker.RunWorkerCompleted += RunWorkerCompleted; // действия при успешном завершении
worker.RunWorkerAsync(filepath); // Вызов асинхронной функции, нужно передать путь к файлу
}
// Это событие выполняется в отдельном потоке, поэтому у нас есть доступ только к аргументам
void DoWork(object sender, DoWorkEventArgs e)
{
try
{
e.Result = new XLWorkbook((string)e.Argument);
}
catch (Exception ex)
{
e.Result = ex;
}
}
// Здесь мы обрабатываем данные после завершения чтения
private void RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Cancelled)
{
MessageBox.Show("Операция отменена");
}
else if (e.Result is Exception) // Здесь мы ловим ошибки возникшие в процессе чтения
{
Exception ex = e.Result as Exception;
MessageBox.Show(ex.Message);
}
else
{
// Здесь мы вызываем событие родительского окна и передаём в него результат работы
// Результат работы мы кастим к типу XLWorkbook
DataChanged?.Invoke(this, (XLWorkbook)e.Result);
Close();
}
}
}
Возможно это пригодится кому нибудь в будущем