Reputation: 3570
Using a library Сatel latest version (3.8.1 beta).
How can I use TAP method from dialog window?
Example. In main ViewModel calling a method
private bool ShowDialogWindow()
{
var typeFactory = TypeFactory.Default ;
var vm = typeFactory.CreateInstanceWithParametersAndAutoCompletion<LoginWindowViewModel>();
return _uiVisualizerService.ShowDialog(vm) ?? false;
}
In LoginWindowViewModel I have Command (also try AsynchronousCommand) which is called method
public async Task<int> Test(string login, string password)
{
var a = await Task<int>.Factory.StartNew(() =>
{
using (var uow = new UnitOfWork<TSDbContext>())
{
var userRep = uow.GetRepository<IUserRepository>();
userRep.GetAll();
return 5;
}
});
a++;
return a;
}
I got the results from awaited method only when close the dialog window. Lock appears on line
var uow = new UnitOfWork()
ConfigureAwait(false) - does not help solve the problem
When I delete UnitOfWork - method works
When I Change Method Code to This var d = TypeFactory.Default.CreateInstanceWithParameters(); return 5;
Blocking is also reproduced on the line TypeFactory...
Depending on the services Catel are not allowed in the dialog box
Upvotes: 2
Views: 1292
Reputation: 5724
Note: I edited this answer so it contains the answer to this question. The previous answer contained some hints for the topic starter to investigate the issue.
You invoke the command in the constructor of the MainViewModel. Note that we never recommend that you invoke anything in the constructor. We have the Initialize method for that.
The reason is that you construct the MainViewModel with the TypeFactory (Catel does that for you). Then in the same (async) command being execution in that thread, you want to instantiate a UnitOfWork which also wants to instantiate a type via the TypeFactory. This is on a different thread. The TypeFactory is still locked because you are still constructoring the MainViewModel.
Again, Catel provides the Initialize method on the ViewModelBase which is called outside of the creation so it is safe to do anything in there. Please use that instead.
Upvotes: 3
Reputation: 61744
I think I know what might be the problem here. If my understanding of the problem is correct, the following code reproduces it:
public partial class MainWindow : Window
{
class Model
{
Model() { }
public Task<int> AsyncTask { get; private set; }
public static Model Create()
{
var model = new Model();
Func<Task<int>> doTaskAsync = async () =>
{
await Task.Delay(1);
return 42;
};
model.AsyncTask = doTaskAsync();
return model;
}
}
public MainWindow()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
var textBlock = new TextBlock();
var window = new Window { Content = textBlock };
window.Loaded += (sIgnore, eIgnore) =>
{
// int result = ((Model)window.DataContext).AsyncTask.Result;
// textBlock.Text = result.ToString();
};
window.DataContext = Model.Create();
window.ShowDialog();
MessageBox.Show("Result: " +
((Model)window.DataContext).AsyncTask.Result);
}
}
Uncomment the commented lines, and there will be a deadlock inside window.Loaded
event handler, at ((Model)window.DataContext).AsyncTask.Result
.
That happens because the window.Loaded
is fired synchronously on the same iteration of the Dispatcher message loop which called ShowDialog
. The AsyncTask
did not have a chance to complete, because the continuation after await Task.Delay(1)
is scheduled on the DispatcherSynchronizationContext
of the UI thread.
The same AsyncTask.Result
code works immediately after ShowDialog
. That's because quite a few more iterations of the message loop have been executed (on the dialog's new Dispatcher frame), before the dialog has been closed.
The fix is simple:
window.Loaded += async (sIgnore, eIgnore) =>
{
int result = await ((Model)window.DataContext).AsyncTask;
textBlock.Text = result.ToString();
};
This will asynchronously complete the task on the dialog's Dispatcher frame.
I'm not sure how close this is to the OP's scenario, because placing await Task.Delay(1).ConfigureAwait(false)
would solve the problem in the above case, as well. Nevertheless, this is as far as I can make guesses based upon the OP's code.
Upvotes: 2