Search code examples
uwpzxingtemplate10

Template10 ZXing Frames and Navigation


I've started using Template10 and are trying to put a ZXing Barcode scanner in the application. But I'm having some issues with the way ZXing and Template10 works togehter.

When I initiate the ZXing scanner it seems to write over all current frames and content with its own layout. So when I initiate the cancel action, there is nothing left to go back to.

The frame is always at the page that initiated it, so Template10 does not understand that anything is happening.

My code:

public async Task ScanQR()
{
    try
    {
        var scanner = new ZXing.Mobile.MobileBarcodeScanner();

        var _overlay = new Views.Scanner();
        _overlay._cancel.Click += (object sender, RoutedEventArgs e) => { scanner.Cancel(); };
        _overlay._torch.Click += (object sender, RoutedEventArgs e) => { scanner.ToggleTorch(); };

        scanner.CustomOverlay = _overlay;
        scanner.UseCustomOverlay = true;

        var result = await scanner.Scan();
        if (result != null)
        {
             // Handle Result
        }
    }
}

As you can see on the snapshots (1)(2) the stacked panels on the application are overwritten. As you can see it replaces the ones from [Frame]->[ContentPresenter] and inwards.

How can I make the code go back to the previous page when canceled? I understand that I probably need to capsulate this somehow, but I can't find anything about it. Been searching around to find anyone with a similar issue. So I turn to you guys.

(1). Before ZXing.Scan()

(2). After ZXing.Scan()

--- Addition Information ---

The solution to this problem on a normal application not using Template10 was to handle the back requests with the following code. This was something I found on a forum somewhere, can't remember the source now.

If this code was not present the application would just close when you press the hardware back button on a phone. When I try the Template10 project on a phone it does the same thing. On a PC you don't get a back button.

    protected override void OnNavigatedTo(NavigationEventArgs e)
    {
        base.OnNavigatedTo(e);

        var currentView = SystemNavigationManager.GetForCurrentView();
        if (!ApiInformation.IsTypePresent("Windows.Phone.UI.Input.HardwareButtons"))
        {
            currentView.AppViewBackButtonVisibility = this.Frame.CanGoBack ?
                AppViewBackButtonVisibility.Visible : AppViewBackButtonVisibility.Collapsed;
        }
        currentView.BackRequested += SystemNavigationManager_BackRequested;
    }

    private void SystemNavigationManager_BackRequested(object sender, BackRequestedEventArgs e)
    {
        if (this.Frame.CanGoBack)
        {
            this.Frame.GoBack();
            e.Handled = true;
        }
    }

Solution

  • When I initiate the ZXing scanner it seems to write over all current frames and content with its own layout. So when I initiate the cancel action, there is nothing left to go back to.

    From your pictures I think you are using Template 10 Hamburger to build your app. Then the Xaml tree is like this: Window.Current.Content -> Shell -> SplitView -> Frame -> MainPage.

    Just read the source code of Zxing MobileBarcodeScanner, when create a new instance of Scanner, it will navigate from the rootFrame of the app to the Scanner/ CustomerScanner page, this is why your "Shell" is gone after Zxing.Scan(). So basically, if you need to cancel the operation/ navigate back to the last page, you can use the rootFrame.GoBack(); to go back.

    Only the problem is, the rootFrame.CanGoBack is false. If you look at the code in the App.xaml.cs, in the task OnInitializeAsync, it set the "Shell" page as content of the Window.Current.Content, it doesn't use the Frame.Navigate method to navigate to the page, to make the rootFrame.CanGoBack to be true, we can manually add Shell page to Backstack like this:

    if (Window.Current.Content as ModalDialog == null)
    {
        // create a new frame
        var nav = NavigationServiceFactory(BackButton.Attach, ExistingContent.Include);
        // create modal root
        Window.Current.Content = new ModalDialog
        {
            DisableBackButtonWhenModal = true,
            Content = new Views.Shell(nav),
            ModalContent = new Views.Busy(),
        };
        var rootFrame = Window.Current.Content as Frame;
        rootFrame.BackStack.Add(new Windows.UI.Xaml.Navigation.PageStackEntry(typeof(Views.Shell), null, null));
    }
    

    Then in the Cancel method of your Scanner page:

    var rootFrame = RootFrame ?? Window.Current.Content as Frame ?? ((FrameworkElement)Window.Current.Content).GetFirstChildOfType<Frame>();
    if (rootFrame.CanGoBack)
    {
        rootFrame.GoBack();
    }