Вывод прогресса асинхронной операции во вторичное окно
Есть метод, загружающий данные из файла. О своём прогрессе он сообщает через вызов события OnFileLoad
public Task UploadDataAsync()
{
return Task.Run(() =>
{
...
if (string.IsNullOrEmpty(FilePath))
{
OnFileLoading?.Invoke($"Error while loading: Path is empty");
...
throw new Exception("Path is emprty");
}
if (!File.Exists(FilePath))
{
OnFileLoading?.Invoke($"Error while loading: File not found");
...
throw new Exception("File not found");
}
OnFileLoading?.Invoke($"Start loading from '{FilePath}'");
...
OnFileLoading?.Invoke("Loaded first line");
OnFileLoading?.Invoke("Loaded second line");
...
OnFileLoading?.Invoke("Loaded n line");
...
OnFileLoading?.Invoke("Loading completed");
});
}
В классе главного окна есть обработчик события нажатия на кнопку "Открыть". В нём создаётся новое окно, в котором показывается прогресс загрузки данных из файла.
public async void OpenFileClick(object sender, RoutedEventArgs e)
{
try
{
var dataProvider = IocContainer.GetService<IDataProvider>();
LoadingDataStatusWindow loadingDataStatusWindow = new LoadingDataStatusWindow();
dataProvider.OnFileLoad = loadingDataStatusWindow.UpdateLoadingStatus;
loadingDataStatusWindow.Show();
dataProvider.FilePath = AppGlobalSettings.DataFilePath;
await dataProvider.UploadDataAsync();
items = dataProvider.CircuitItems;
CircuitItemDataGrid.ItemsSource = dataProvider.CircuitItems;
}
catch(Exception ex)
{
LogUtility.LogError(ex);
}
}
Метод отображения прогресса окна LoadingDataStatusWindow:
public void UpdateLoadingStatus(string currentRow)
{
StatusTextBox.Text += currentRow + Environment.NewLine;
}
При попытке загрузить данные возникает ошибка, говорящая о том, что поток пытается обратиться к объекту, владельцем которого является другой поток.
Я пробовал починить это, сделав добавление текста в StatusTextBox через Dispatcher. Но это не помогло.
Как в данном случае можно организовать вывод прогресса во второе окно с асинхронной загрузкой данных, чтобы она не подвешивала GUI?
Ответы (1 шт):
Как совершенно верно заметил @aepot в комментариях, для сообщения о прогрессе операции используйте Progress<T>, он именно для этого и предназначен, и сам маршаллирует в нужный контекст.
Попробуйте как-то так:
public async void OpenFileClick(object sender, RoutedEventArgs e)
{
// ...
Progress<string> p = new(s => StatusTextBox.Text += s + Environment.NewLine);
await UploadDataAsync(p);
// ...
}
и соответственно
public async Task UploadDataAsync(IProgress<string> progress)
{
// ...
progress.Report($"Start loading from '{filePath}'");
// ...
progress.Report("Loaded first line");
// ...
progress.Report("Loaded second line");
// ...
progress.Report("Loaded n line");
// ...
progress.Report("Loading completed");
// ...
}