Friday, 11 April 2014

Using the CameraCaptureUI class in a C++/CX Windows Store app

Previously I extended the C# sample photo viewer app by integrating capturing photos into the app.

This blog posts extends my C++/CX sample photo viewer app by integrating capturing photos into the app. It uses the CameraCaptureUI class to capture photos. This class provides a UI for capturing audio, video, and photos from a camera, and provides controls for cropping photos and videos, time-delayed capture, and for adjusting the camera’s settings such as resolution, audio device, brightness, and contrast.

Implementation

The MainPage now includes an AppBarButton that allows the user to take a photo.

<local:MvvmPage.BottomAppBar>
    <CommandBar HorizontalAlignment="Right">
        <AppBarButton Command="{Binding TakePhotoCommand}"
                      Label="Take Photo"
                      Icon="Camera">
        </AppBarButton>
    </CommandBar>
</local:MvvmPage.BottomAppBar>

The AppBarButton binds to the TakePhotoCommand in the MainPageViewModel class. The TakePhotoCommand property is a DelegateCommand that is initialised in the MainPageViewModel constructor to execute the TakePhoto method when the AppBarButton is selected.

void MainPageViewModel::TakePhoto(Object^ parameter)
{
    auto capturedFile = make_shared<StorageFile^>(nullptr);
 
    m_captureService->CapturePhotoAsync().then([capturedFile](StorageFile^ file)
    {
        assert(IsBackgroundThread());
        if (file == nullptr)
        {
            cancel_current_task();
        }
        (*capturedFile) = file;
        return file->CopyAsync(KnownFolders::PicturesLibrary, file->Name, NameCollisionOption::GenerateUniqueName);
    }, task_continuation_context::use_arbitrary()).then([capturedFile](StorageFile^ file)
    {
        assert(IsBackgroundThread());
        return (*capturedFile)->DeleteAsync();
    }, task_continuation_context::use_arbitrary()).then([this]()
    {
        assert(IsMainThread());
        OnPropertyChanged("Photos");
    });
}

The TakePhoto member function invokes the CapturePhotoAsync member function in the CameraCaptureService class, which returns a StorageFile object representing the captured photo. This photo is saved on disk in the apps TempState directory. Therefore, the continuation chain copies the photo to the pictures library before deleting the version stored in the TempState directory. In the final continuation, property change notification is fired on the Photos property to refresh the thumbnails shown on the MainPage. This causes the GetPhotosAsync member function in the FileSystemRepository class to be executed to retrieve the thumbnail data.

Photo capture is handled by the CameraCaptureService, which implements the pure virtual member functions in the CaptureService abstract base class. The App class contains a member variable, m_captureService, of type CaptureService, which is instantiated as a shared pointer of type CameraCaptureService. This instance is created as a shared pointer so that there’s only a single instance of the CameraCaptureService class in the app, which is then passed between the required classes. The CameraCaptureService class instance is then exposed by the GetCaptureService member function, which is called by the ViewModelLocator constructor. The ViewModelLocator then passes the CameraCaptureService instance into the MainPageViewModel class from where camera capture is invoked.

task<StorageFile^> CameraCaptureService::CapturePhotoAsync()
{
    auto dialog = ref new CameraCaptureUI();
    dialog->PhotoSettings->MaxResolution = CameraCaptureUIMaxPhotoResolution::HighestAvailable;
    dialog->PhotoSettings->Format = CameraCaptureUIPhotoFormat::Jpeg;
    dialog->PhotoSettings->AllowCropping = true;
 
    return create_task(dialog->CaptureFileAsync(CameraCaptureUIMode::Photo)).then([](StorageFile^ file)
    {
        return file;
    });
}

Once the CameraCaptureUI instance is created, several PhotoSettings properties are specified to customize the capture experience. These are the maximum resolution, photo format, and a boolean value that enables the photo cropping interface. The CaptureFileAsync method is then called to launch the UI for capturing a photo from the camera. This method takes a CameraCaptureUIMode enumeration that specifies that the user can only capture a photo, rather than video. The user then has control over when to start the capture. When the CaptureFileAsync operation completes, a StorageFile object is returned, which is then returned to the calling method (in this case the TakePhoto method of the MainPageViewModel class). The UI used by the CameraCaptureUI class is shown in the following screenshot.

screenshot_04082014_115643[2]

The overall effect is that when the user takes a photo, the app returns to the thumbnail view on the MainPage. The thumbnails are then refreshed, with the thumbnail for the new photo appearing.

Summary

This blog post has extended the sample app by further by integrating capturing photos into the app. It uses the CameraCaptureUI class to capture a photo. When the user takes a photo the app returns to the thumbnail view on the MainPage. The thumbnails are then refreshed, with the thumbnail for the new photo appearing.

The sample app can be downloaded here.

Tuesday, 8 April 2014

Using the CameraCaptureUI class in a Windows Store app

Previously I extended the sample photo viewer app so that the user will see the page content scrolled to the exact location it was at prior to termination or navigation, regardless of whether the page orientation has changed in between termination and reactivation.

This blog post extends the sample app further by integrating capturing photos into the app. It uses the CameraCaptureUI class to capture photos. This class provides a UI for capturing audio, video, and photos from a camera, and provides controls for cropping photos and videos, time-delayed capture, and for adjusting the camera’s settings such as resolution, audio device, brightness, and contrast.

Implementation

The MainPage now includes an AppBarButton that allows the user to take a photo.

<prism:VisualStateAwarePage.BottomAppBar>
    <CommandBar HorizontalAlignment="Right">
        <AppBarButton Command="{Binding TakePhotoCommand}"
                      Label="Take Photo"
                      Icon="Camera">
        </AppBarButton>
    </CommandBar>
</prism:VisualStateAwarePage.BottomAppBar>

The AppBarButton binds to the TakePhotoCommand in the MainPageViewModel class. The TakePhotoCommand property is a DelegateCommand that is initialised in the MainPageViewModel constructor to execute the TakePhoto method when the AppBarButton is selected.

private async void TakePhoto()
{
    StorageFile capturedFile = await _captureService.CapturePhotoAsync();
    if (capturedFile != null)
    {
        bool error = false;
        try
        {
            await capturedFile.CopyAsync(KnownFolders.PicturesLibrary, capturedFile.Name, NameCollisionOption.GenerateUniqueName);
            await capturedFile.DeleteAsync(StorageDeleteOption.PermanentDelete);
 
            // Refresh page content
            await Task.Delay(TimeSpan.FromSeconds(5));
            Photos = await _repository.GetPhotosAsync();
            OnPropertyChanged("Photos");
        }
        catch (FileNotFoundException)
        {
            error = true;
        }
 
        if (error)
        {
            await _messageService.ShowAlertAsync("There was an error when trying to read the photo. Please check that the photo is still available.", "Error with photo.");
        }
    }
}

The TakePhoto method invokes the CapturePhotoAsync method in the CameraCaptureService class, which returns a StorageFile object representing the captured photo. This photo is saved on disk in the apps TempState directory. Therefore, the method copies the photo to the pictures library before deleting the version stored in the TempState directory. After waiting five seconds to ensure that the file system index has been updated with the new photo details, the Photos property is updated by calling the GetPhotosAsync method on the FileSystemRepository instance. If the file is deleted before this operation can complete an error message is displayed to the user in a modal message box.

Photo capture is handled by the CameraCaptureService, which implements the ICaptureService interface. This service class is injected into the MainPageViewModel class by the Unity dependency injection container, after having been registered with the container in the App class.

public class CameraCaptureService : ICaptureService
{
    public async Task<StorageFile> CapturePhotoAsync()
    {
        var dialog = new CameraCaptureUI();
        dialog.PhotoSettings.MaxResolution = CameraCaptureUIMaxPhotoResolution.HighestAvailable;
        dialog.PhotoSettings.Format = CameraCaptureUIPhotoFormat.JpegXR;
        dialog.PhotoSettings.AllowCropping = true;
 
        var file = await dialog.CaptureFileAsync(CameraCaptureUIMode.Photo);
        return (file == null) ? null : file;
    }
}

Once the CameraCaptureUI instance is created, several PhotoSettings properties are specified to customize the capture experience. These are the maximum resolution, photo format, and a boolean value that enables the photo cropping interface. The CaptureFileAsync method is then called to launch the UI for capturing a photo from the camera. This method takes a CameraCaptureUIMode enumeration that specifies that the user can only capture a photo, rather than video. The user then has control over when to start the capture. When the CaptureFileAsync operation completes, a StorageFile object is returned, which is then returned to the calling method (in this case the TakePhoto method of the MainPageViewModel class). The UI used by the CameraCaptureUI class is shown in the following screenshot.

screenshot_04082014_115643

The overall effect is that when the user takes a photo, the app returns to the thumbnail view on the MainPage. After 5 seconds the page refreshes with the thumbnail for the new photo appearing. However, without additional code in the Photo model object, when the thumbnail appears it will be blank (grey specifically). This is because the file system will not have updated the thumbnail data for the photo. Therefore, it becomes necessary to modify the Photo model object to respond to the ThumbnailUpdated event of the FileInformation object.

private async void OnFileThumbnailUpdated(IStorageItemInformation sender, object args)
{
    await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, new DispatchedHandler(() =>
        {
            OnPropertyChanged("Thumbnail");
        }));
}

The Photo constructor registers the OnFileThumbnailUpdated event handler for the ThumbnailUpdated event of the FileInformation object. This event handler fires when the thumbnail for a FileInformation object is updated, and simply fires property change notification for the Thumbnail property of the FileInformation object. However, the property change notification has to be dispatched back to the main thread (which is the UI thread), as the code that creates Photo objects (GetPhotosAsync in the FileSystemRepository class) is running on a background thread from the thread pool. This works by using the CoreDispatcher class’s RunAsync method to run code in the main thread. You can get access to a CoreDispatcher object from the Dispatcher property of the CoreWindow object.

The overall effect is that when the thumbnail for the photo is updated, the thumbnail on the MainPage will be updated. This happens quickly enough that the user won’t see a blank (grey) thumbnail, but without this additional code, the user will see a blank thumbnail.

Summary

This blog post has extended the sample app by further by integrating capturing photos into the app. It uses the CameraCaptureUI class to capture a photo. The MainPage is then updated with the thumbnail for a photo, with an event handler for the ThumbnailUpdated event of the FileInformation object dispatching the thumbnail property change notification back to the main thread.

The sample app can be downloaded here.

Thursday, 3 April 2014

DevWeek2014–Accelerating Windows Store app development using Prism for the Windows Runtime

Today I spoke at DevWeek 2014 about Accelerating Windows Store app development using Prism for the Windows Runtime. The slides from the talk can be found here.

The code demos I used are:

For further resources see:

Thanks to DevWeek for giving me the opportunity to present, and to all attendees for listening.

DevWeek2014–Building native Windows Store apps for C# developers

Yesterday I spoke at DevWeek 2014 about Building native Windows Store apps for C# developers. The slides from the talk can be found here.

The code I walked through (the PhotoViewer sample app) can be downloaded here.

For further resources see:

Thanks to DevWeek for giving me the opportunity to present, and to all attendees for listening.