I'm trying to build a simple dialog with a loading animation to show while a task is running.
I use the Prism IDialogService
and IEventAggregator
However, I get a System.InvalidOperationException
as the dialog with the animation pops up but never get's closed when the task is finished.
The Exception message is: The calling thread cannot access this object because a different thread owns it.
The dialog can be closed by clicking on it's X Button with no issues.
In non-async situations, I can open and close dialogs as I want, but I can't wrap my head around doing this async.
This is what I came up with so far, leading to the aforementioned Error.
WarehouseViewModel.cs
The Data is loaded and the dialog gets shown.
private async void LoadData()
{
await WarehouseListLoad().ContinueWith(t => { _eventAggregator.GetEvent<LoadingFinishedEvent>().Publish(true); });
}
private async Task WarehouseListLoad()
{
_dialogService.ShowDialog("LoadingDialogView");
List<Warehouse> warehouses = await Task.Run(() =>
{
List<Warehouse> list = _warehouseStore.GetAll();
return list;
});
}
LoadingDialogViewModel.cs
Listen for the LoadingFinishedEvent and invoke RequestClose.
public event Action<IDialogResult> RequestClose;
public LoadingDialogViewModel(IEventAggregator eventAggregator)
{
eventAggregator.GetEvent<LoadingFinishedEvent>().Subscribe(close => CloseDialog(null));
}
protected virtual void CloseDialog(string parameter)
{
RaiseRequestClose(new DialogResult(ButtonResult.None));
}
public virtual void RaiseRequestClose(IDialogResult dialogResult)
{
try
{
RequestClose?.Invoke(dialogResult);
}
catch(System.InvalidOperationException ex)
{
Debug.WriteLine(ex.Message);
//System.InvalidOperationException: The calling thread cannot access this object because a different thread owns it
}
}
CodePudding user response:
You either want to Subscribe
on the UI-Thread
eventAggregator.GetEvent<LoadingFinishedEvent>().Subscribe(close => CloseDialog(null), ThreadOption.UIThread);
or use the Dispatcher
to invoke RequestClose
.
Application.Current.Dispatcher.Invoke( () => RequestClose?.Invoke(dialogresult) );
Or you drop Task.Run
and make GetAll
actually asynchronous...