Using UWP and MVVM Light, I have a program that uses the same page and ViewModel multiple times with different data. Each page/ViewModel pair is assigned a matching ID so they can more easily reference each other. On the page is a button that shows a ContentDialog.
When opening one of the pages for the first time, the ContentDialog opens properly, but if the page is left and then returned to, calling ShowAsync for ContentDialog causes the very descriptive ArgumentException: 'Value does not fall within the expected range.'
ViewModel
public RelayCommand LockButtonCommand => new RelayCommand(() => lockButtonClicked());
private void lockButtonClicked()
{
System.Diagnostics.Debug.WriteLine("Button clicked on VM " + myID);
Messenger.Default.Send(new ShowPassphraseDialogMessage(), myID);
}
Page Code-Behind
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();
}
ContentDialog 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>
My first concern has been that somehow in my setup the showDiag method was being called multiple times. So I've done several tests to know the following:
I'm not sure if this is related, but I found that with this setup the page constructor is being called every time that page is navigated to.
When you need to use the same page multiple times, please cache the page.
Try this:
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;
}
When the page is cached, it maintains the current state of the page, which means two things:
ContentDialog
you create will not be replaced by the ContentDialog
of the newly created page, resulting in an error.Best regards.