返回 UWP XAML 页面后 ContentDialog.RunAsync() 导致 'Value does not fall within the expected range.'

After returning to a UWP XAML page ContentDialog.RunAsync() causes 'Value does not fall within the expected range.'

使用 UWP 和 MVVM Light,我有一个程序使用不同的数据多次使用相同的页面和 ViewModel。每个 page/ViewModel 对都分配了一个匹配的 ID,因此它们可以更轻松地相互引用。页面上有一个显示 ContentDialog 的按钮。

第一次打开其中一个页面时,ContentDialog 正常打开,但如果页面离开然后返回,为 ContentDialog 调用 ShowAsync 会导致非常具有描述性的 ArgumentException:'Value does not fall within the expected range.'

视图模型

public RelayCommand LockButtonCommand => new RelayCommand(() => lockButtonClicked());

private void lockButtonClicked()
{
    System.Diagnostics.Debug.WriteLine("Button clicked on VM " + myID);
    Messenger.Default.Send(new ShowPassphraseDialogMessage(), myID);
}

页面代码隐藏

protected override void OnNavigatedTo(NavigationEventArgs e)
{
    if (!idsRegistered.Contains(myID))
    {
        Messenger.Default.Register<ShowPassphraseDialogMessage>(this, myID, showDiag);

        System.Diagnostics.Debug.WriteLine("Registered messages for " + myID);

        idsRegistered.Add(myID);
    }
}

private async void showDiag(object msg)
{
    System.Diagnostics.Debug.WriteLine("Showing dialog for " + myID);
    if (activePageID != myID)
        return;
    await PassphraseDialog.ShowAsync();
}

内容对话框XAML

<ContentDialog x:Name="PassphraseDialog"
                       x:Uid="Page_PassDialog"
                       PrimaryButtonText="Enter"
                       SecondaryButtonText="Cancel"
                       PrimaryButtonCommand="{x:Bind ViewModel.PassDialogEnterCommand}"
                       Closing="PassphraseDialog_Closing">
    <StackPanel>
        <TextBlock x:Uid="Page_PassDialogText" />
        <StackPanel Orientation="Horizontal" VerticalAlignment="Center">
            <PasswordBox x:Name="PassphraseDialogInput"
                         Password="{x:Bind ViewModel.PassDialogInputText, Mode=TwoWay}"
                         helper:EnterKeyHelpers.EnterKeyCommand="{x:Bind ViewModel.PassDialogEnterCommand}" />
            <ProgressRing Margin="8,0,0,12"
                                  IsActive="{x:Bind ViewModel.PassDialogLoading, Mode=OneWay}" />
        </StackPanel>
        <TextBlock Text="{x:Bind ViewModel.PassDialogErrorText, Mode=OneWay}"
                   Foreground="{ThemeResource SystemErrorTextColor}"/>
    </StackPanel>
</ContentDialog>

我首先担心的是在我的设置中不知何故多次调用了 showDiag 方法。所以我做了几个测试来了解以下内容:

  1. 正在为代码隐藏中的每个 ID 注册一次消息。
  2. 消息发送一次。
  3. showDiag 被调用一次。

我不确定这是否相关,但我发现使用此设置,每次导航到该页面时都会调用页面构造函数。

当您需要多次使用同一个页面时,请缓存该页面。

试试这个:

private bool _isInit = false;
public MyPage()
{
    this.InitializeComponent();
    NavigationCacheMode = NavigationCacheMode.Enabled;
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
    if (e.NavigationMode == NavigationMode.Back || _isInit)
        return;

    // Do Somethings...

    _isInit = true;
}

缓存页面时,它会保持页面的当前状态,这意味着两件事:

  1. 您创建的ContentDialog不会被新建页面的ContentDialog替换,导致出错
  2. 页面离开和返回时,不会重复创建页面

此致。