I have a UWP project and I want to message passing between ViewModel
and View
with CommunityToolkit MVVM Toolkit.
As you can see in my ViewModel
we have something like below
private async void CallbackClick()
{
while (true)
{
CallbackDto callback = callbackQueue.Pop();
if (callback is null)
break;
callbackQueue.Push(new CallbackDto(callback.Number, DateTimeOffset.UtcNow.ToUnixTimeSeconds()));
string normalizedAddress = callback.Number;
BSN.LinphoneSDK.Call outgoingCall = await LinphoneManager.Instance.NewOutgoingCall($"{normalizedAddress}");
await outgoingCall.WhenEnded();
// TODO: It is mandatory for backing to Dialer from InCall, but it is very bugous and must fix it
await Task.Delay(1000);
Task<CancellationToken> cancellationTokenTask = WeakReferenceMessenger.Default.Send<ContinueCallbackAnsweringRequestMessage>();
CancellationToken cancellationToken = await cancellationTokenTask;
if (cancellationToken.IsCancellationRequested)
break;
}
}
And I have register on message in Dialer.xaml.cs
in NavigatedTo
like below
WeakReferenceMessenger.Default.Register<ContinueCallbackAnsweringRequestMessage>(this, async (r, message) =>
{
var continueCallbackAnsweringDialog = new MessageDialog("آیا مایل به ادامه پاسخدهی به تماسهای درخواستی هستید؟");
TaskCompletionSource<CancellationToken> tcs = new TaskCompletionSource<CancellationToken>(TaskCreationOptions.RunContinuationsAsynchronously);
continueCallbackAnsweringDialog.Commands.Add(new UICommand(
"بلی",
new UICommandInvokedHandler((IUICommand command) =>
{
tcs.SetResult(new CancellationToken(false));
})));
continueCallbackAnsweringDialog.Commands.Add(new UICommand(
"خیر",
new UICommandInvokedHandler((IUICommand command) =>
{
tcs.SetResult(new CancellationToken(true));
})));
continueCallbackAnsweringDialog.DefaultCommandIndex = 0;
continueCallbackAnsweringDialog.CancelCommandIndex = 1;
await continueCallbackAnsweringDialog.ShowAsync();
message.Reply(tcs.Task);
});
In this scenario I got a InvalidOperationException
on WeakReferenceMessenger.Default.Send
. My question is how to handle this situation?
In another side, if I remove async
and await
keyword in handler, my code is work correctly. but the problem is I do not await on IAsyncOperation
and I want to await
on in it.
I add discussion on CommunityToolkit GitHub about that.
My question is how to handle this situation?
Since the MessageHandler
won't (can't) be awaited by the toolkit, it returns when you call await ...
.
You could try something like this:
WeakReferenceMessenger.Default.Register<ContinueCallbackAnsweringRequestMessage>(
this, (r, m) => m.Reply(ShowDialogAndWaitForResult()));
...where ShowDialogAndWaitForResult()
is a custom async
method that returns a Task<T>
, calls the ShowAsync()
of the dialog and wait for the result.
Another option is implement your own blocking (non-async) dialog. Or consider another solution which don't involve a messenger.