.NET MAUI PopUp CloseAsync() не завершается

Я пытаюсь использовать PopUpService для отображения всплывающего окна, которое, с одной стороны, принимает параметр и возвращает его.

К сожалению, после возвращения всплывающее окно, похоже, не завершает асинхронную задачу, и я не знаю, почему. Я предполагаю, что требуется какой-то CancellationToken.

Вот необходимый код: В одной ViewModel PopUp вызывается:

public partial class SomeViewModel
{
    private readonly IPopupService _popupService;

    // ...

    public SomeViewModel(
        IPopupService popupService)
    {
        _popupService = popupService;
    }
    
    [RelayCommand]
    private async Task OnCallingPopUpAsync()
    {
        var result = await _popupService.ShowPopupAsync<PopupViewModel>(
                onPresenting: viewModel => viewModel.TransferValue(true)
            );
        if (result is bool boolResult)
            Debug.WriteLine("Success!!");
        else
            return;
    }
}

В PopupViewModel получено значение. Кроме того, в представлении можно просто закрыть PopupView, нажав кнопку и вызвав ClosePopupCommand:

public partial class PopupViewModel : Popup
{
    public ImagePickerViewModel() {}

    [RelayCommand]
    private async Task OnClosePopup()
    {
        await CloseAsync(true);
    }

    public void TransferValue(bool value)
    {
        Debug.WriteLine($"The transferred value is {value}");
    }
}

Тем не менее, всплывающее окно не закрывается.

Я попробовал передать CancellationToken (аналогично тому, как это делается в MS Docs, например:

[RelayCommand]
private async Task OnClosePopup()
{
    var cts = new CancellationTokenSource(TimeSpan.FromSeconds(1));
    await CloseAsync(true, token: cts.Token);
}

Однако это привело к исключению: System.Threading.Tasks.TaskCanceledException: 'A task was canceled.'

Как я могу это решить?

Асинхронная передача данных с помощью sendBeacon в JavaScript
Асинхронная передача данных с помощью sendBeacon в JavaScript
В современных веб-приложениях отправка данных из JavaScript на стороне клиента на сервер является распространенной задачей. Одним из популярных...
2
0
120
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Что такое версия dotnet и MAUI и какую платформу iOS или Android вы тестируете?

Ответ принят как подходящий

Шаблон Модель-Представление-ViewModel (MVVM) обеспечивает разделение между тремя уровнями программного обеспечения — пользовательским интерфейсом XAML, называемым представлением, базовыми данными, называемыми моделью, и посредником между представлением и моделью, называемым моделью представления.

Таким образом, использование CloseAsync() во ViewModel не приведет к закрытию всплывающего окна.

Самый простой способ — закрыть всплывающее окно в коде.

Предположим, мы закрываем всплывающее окно при нажатии кнопки,

private async void Button_Clicked(object sender, EventArgs e)
{
    var cts = new CancellationTokenSource(TimeSpan.FromSeconds(1));
    await CloseAsync(true, token: cts.Token);
}

Или, если вы хотите закрыть всплывающее окно во ViewModel, вы можете попробовать передать всплывающее окно через CommandParameter, используя Относительную привязку,

<Button Text = "click me" Command = "{Binding ClosePopupCommand}" CommandParameter = "{Binding Source = {RelativeSource AncestorType = {x:Type toolkit:Popup}}}"/>

и разрешите его и закройте в ViewModel,

    [RelayCommand]
    private void OnClosePopup(object o)
    {
        var cts = new CancellationTokenSource(TimeSpan.FromSeconds(1));
        var p = o as MyPopupPage;

        p.CloseAsync(false, token: cts.Token);
    }

Обновлять

Если относительная привязка не работает, вы также можете попробовать выражение x:Reference Binding.

Установите имя всплывающего окна «это»,

<toolkit:Popup 
...
             x:Name = "this">


...

<Button Text = "click me" Command = "{Binding ClosePopupCommand}" CommandParameter = "{Binding Source = {x:Reference this}}"/>

и передайте всплывающее окно, используя выражение x:Reference Binding, и закройте его в ViewModel,

    [RelayCommand]
    private void OnClosePopup(object o)
    {
        var cts = new CancellationTokenSource(TimeSpan.FromSeconds(1));
        var p = o as MyPopupPage;

        p.CloseAsync(false, token: cts.Token);
    }

Надеюсь, поможет!

Когда я пытаюсь использовать решение ViewModel (которое я предпочитаю), я получаю при вызове p.CloseAsync(false, token: cts.Token)` исключение System.NullReferenceException: 'Object reference not set to an instance of an object.' Знаете, почему?

user25033240 27.05.2024 13:01

Это странно. Это работает на моей стороне. Вы зарегистрировали всплывающее окно и модель представления, builder.Services.AddTransientPopup< MyPopupPage, PopupViewModel >();?

Liqun Shen-MSFT 27.05.2024 14:44

@user25033240 user25033240 Если способы, описанные в моем ответе, не работают, могу ли я узнать, какую версию и платформу .NET вы используете? Кстати, я также обновляю новый способ использования выражения привязки x:Reference.

Liqun Shen-MSFT 29.05.2024 03:24

Да, я зарегистрировал всплывающее окно // Register PupUps builder.Services.AddTransientPopup<ImagePickerView, ImagePickerViewModel>(); для MauiAppBuilder.

user25033240 29.05.2024 11:28

Я нацелен на net8.0-windows10.0.19041.0. Вы это имели в виду?

user25033240 29.05.2024 11:31

Только что протестировал ваше обновление! Привязка x:Refrence работает!! Большое спасибо!

user25033240 29.05.2024 11:34

Другие вопросы по теме