2

I'm trying to start and stop a MediaCapture preview for the camera in a Windows 8.1 Universal app. In the OnNavigatedTo method, I have the following code:

protected override async void OnNavigatedTo(NavigationEventArgs e)
{
    var scanItemsParameter = e.Parameter as ScanItemParameter;

    if (scanItemsParameter != null)
    {
        ((ScanItemViewModel)DataContext).ScanCallback = scanItemsParameter.ScanCallback;
    }

    try
    {
        HardwareButtons.CameraPressed += HardwareButtonsOnCameraPressed;
        HardwareButtons.CameraHalfPressed += HardwareButtonsOnCameraHalfPressed;
        DisplayInformation.GetForCurrentView().OrientationChanged += OnOrientationChanged;

        if (!_mediaInitialized)
        {
            var cameras = await DeviceInformation.FindAllAsync(DeviceClass.VideoCapture);
            if (cameras.Count < 1)
            {
                return;
            }
            MediaCaptureInitializationSettings settings;
            settings = new MediaCaptureInitializationSettings
            {
                VideoDeviceId = cameras[0].Id,
                PhotoCaptureSource = PhotoCaptureSource.Photo
            };

            await _mediaCapture.InitializeAsync(settings);

            VideoCapture.Source = _mediaCapture;

            _mediaInitialized = true;
        }

        SetOrientation(DisplayInformation.GetForCurrentView().CurrentOrientation);

        await _mediaCapture.StartPreviewAsync();

        await _mediaCapture.VideoDeviceController.ExposureControl.SetAutoAsync(true);

        if (_mediaCapture.VideoDeviceController.FocusControl.FocusChangedSupported)
        {
            var focusSettings = new FocusSettings();
            focusSettings.AutoFocusRange = AutoFocusRange.Normal;
            focusSettings.Mode = FocusMode.Auto;
            focusSettings.WaitForFocus = true;
            focusSettings.DisableDriverFallback = false;
            _mediaCapture.VideoDeviceController.FocusControl.Configure(focusSettings);
        }

        _mediaCapture.VideoDeviceController.FlashControl.Auto = true;
    }
    catch (Exception ex)
    {
        var ex2 = ex;
        throw;
    }
}

In the OnNavigatingFrom method, I am cleaning up some event handlers and calling MediaCapture.StopPreviewAsync():

protected override async void OnNavigatingFrom(NavigatingCancelEventArgs e)
{
    await _mediaCapture.StopPreviewAsync();
    HardwareButtons.CameraPressed -= HardwareButtonsOnCameraPressed;
    HardwareButtons.CameraHalfPressed -= HardwareButtonsOnCameraHalfPressed;
    DisplayInformation.GetForCurrentView().OrientationChanged -= OnOrientationChanged;
}

The call works correctly the first time I open the page, but if I navigate away from the page and come back, I get an InvalidOperationException. What am I missing?

As a note, I'm using MVVM light, if that makes any difference...

Thanks in advance for any help...

Wyatt Earp
  • 1,783
  • 13
  • 23
  • How do you navigate away? The problem I suspect is that those events are not called every time you 'leave the app'. For example if you are using suspension manager, the NavigateFrom event will be called when you suspend the app (hit start button, change app etc.) (this also won't happen while debugging), but NavigatedTo will not be called when you return to the app. – Romasz Mar 03 '15 at 05:58
  • @Romasz I am using the `NavigationService.NavigateTo()`, and `NavigationService.GoBack()` methods to change the pages. When I use the latter, the code in the `OnNavigatingFrom` method is getting called successfully. And the `OnNavigatedTo` code definitely gets called on at least the second time I visit the page. It consistently breaks on the `StartPreviewAsync` method. I think it does the same thing when the app is suspended or the home button is pressed. I haven't started looking into those issues yet. – Wyatt Earp Mar 03 '15 at 13:18
  • Have you set the `NavigationCacheMode = NavigationCacheMode.Required;` of your Page - if not there is possibility that your MediaCapture is *null* once you come back from navigation. I've tested sample and should work if you have futher problems give me a sign. Also using OnNavigatedTo and From (only) is not a good idea and you should slowly start looking into these issues ;) – Romasz Mar 03 '15 at 17:00
  • @Romasz Thanks for the help. I'll try it with NavigationCacheMode.Required this evening. Off the top of my head, I don't think I'm using that. And what do you mean by "using OnNavigatedTo and From (only) is not a good idea"? This is the first project I've done with these technologies, so I could certainly use all the advice you can give. I'm also finding it hard to get good documentation when it comes to developing a Windows Phone 8.1 Universal App. – Wyatt Earp Mar 03 '15 at 21:33
  • As I think most of things you should find at MSDN. As for a bad idea - take a look [at this answer](http://stackoverflow.com/a/23973521/2681948) (you will also find there some links refering to the problem). You may also thing of *Window.Current* events which may be better in some cases. – Romasz Mar 03 '15 at 21:48

1 Answers1

1

I was able to resolve this by disposing of the MediaCapture element before navigating away from the page, and re-instantiating it upon returning to the page.

In the OnNavigatingFrom method, I added _mediaCapture.Dispose(); and _mediaCapture = null;:

protected override async void OnNavigatingFrom(NavigatingCancelEventArgs e)
{
    if (_mediaCapture != null)
    {
        await _mediaCapture.StopPreviewAsync();
        _mediaCapture.Dispose();
       _mediaCapture = null;
    }
    HardwareButtons.CameraPressed -= HardwareButtonsOnCameraPressed;
    HardwareButtons.CameraHalfPressed -= HardwareButtonsOnCameraHalfPressed;
    DisplayInformation.GetForCurrentView().OrientationChanged -= OnOrientationChanged;
}

Then, just before the _mediaCapture.InitializeAsync() call in OnNavigatedTo, I instantiate a new one:

//...
_mediaCapture = new MediaCapture();
//...
Wyatt Earp
  • 1,783
  • 13
  • 23