I'm get an issue using the Template 10 Hamburger Template and Zxing.mobile.net library "Template10": "1.1.12", "ZXing.Net.Mobile": "2.1.46"
if I add the following code to the Mainpage and Viewmodel, the scanner works correctly and binds the value back to the TextBox but if I add the same code to the details page the returned code wont bind.I'm doing anything wrong.
Mainpage.xaml
<Page x:Class="WindowsApp3.Views.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:Behaviors="using:Template10.Behaviors"
xmlns:Core="using:Microsoft.Xaml.Interactions.Core"
xmlns:Interactivity="using:Microsoft.Xaml.Interactivity"
xmlns:controls="using:Template10.Controls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="using:WindowsApp3.Views"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:vm="using:WindowsApp3.ViewModels"
mc:Ignorable="d">
<Page.DataContext>
<vm:MainPageViewModel x:Name="ViewModel" />
</Page.DataContext>
<RelativePanel Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="AdaptiveVisualStateGroup">
<VisualState x:Name="VisualStateNarrow">
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="{StaticResource NarrowMinWidth}" />
</VisualState.StateTriggers>
<VisualState.Setters>
<!-- TODO: change properties for narrow view -->
<Setter Target="stateTextBox.Text" Value="Narrow Visual State" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="VisualStateNormal">
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="{StaticResource NormalMinWidth}" />
</VisualState.StateTriggers>
<VisualState.Setters>
<!-- TODO: change properties for normal view -->
<Setter Target="stateTextBox.Text" Value="Normal Visual State" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="VisualStateWide">
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="{StaticResource WideMinWidth}" />
</VisualState.StateTriggers>
<VisualState.Setters>
<!-- TODO: change properties for wide view -->
<Setter Target="stateTextBox.Text" Value="Wide Visual State" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<controls:PageHeader x:Name="pageHeader"
RelativePanel.AlignLeftWithPanel="True"
RelativePanel.AlignRightWithPanel="True"
RelativePanel.AlignTopWithPanel="True"
Text="Main Page">
<!-- secondary commands -->
<controls:PageHeader.SecondaryCommands>
<AppBarButton Click="{x:Bind ViewModel.GotoSettings}" Label="Settings" />
<AppBarButton Click="{x:Bind ViewModel.GotoPrivacy}" Label="Privacy" />
<AppBarButton Click="{x:Bind ViewModel.GotoAbout}" Label="About" />
</controls:PageHeader.SecondaryCommands>
</controls:PageHeader>
<RelativePanel EntranceNavigationTransitionInfo.IsTargetElement="True"
RelativePanel.AlignBottomWithPanel="True"
RelativePanel.AlignLeftWithPanel="True"
RelativePanel.AlignRightWithPanel="True"
RelativePanel.Below="pageHeader">
<controls:Resizer x:Name="parameterResizer" Margin="16,16,16,0">
<TextBox MinWidth="150"
MinHeight="62"
Header="Parameter to pass"
Text="{Binding Value, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
TextWrapping="Wrap">
<Interactivity:Interaction.Behaviors>
<!-- enable submit on enter key -->
<Behaviors:KeyBehavior Key="Enter">
<Core:CallMethodAction MethodName="GotoDetailsPage" TargetObject="{Binding}" />
</Behaviors:KeyBehavior>
<!-- focus on textbox when page loads -->
<Core:EventTriggerBehavior>
<Behaviors:FocusAction />
</Core:EventTriggerBehavior>
</Interactivity:Interaction.Behaviors>
</TextBox>
</controls:Resizer>
<Button x:Name="submitButton"
Click="{x:Bind ViewModel.GotoDetailsPage}"
Content="Submit"
RelativePanel.AlignBottomWith="parameterResizer"
RelativePanel.RightOf="parameterResizer" />
<TextBlock x:Name="stateTextBox"
Margin="16,16,0,0"
RelativePanel.AlignLeftWith="parameterResizer"
RelativePanel.Below="parameterResizer"
Text="Current Visual State" />
<!-- content -->
<!-- content -->
<Button x:Name="loadButton"
HorizontalAlignment="Center"
Width="180"
Height="50"
RelativePanel.Below="stateTextBox"
Click="{x:Bind ViewModel.QRCodeCick}">
<StackPanel Orientation="Horizontal">
<SymbolIcon Width="48"
VerticalAlignment="Center"
Height="48"
Symbol="Camera" />
<TextBlock Margin="12,0,0,0"
VerticalAlignment="Center"
Text="Read QR Code" />
</StackPanel>
</Button>
<TextBox x:Name="QRTextBox"
PlaceholderText="Enter Code"
Text="{x:Bind ViewModel.QRText,Mode=TwoWay}"
RelativePanel.Below="loadButton"
Margin="0,0,0,12"/>
</RelativePanel>
</RelativePanel>
</Page>
MainPage.xaml.cs
using System;
using WindowsApp3.ViewModels;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Navigation;
using System.Collections.ObjectModel;
namespace WindowsApp3.Views
{
public sealed partial class MainPage : Page
{
public MainPage()
{
InitializeComponent();
NavigationCacheMode = Windows.UI.Xaml.Navigation.NavigationCacheMode.Enabled;
}
}
}
MagePageViewModel.cs
using Template10.Mvvm;
using System.Collections.Generic;
using System;
using System.Linq;
using System.Threading.Tasks;
using Template10.Services.NavigationService;
using Windows.UI.Xaml.Navigation;
using ZXing.Mobile;
namespace WindowsApp3.ViewModels
{
public class MainPageViewModel : ViewModelBase
{
MobileBarcodeScanner scanner;
public MainPageViewModel()
{
if (Windows.ApplicationModel.DesignMode.DesignModeEnabled)
{
Value = "Designtime value";
}
//Create a new instance of our scanner
scanner = new MobileBarcodeScanner();
// this.Dispatcher
// scanner.Dispatcher = this.Dispatcher;
}
string _Value = "Gas";
public string Value { get { return _Value; } set { Set(ref _Value, value); } }
public override async Task OnNavigatedToAsync(object parameter, NavigationMode mode, IDictionary<string, object> suspensionState)
{
if (suspensionState.Any())
{
Value = suspensionState[nameof(Value)]?.ToString();
}
await Task.CompletedTask;
}
public override async Task OnNavigatedFromAsync(IDictionary<string, object> suspensionState, bool suspending)
{
if (suspending)
{
suspensionState[nameof(Value)] = Value;
}
await Task.CompletedTask;
}
public override async Task OnNavigatingFromAsync(NavigatingEventArgs args)
{
args.Cancel = false;
await Task.CompletedTask;
}
public void GotoDetailsPage() =>
NavigationService.Navigate(typeof(Views.DetailPage), Value);
public void GotoSettings() =>
NavigationService.Navigate(typeof(Views.SettingsPage), 0);
public void GotoPrivacy() =>
NavigationService.Navigate(typeof(Views.SettingsPage), 1);
public void GotoAbout() =>
NavigationService.Navigate(typeof(Views.SettingsPage), 2);
public async void QRCodeCick()
{
scanner.UseCustomOverlay = false;
scanner.TopText = "Hold camera up to barcode";
scanner.BottomText = "Camera will automatically scan barcode\r\n\r\nPress the 'Back' button to Cancel";
//Start scanning
var result = await scanner.Scan();
if (result != null)
_QRText = result.Text;
}
string _QRText;
public string QRText { get { return _QRText; } set { Set(ref _QRText, value); } }
}
}
Details.xaml
<Page x:Class="WindowsApp3.Views.DetailPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:Behaviors="using:Template10.Behaviors"
xmlns:Core="using:Microsoft.Xaml.Interactions.Core"
xmlns:Interactivity="using:Microsoft.Xaml.Interactivity"
xmlns:controls="using:Template10.Controls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="using:WindowsApp3.Views"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:vm="using:WindowsApp3.ViewModels"
x:Name="ThisPage"
mc:Ignorable="d">
<Page.DataContext>
<vm:DetailPageViewModel x:Name="ViewModel" />
</Page.DataContext>
<RelativePanel Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="AdaptiveVisualStateGroup">
<VisualState x:Name="VisualStateNarrow">
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="{StaticResource NarrowMinWidth}" />
</VisualState.StateTriggers>
<VisualState.Setters>
<!-- TODO: change properties for narrow view -->
</VisualState.Setters>
</VisualState>
<VisualState x:Name="VisualStateNormal">
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="{StaticResource NormalMinWidth}" />
</VisualState.StateTriggers>
<VisualState.Setters>
<!-- TODO: change properties for normal view -->
</VisualState.Setters>
</VisualState>
<VisualState x:Name="VisualStateWide">
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="{StaticResource WideMinWidth}" />
</VisualState.StateTriggers>
<VisualState.Setters>
<!-- TODO: change properties for wide view -->
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<!-- header -->
<controls:PageHeader x:Name="pageHeader"
Frame="{x:Bind Frame}"
RelativePanel.AlignLeftWithPanel="True"
RelativePanel.AlignRightWithPanel="True"
RelativePanel.AlignTopWithPanel="True"
Text="Detail Page" />
<!-- content -->
<ScrollViewer EntranceNavigationTransitionInfo.IsTargetElement="True"
Padding="12,8,0,0"
RelativePanel.AlignBottomWithPanel="True"
RelativePanel.AlignLeftWithPanel="True"
RelativePanel.AlignRightWithPanel="True"
RelativePanel.Below="pageHeader"
VerticalScrollBarVisibility="Auto">
<StackPanel>
<TextBlock Style="{StaticResource TitleTextBlockStyle}" Text="You passed:" />
<TextBlock Style="{StaticResource SubtitleTextBlockStyle}" Text="{x:Bind ViewModel.Value, Mode=OneWay, FallbackValue=DesigntimeValue}" />
<Button x:Name="loadButton"
HorizontalAlignment="Center"
Width="180"
Height="50"
Click="{x:Bind ViewModel.QRCodeCick}">
<StackPanel Orientation="Horizontal">
<SymbolIcon Width="48"
VerticalAlignment="Center"
Height="48"
Symbol="Camera" />
<TextBlock Margin="12,0,0,0"
VerticalAlignment="Center"
Text="Read QR Code" />
</StackPanel>
</Button>
<TextBox x:Name="QRTextBox"
PlaceholderText="Enter Code"
Text="{x:Bind ViewModel.QRText,Mode=TwoWay}"
Margin="0,0,0,12"/>
</StackPanel>
</ScrollViewer>
</RelativePanel>
</Page>
DesignPage.xaml.cs
using WindowsApp3.ViewModels;
using Windows.UI.Xaml.Navigation;
using Windows.UI.Xaml.Controls;
namespace WindowsApp3.Views
{
public sealed partial class DetailPage : Page
{
public DetailPage()
{
InitializeComponent();
NavigationCacheMode = NavigationCacheMode.Disabled;
}
}
}
DesignViewModel.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Template10.Common;
using Template10.Mvvm;
using Template10.Services.NavigationService;
using Windows.UI.Xaml.Navigation;
using ZXing.Mobile;
namespace WindowsApp3.ViewModels
{
public class DetailPageViewModel : ViewModelBase
{
MobileBarcodeScanner scanner;
public DetailPageViewModel()
{
if (Windows.ApplicationModel.DesignMode.DesignModeEnabled)
{
Value = "Designtime value";
}
//Create a new instance of our scanner
scanner = new MobileBarcodeScanner();
// this.Dispatcher
// scanner.Dispatcher = this.Dispatcher;
}
private string _Value = "Default";
public string Value { get { return _Value; } set { Set(ref _Value, value); } }
public override async Task OnNavigatedToAsync(object parameter, NavigationMode mode, IDictionary<string, object> suspensionState)
{
Value = (suspensionState.ContainsKey(nameof(Value))) ? suspensionState[nameof(Value)]?.ToString() : parameter?.ToString();
await Task.CompletedTask;
}
public override async Task OnNavigatedFromAsync(IDictionary<string, object> suspensionState, bool suspending)
{
if (suspending)
{
suspensionState[nameof(Value)] = Value;
}
await Task.CompletedTask;
}
public override async Task OnNavigatingFromAsync(NavigatingEventArgs args)
{
args.Cancel = false;
await Task.CompletedTask;
}
public async void QRCodeCick()
{
scanner.UseCustomOverlay = false;
scanner.TopText = "Hold camera up to barcode";
scanner.BottomText = "Camera will automatically scan barcode\r\n\r\nPress the 'Back' button to Cancel";
//Start scanning
var result = await scanner.Scan();
if (result != null)
_QRText = result.Text;
}
string _QRText;
public string QRText { get { return _QRText; } set { Set(ref _QRText, value); } }
}
}
I see two issues with your code:
1.) The _QRText = result.Text
does not fire the PropertyChange for the binding.
2.) The main difference is in the pages' NavigationCacheMode
property. You are using NavigationCacheMode.Enabled
on MainPage
and NavigationCacheMode.Disabled
for DesignPage
.
In the background the ZXing do a page navigation then a back navigation, so when it navigate back to the MainPage
it uses the cached version so the ViewModel is cached too.
But in the DesignPage
the caching is disabled so the back navigation creates a new page and view model instance so the following code is called in the old view model and not in the new one.
//Start scanning
var result = await scanner.Scan();
if (result != null)
_QRText = result.Text;
So you need to set the NavigationCacheMode
property of the page to NavigationCacheMode.Required
where you start the QR Code scanning.