Edit2: I tracked down the problem to an unrelated issue (the view and the logic were looking at different ViewModel instances. oops.)
I have the following code in a WinUI 3 application, using CommunityToolkit.MVVM, trying to use TaskCompletionSource with RelayCommand to control application flow around user input. It's working in one spot, and not in another. I cannot for the life of me tell what I'm doing differently in the second that would cause it to fail like this.
Edit: Following up on Andrew's answer, I've discovered it works fine if I call the Next method from code, rather than from the UI (using the generated NextCommand.) I still don't know why it works for the first one and not the second. I've tried using both ConfigureAwait(false) and TaskCreationOptions.RunContinuationsAsynchronously, to no avail.
//App.xaml.cs
protected override void OnLaunched(Microsoft.UI.Xaml.LaunchActivatedEventArgs args)
{
m_window = new MainWindow();
m_window.Activate();
_ = RunGame();
}
private async Task RunGame()
{
// ... create start view ...
var settings = await startView.ViewModel.WaitForStartAsync(); //This works
// ... create first game step ...
await currentStep.WaitForNextAsync(); //This doesn't
Exit(); //never called
}
//StartViewModel.cs
public partial class StartViewModel : ObservableObject
{
//settings logic
private readonly TaskCompletionSource<GameSettings> m_taskCompletionSource = new();
[RelayCommand]
private void Start() => m_taskCompletionSource.TrySetResult(new(Difficulty));
public Task<GameSettings> WaitForStartAsync() => m_taskCompletionSource.Task;
}
//GameStepViewModel.cs
public abstract partial class GameStepViewModel : ObservableObject
{
[ObservableProperty, NotifyCanExecuteChangedFor("NextCommand")]
private bool m_nextEnabled = true;
private readonly TaskCompletionSource _tcs = new();
[RelayCommand(CanExecute = "NextEnabled")]
private void Next() => _tcs.TrySetResult();
public Task WaitForNextAsync() => _tcs.Task;
}
edit: I know from debugging that the Next() method is being called successfully and the TaskCompletionSource.Task is transitioning to RanToCompletion.
This is the code that worked (Exit() called after Next() is called) for me.
App.xaml.cs