Archive

Archive for the ‘Windows 8’ Category

Windows 8 Using WebCam

September 10, 2012 1 comment

The new Windows Runtime object model makes it very easy to access all kind of sensors and devices. In this example i’ll show, how to get images and videos from a connected / builtin webcam.

There are two ways how to get images or videos from the device:

  • CameraCaptureUI

The easiest way is using the builtin CameraCaptureUI object, which displays the system provided dialog always fullscreen and looks like this: image
The disadvantage of this approach is, that your app is not visible during capturing, because the CameraCaptureUI always takes up the whole screen and the user can only use the system provided settings dialogs. This dialog allows the user to crop the taken image or video immediately after recording and then returns the resulting image or video to your app.

  • MediaCapture

    Using the MediaCapture object model the system does not show any UI, but your app must display its own UI for preview and capturing the image or video.
    Although it takes a few more steps, it also allows much more finer control
    For more info on this way, scroll down to "How to use MediaCapture"

I’ll start from the minimalistic template app, which i’ve described in this post.

Sample on how to use the CameraCaptureUI:
Then we’ll add two button in the content area and label the first button "Get Image" and the second one "Get Video". Below we will place a Border control and above this a Image Control.

Should look like like this:

image   image

Fetching images using CameraCaptureUI

Interaction with the Webcam can only be done, if the user allows to do so.

Therefore the developer has to request access to the webcam. This can be done by opening the Package.appxmanifest and check the WebCam capability:

This will prompt the user on the first startup of the app with this question:

image 

image

Now we need a few lines of code to fetch the image from the webcam, save it to a temp folder and then read it into memory to display it in the image control.

The easiest way would be this:

private async void GetImageFromWebCamSimple()
{
    CameraCaptureUI camUI = new CameraCaptureUI();
    StorageFile storageFile = await camUI.CaptureFileAsync(CameraCaptureUIMode.Photo);
    if (storageFile != null)
    {
        IRandomAccessStream stream = await storageFile.OpenReadAsync();
        BitmapImage bitmapImage = new BitmapImage();
        bitmapImage.SetSource(stream);
        MyImageControl.Source = bitmapImage;
    }
}


Fetching the image from the webcam and storing it to disk is just the first 2 lines!!

A real world app would of course wrap the call to CaptureFileAsync() with a try block, because if the user denies the permission to use the webcam, then this would crash the app.

 

Fetching a video using CameraCaptureUI

Almost the same logic is needed to fetch a video, save it to a temporary file and then play it back on a MediaElement control:

private async void GetVideoFromWebCam()
{
    CameraCaptureUI camUI = new CameraCaptureUI();
    StorageFile storageFile = await camUI.CaptureFileAsync(CameraCaptureUIMode.Video);
    if (storageFile != null)
    {
        IRandomAccessStream stream = await storageFile.OpenReadAsync();
        MyMediaElement.SetSource(stream, "image/jpeg");
        MyMediaElement.Play();
    }
}

 

Sample on how to use MediaCapture

 

Also for this sample, i’ll start from the minimalistic template app, which i’ve described in

this post.

As UI elements we need a ImageControl for displaying the captured image and a MediaElement for replaying the captured video stream.

For recording the image or video, a CaptureElement must be added to the XAML code.

To use the webCam, the capabilities WebCam and Microphone must be checked in the Package.AppxManifest.

 

image

 

  1. The first step is to find all the Cameradevices using DeviceInformation.FindAllAsync()
  2. The next step is to create a Storagefile for the image or video
  3. Then a new MediaCapture object must be created
  4. A new MediaCaptureInitializationSettings object must be created and the member VideoDeviceId must be set to one of the Ids of the found cameras.
  5. After this, the InitializeAsync(settings) call on the MediaCapture object must be made and then either one of this functions can be called:
  • CapturePhotoToStorageFileAsync
  • StartRecordToStorageFileAsync

Both will save the image or video into the given StorageFile.

Optionally the StartPreviewAsync() function can be called to get a preview of the current image.

MediaCapture mc = null;
StorageFile videoStorageFile = null;

private void btnStartVideo_Click_1(object sender, RoutedEventArgs e)
{
    StartRecordVideoUsingMediaCapture();
}

private void btnStopVideo_Click_1(object sender, RoutedEventArgs e)
{
    StopRecordVideoUsingMediaCapture();
}

private async void GetImageUsingMediaCapture()
{
    DeviceInformationCollection myDevices = 
        await DeviceInformation.FindAllAsync(DeviceClass.VideoCapture);

    if (myDevices.Count < 1)
    {
        await new MessageDialog("No Camera found!").ShowAsync();
        return;
    }
    // Create the image file
    StorageFolder localFolder = ApplicationData.Current.LocalFolder;
    string filename = "Pic_" + DateTime.Now.ToString("yyyy_MM_dd-hh_mm_ss") + ".jpg";
    StorageFile photoStorageFile = 
        await localFolder.CreateFileAsync(filename, 
                        CreationCollisionOption.ReplaceExisting);

    bool camAvailable = true;
    try
    {
        // Initialize MediaCapture
        mc = new MediaCapture();
        MediaCaptureInitializationSettings settings =
                    new MediaCaptureInitializationSettings();

        settings.VideoDeviceId = myDevices.ElementAt(0).Id;
        await mc.InitializeAsync(settings); // Will check for Capabilities here

        //// Define Image quality
        ImageEncodingProperties imageProperties = new ImageEncodingProperties();
        imageProperties.Subtype = "JPEG";
        imageProperties.Width = 640;
        imageProperties.Height = 400;
        
        await mc.CapturePhotoToStorageFileAsync(imageProperties, photoStorageFile);

        DisplayImageFromFileInImageControl(photoStorageFile);
    }
    catch (Exception ex)
    {
        camAvailable = false;
    }

    if (camAvailable == false)
    {
        await new Windows.UI.Popups.MessageDialog("No Webcam allowed?").ShowAsync();
    }

    if (photoStorageFile != null)
    {
        DisplayImageFromFileInImageControl(photoStorageFile);
    }
}

private async void StartRecordVideoUsingMediaCapture()
{
    DeviceInformationCollection myDevices = 
        await DeviceInformation.FindAllAsync(DeviceClass.VideoCapture);

    if (myDevices.Count < 1)
    {
        await new MessageDialog("No Camera found!").ShowAsync();
        return;
    }
    // Create the video file
    StorageFolder localFolder = ApplicationData.Current.LocalFolder;
    string filename = "Video_" + DateTime.Now.ToString("yyyy_MM_dd-hh_mm_ss") + ".mp4";
    videoStorageFile = await localFolder.CreateFileAsync(filename, 
                                        CreationCollisionOption.ReplaceExisting);

    bool camAvailable = true;
    try
    {
        btnStartVideo.IsEnabled = false;
        btnStopVideo.IsEnabled = true;

        // Initialize MediaCapture
        mc = new MediaCapture();
        MediaCaptureInitializationSettings settings = 
            new MediaCaptureInitializationSettings();

        settings.VideoDeviceId = myDevices.ElementAt(0).Id; // Use 1. camera
        await mc.InitializeAsync(settings); // Will check for Capabilities here

        // Also do Preview
        previewElement.Source = mc;
        await mc.StartPreviewAsync();

        MediaEncodingProfile recordProfile = 
            Windows.Media.MediaProperties.MediaEncodingProfile.CreateMp4(
                                                        VideoEncodingQuality.Auto);
        await mc.StartRecordToStorageFileAsync(recordProfile, videoStorageFile);
        lblStatus.Text = "Recording...";
    }
    catch (Exception ex)
    {
        camAvailable = false;
    }

    if (camAvailable == false)
    {
        await new Windows.UI.Popups.MessageDialog("No Webcam allowed?").ShowAsync();
    }
}

private async void StopRecordVideoUsingMediaCapture()
{
    btnStartVideo.IsEnabled = true;
    btnStopVideo.IsEnabled = false;

    await mc.StopRecordAsync();

    if (videoStorageFile != null)
    {
        lblStatus.Text = "Replay video...";
        DisplayVideo(videoStorageFile);
    }
}

#endregion Using MediaCapture 

#region Image / Video Display helpers
private async void DisplayImageFromFileInImageControl(StorageFile storageFile)
{
    IRandomAccessStream stream = await storageFile.OpenReadAsync();
    BitmapImage bitmapImage = new BitmapImage();

    bitmapImage.SetSource(stream);
    MyImageControl.Source = bitmapImage;
}

private async void DisplayVideo(StorageFile storageFile)
{
    IRandomAccessStream stream = await storageFile.OpenReadAsync();
    MyMediaElement.SetSource(stream, "image/jpeg");
    MyMediaElement.Play();
}        
#endregion

 .

Categories: Metro, Windows 8

Windows 8 New UI Apps FilePickerTarget

September 9, 2012 Leave a comment

The FilePicker concept is very flexible to provide apps with access to any filesystem location, while the user is still in charge of his data, because the app always requires user interaction before data from the filesystem can be accessed.

But there is more behind this concept. Developer can extend their app to not only use the FilePicker interface for loading and saving data, but also enable their app to act as source for any FilePicker operation.

This is what SkyDrive app by default does.

To see this concept in action, just use any app, e.g. tghe Music app and open a file.

Then open the list of provider from the left top and switch to SkyDrive.
This will then be on screen:
image  ==> image

After selecting a file, the original app can use this file as it would be on the local filesystem.

To enable your app to provide this kind of FilePickerTarget feature you must follow this steps:

Add the "File Open Picker" Declaration in the AppXManifest and either select "Supports any filetype" or add all filetypes you want to provide.

image

Add a new page of type  FileOpen Picker Contract to your project
image

Make sure, that the following function will be added to App.xaml.cs. The Add Page wizard does it for you., when adding the File Open Picker contract.

Inside this code make sure to activate the newly added page:

protected override void OnFileOpenPickerActivated(Windows.ApplicationModel.Activation.FileOpenPickerActivatedEventArgs args)
{
   var fileOpenPickerPage = new FilePickerTargetApp.Views.FileOpenPickerPage();
   fileOpenPickerPage.Activate(args);
}

 

I stripped down the code behind for the newly added FileOpenPickerPage to a minimum here:

The Activate function there looks like this:

public async void Activate(FileOpenPickerActivatedEventArgs args)
{
    this._fileOpenPickerUI = args.FileOpenPickerUI;
    Window.Current.Content = this;
    Window.Current.Activate();

    CreateAndReadDummyData();
}

 

CreateAndReadDummyData will create a few textfiles in the temp storage of the app and then add all this filenames to the left ListBox.

The user should then select one or more files, which will add the names to the right listbox and also add it to the given instance of _fileOpenPicker, where it will be given to the AddFile() method

 

The UI looks ugly, but the minimalistic view should help to understand the concept:

Only the grey part is coming from the FilePicker target app, the surrounding space is from the calling app, which is in this demo scenarion the same app, but usually a different one!

image

 

public sealed partial class MyFileOpenPickerPage : FilePickerTargetApp.Common.LayoutAwarePage
{
    private Windows.Storage.Pickers.Provider.FileOpenPickerUI _fileOpenPickerUI;

    public MyFileOpenPickerPage()
    {
        this.InitializeComponent();
    }

    public async void Activate(FileOpenPickerActivatedEventArgs args)
    {
        this._fileOpenPickerUI = args.FileOpenPickerUI;
        Window.Current.Content = this;
        Window.Current.Activate();

        CreateAndReadDummyData();
    }

    private async void ListFiles_SelectionChanged_1(object sender, SelectionChangedEventArgs e)
    {
        var tempFolder = Windows.Storage.ApplicationData.Current.TemporaryFolder;
        for (int i = 0; i < e.AddedItems.Count; i++)
        {
            string filename = (e.AddedItems[i]) as String;

            // add selected file to FileOpenPicker
            StorageFile sf = await tempFolder.GetFileAsync(filename);
            this._fileOpenPickerUI.AddFile(filename, sf);

            // Update UI
            await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
            {
                SelectedFiles.Items.Add(filename);
            });
        }

    }

    private async void SelectedFiles_Tapped_1(object sender, TappedRoutedEventArgs e)
    {
        string filename = SelectedFiles.SelectedItem.ToString();

        // REMOVE selected file from FileOpenPicker
        this._fileOpenPickerUI.RemoveFile(filename);

        // Update UI
        await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
        {
            SelectedFiles.Items.Remove(filename);
        });
    }
}

 

 

The important detail is to add at least one file of the type, which was specified by the caller.

(See lines 28 and 44)

Otherwise the "Open" button at the bottom never gets active and the user can only cancel the FilePicker operation.

If the user selects a file and then  click "Open", then the selected files will be forwarded to the calling application and there they can be treated like any other regular files.

 

The nice thing is, that the target application can fake all the files, which will be displayed and only fetch the real files, when any file is selected. So the left listbox could be filled with just the filenames from a webservice and the real file could then be fetched and temporarily placed in the temporary storage, when the user has reallly selected the file.

 .

Categories: Metro, Windows 8

Windows 8 New UI Apps FilePicker

September 9, 2012 Leave a comment

Every Win 8 app does live in its own sandbox. Communication between apps is very limited.

The following picture does show the possible interaction ways:

image

In theory, any developer can require access to the users filesystem places by checking the matching capabilities in the app manifest.

But this will ask the user on the first start, whether he want to allow access the app to this specific places.

And: Some of the capabilities can only be requested by developers, who have registered a company account!

The reasons, that this is in almost all the cases not a very good idea, is data privacy. If a user allows access to his data folders, then the app could transfer all data to any place in the internet.

==> Capabilities for allowing access to the users data locations should be used very seldom due to potential data privacy issues!

image

But even in the scenario, that the user will allow access to this places:

The app will never be able to transfer data to or from the users desktop or any other filesystem location, because the access is limited to the e.g. Documents libarary.

 

If your app needs to transfer data to any location on the users filesystem, then the concept of FilePicker will be very helpful.

FileOpenPicker and FileSavePicker are a way to ask the user to provide a file. The user can then navigate to any place on the local filesystem or even on any connected network filesystem and select a file.

Using FileOPenPicker the user will see this and can switch between all this places:

image                                                           image

The big difference then is, that the user is in charge and can decide whether he really wants to allow the app to access this file.

The app can never access this file without the users explicit action.

There is even another big advantage using the FilePicker interface:

It’s not only limited to the local and network filesystem, but can access a lot of other places, like Skydrive and other third party apps. You can even provide a FilePicker interface in your app, which then acts as source for data read/write operations to other apps.

Another very nice feature of this interface is, that reading and writing to any source/destination which the user has selected, is as easy as reading from a local file. There is no difference and the app code must not handle any special cases. It is just reading or writing through the FileOpen- or FileSavePicker interface.

Using the FileOpenPicker from code requires only a few lines of code:

private async void LoadFileUsingFilePicker()
{
    FileOpenPicker fop = new FileOpenPicker();
    fop.SuggestedStartLocation = PickerLocationId.ComputerFolder;
    fop.ViewMode = PickerViewMode.List;
    fop.FileTypeFilter.Add(".txt");
    fop.FileTypeFilter.Add(".cs");
    var storageFile = await fop.PickSingleFileAsync();
    if (storageFile != null)
    {
        var lines = await FileIO.ReadLinesAsync(storageFile);
        if (lines != null)
        {
            for (int i = 0; i < lines.Count; i++)
            {
                txtData.Text += lines[i];
            }
        }

    }
}


The same applies for saving a file to any location on the users filesystem

(but on behalf of the user):

private async void SaveFileUsingFilePicker()
{
    FileSavePicker fsp = new FileSavePicker();
    fsp.SuggestedStartLocation = PickerLocationId.Desktop;
    fsp.FileTypeChoices.Add("Text file", new string[] { ".txt" });
    fsp.SuggestedFileName = "NewFile.txt";
    fsp.DefaultFileExtension = ".txt";
    StorageFile storageFile = await fsp.PickSaveFileAsync();
    if (storageFile != null)
    {
        await FileIO.WriteTextAsync(storageFile, txtData.Text);
    }
}
Categories: Metro, Windows 8

Windows 8 AppBar

September 8, 2012 2 comments

New UI Style apps are always fullscreen and do not display any chrome like borders or frames. Functionality should be placed on data items instead. But in some cases additional functionality is needed. One of the possible solutions for this, is to use the AppBar concept.

Windows 8 apps can provide AppBar on the top or on the bottom of the app itslef.

Some examples:
Internet Explorer is using the top AppBar for switching / adding tabs and the bottom bar for display of the Url input field and the users favorites.

The following picture shows both AppBars, which is in reality not possible. You can either display the top or the bottom AppBar, but not both at the same time. (Other apps will show both at the same time)

Invoking the AppBar can be done by swiping from the top border or from the bottom border on a touch device. Right click with the mouse or WinKey + Z will have the same effect.

 

image

 

Adding a AppBar to the bottom of a page

To add a AppBar at the bottom of your own program, the following definition must be added to the XAML-page:

<Page.BottomAppBar>
    <AppBar Name="PageAppBar" IsOpen="True" IsSticky="True">
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*" />
                <ColumnDefinition Width="*" />
            </Grid.ColumnDefinitions>

            <StackPanel Orientation="Horizontal" 
                        Grid.Column="0" HorizontalAlignment="Left">
                <Button x:Name="btnFilePicker" 
                        Style="{StaticResource OpenFileAppBarButtonStyle}" 
                        Click="btnFilePicker_Click_1" />
            </StackPanel>
            <StackPanel Orientation="Horizontal" 
                        Grid.Column="1" HorizontalAlignment="Right">
                <Button x:Name="btnAdd" 
                        Style="{StaticResource AddAppBarButtonStyle}" 
                        Click="btnAdd_Click_1" />
            </StackPanel>
        </Grid>

    </AppBar>
</Page.BottomAppBar>

The bottom AppBar in this example is split into a left and right part. UI Style guide recommends, that the commands on the right side should be selection specific, while the commands on the left side should be global and not specific to any selection.

In this case the button on the bottom left will open the FileOpenPicker and the button on the bottom right will create a new item.

The symbols in this buttons are automatically added by using predefined styles.

Look into Common/StandardStyles.xaml and you will find a lot of predefined styles.

BUT: Most of them are commented out and you need to uncomment the one, you want to use

After adding the XAML above to a blank page you will get the following UI:

image

The attributes IsOpen="True" will display the AppBar all the time. Without the attribut, the user must first invoke the AppBar, either with a swipe from the bottom or WinKey + Z.

The default and recommended behavior is, that AppBar is NOT visible all the time.

The attribute IsSticky="True" will leave the AppBar open, even after a button was clicked on the AppBar. This is again not the default behavior. The recommended default behavior is, that the AppBar must be manually invoked and then will be hidden after using it.

 

Adding a AppBar to the top of a page

To add a AppBar at the top, the following XAML must be added to the page:

<Page.TopAppBar>
    <AppBar Name="PageTopAppBar" IsOpen="False" IsSticky="False">
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*" />
                <ColumnDefinition Width="*" />
            </Grid.ColumnDefinitions>
                
            <StackPanel Grid.Column="0" 
                        Orientation="Horizontal" HorizontalAlignment="Left">
                <Button Name="btnTopLeft" 
                        Style="{StaticResource StreetAppBarButtonStyle}" />
            </StackPanel>

            <StackPanel Grid.Column="1" 
                        Orientation="Horizontal" HorizontalAlignment="Right">
                <Button Name="btnTopRight" 
                        Style="{StaticResource MapAppBarButtonStyle}" />
            </StackPanel>            
        </Grid>
    </AppBar>
</Page.TopAppBar>

Again, the highlighted style definitions must be uncommented from StandardStyles.xaml.

The app will then look like this:

image

 

[EDIT]

I’ve added the sample project as attachement here: BottomAppBarSample.zip

 .

Categories: Metro, Windows 8

Windows 8 Apps: Page navigation with XAML

September 8, 2012 Leave a comment

Windows 8 Apps are always fullscreen. The concept of overlapping windows like in Desktop applications is not existing. Only popup style dialogs are ok to use. In most scenarios it will be necessary to have different windows for displaying different data. Only one window is vivible at any time. All previous windows are hidden.

But Windows can track the list of previously displayed windows inside a single application.

Every page, except for the main page will show a back button at the top left corner. This concept is known from Windows Phone and makes it easy for users to navigate inside the app.

It is recommended to use the template "Basic Page" for all pages, which is inheriting a lot of functionality from inside the LayoutAwarePage class.

The Navigation functionality is placed inside the Frame class.

rootFrame.Navigate(typeOf(DestinationPage), objParam) allows to change to the given page by just using its typename.

There are is also GoBack and GoForward() functions, which act on the current stack.

The properties CanGoBack and CanGoForward can be used as an indicator, whether it’s useful to display the BackButton or not.

This code will change the current page to SecondPage, where the template code from BasicPage already makes sure, that the SecondPage will display a BackButton at the left top:

private void btnGotoSecondPage_Click_1(object sender, RoutedEventArgs e)
{
    this.Frame.Navigate(typeof(SecondPage));
}

image image

Categories: Metro, Windows 8

Windows 8 App Setttings flyout dialog

September 8, 2012 1 comment

All Windows 8 app settings must be accessible through the same mechanism.
While in any app, the user must be able to enter the settings dialog through the settings charm. (Swipe from the right edge on a touch device or use WinKey+C)

The settings charm by default will display the generic settings dialog like this one on the left.

The user can follow links from this dialog to specific settings, which in turn will display another dialog.  This other dialogs will always lay on top of the current dialog,
so it seems, that they are replacing it.
The only difference is, that this other dialogs have a back button
on the top, which allows the user to go back to the initial settings page.

image image

Clicking on anything outside the settings dialog will close the dialog (light dismiss).

Sample dialog after clicking on "My Settings menu" entry

Adding a new menu entry to the default settings page

To add a settings dialog, the first step is to add a menu label to the default settings page.

For this the CommandsRequested event must be intercepted, e.g. by adding the hilighted line in the ctor of the Mainpage:

This will make sure, that the new settings menu label will be added to the settings pane, before the pane will be shown. 
The Microsoft UI style guide recommends to use either a 346 px or 646 px wide dialog for the settings flyout!

private double settingsWidth = 346; // should be 346 or 646 
private Popup settingsPopup;        // container for flyout
private Rect windowBounds;          // determine correct height
public MainPage() { this.InitializeComponent(); windowBounds = Window.Current.Bounds; SettingsPane.GetForCurrentView().CommandsRequested +=
SettingsOnCommandsRequested;
Window.Current.SizeChanged += OnWindowSizeChanged; } void OnWindowSizeChanged(object sender,
Windows.UI.Core.
WindowSizeChangedEventArgs e) { windowBounds = Window.Current.Bounds; }
void SettingsOnCommandsRequested(SettingsPane settingsPane,
SettingsPaneCommandsRequestedEventArgs eventArgs) { UICommandInvokedHandler mySettingsHandler
=
new UICommandInvokedHandler(onSettingsCommand); SettingsCommand mySettingsCommand
=
new SettingsCommand("MySettingsId", "My Settings menu",
mySettingsHandler); eventArgs.Request.ApplicationCommands.Add(mySettingsCommand); }

 

Then we also need a handler, which gets executed, when the user clicks the new settings menu. This handler will then create a popup dialog on top of the settings pane, in which the settings flyout page will be added. The folllowing code does exactly this:

 

void onSettingsCommand(IUICommand command)
{
// Create a Popup window which will contain our flyout. settingsPopup = new Popup(); settingsPopup.Closed += OnPopupClosed; Window.Current.Activated += OnWindowActivated; settingsPopup.IsLightDismissEnabled = true; settingsPopup.Width = settingsWidth; settingsPopup.Height = windowBounds.Height; // Add the proper animation for the panel. settingsPopup.ChildTransitions = new TransitionCollection(); settingsPopup.ChildTransitions.Add(new PaneThemeTransition() { Edge = (SettingsPane.Edge == SettingsEdgeLocation.Right) ? EdgeTransitionLocation.Right : EdgeTransitionLocation.Left }); // Create a SettingsFlyout the same dimenssions as the Popup. SettingsFlyout mypane = new SettingsFlyout(); mypane.Width = settingsWidth; mypane.Height = windowBounds.Height; // Place the SettingsFlyout inside our Popup window. settingsPopup.Child = mypane; // Let's define the location of our Popup. settingsPopup.SetValue(Canvas.LeftProperty,
SettingsPane.Edge == SettingsEdgeLocation.Right ?
(windowBounds.Width - settingsWidth) : 0); settingsPopup.SetValue(
Canvas.TopProperty, 0); settingsPopup.IsOpen = true;
}

 
Then we need to make sure, that clicking outside the dialog will automatically close the dialog. This can be done by handling the Activated event and checking for Deactivated state.

Then make sure, that when the dialog really gets dismissed, that the Activated event handler gets removed:

private void OnWindowActivated(object sender, 
                Windows.UI.Core.WindowActivatedEventArgs e)
{
    if (e.WindowActivationState == 
          Windows.UI.Core.CoreWindowActivationState.Deactivated)
    {
        settingsPopup.IsOpen = false;
    }
}


void OnPopupClosed(object sender, object e)
{
    Window.Current.Activated -= OnWindowActivated;
}

..

 

Now clicking on the new menu entry, the system will display the SettingsFlyout.xaml page inside the settings pane.

This page is a regular "Basic page", inheriting from LayoutAwarePage.

Make sure to set the design width attribut to either 346 or 646 so that the designer also displays it in correct way.

The XAML should look like this:

 

<common:LayoutAwarePage
    x:Class="FlyOutSampleApp.Views.SettingsFlyout"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:common="using:FlyOutSampleApp.Common"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    d:DesignHeight="768"
    d:DesignWidth="346">

The the real content of the settingspage must then be added to Row 1 of the LayoutRoot grid:

<ScrollViewer VerticalScrollBarVisibility="Auto" Grid.Row="1">

<
Grid Margin="40,33,40,39" VerticalAlignment="Top" Grid.RowSpan="3">
<
StackPanel x:Name="FlyoutContent">
<
TextBlock FontWeight="Bold" Text="My Settings" />
<
ToggleSwitch Name="ts1" Header="WLAN"

OnContent="ON" OffContent="OFF"

Toggled="ts1_Toggled_1" IsOn="True"/>
<!-- ... some more settings controls.. --->

</
StackPanel>
</
Grid>
</
ScrollViewer>

      


The code behind for the SettingsFlyout should have some code for setting the transitions and positions:

public SettingsFlyout()
{
    this.InitializeComponent();
    FlyoutContent.Transitions = new TransitionCollection();
    FlyoutContent.Transitions.Add(new EntranceThemeTransition()
    {
        FromHorizontalOffset = 
        (SettingsPane.Edge == SettingsEdgeLocation.Right) ? 
            ContentAnimationOffset : (ContentAnimationOffset * -1)
    });
}

 

And then finally the back button handling:

private void MySettingsBackClicked(object sender, RoutedEventArgs e)
{
    // First close our Flyout.
    Popup parent = this.Parent as Popup;
    if (parent != null)
    {
        parent.IsOpen = false;
    }

    // If app is not snapped, then back button shows Settings pane again.
    if (Windows.UI.ViewManagement.ApplicationView.Value != 
Windows.UI.ViewManagement.
ApplicationViewState.Snapped) { SettingsPane.Show(); } }
Categories: Metro, Windows 8

Windows 8 Toast Notifications

September 5, 2012 Leave a comment

Every Windows 8 New UI Style app can display notifications, which will be shown on the right top corner like this:

image

User can ignore or close the messages using the Close symbol.

If the user clicks on the message, the the app will be invoked again and the code in app.xaml – OnLaunched() will be executed

 

Display toast notification

To display a notification the following code is needed:

  1. Fetch one of the predefined templates as XML:
    XmlDocument xmlDoc = 
        ToastNotificationManager.GetTemplateContent(ToastTemplateType.ToastText02);
    
    // ToastTemplateType.ToastText02 will return xml like this:
    //<toast>
    //  <visual>
    //    <binding template="ToastText02">
    //      <text id="1"></text>
    //      <text id="2"></text>
    //    </binding>
    //  </visual>
    //</toast>
    

  2. Update the toast data:
    XmlDocument xmlDoc = 
        ToastNotificationManager.GetTemplateContent
    (
    ToastTemplateType.ToastText02); // ToastTemplateType.ToastText02 will return xml like this: //<toast> // <visual> // <binding template="ToastText02"> // <text id="1"></text> // <text id="2"></text> // </binding> // </visual> //</toast>

  3. Get a ToastNotifier and show the notification:

    ToastNotifier toastNotifier = 
    ToastNotificationManager.CreateToastNotifier();
    ToastNotification toastNotification = new ToastNotification(xmlDoc); toastNotifier.Show(toastNotification);

 

Now the toast should be displayed. If not, then the user did probably disable toast notifications. This can be done either per app, globally or per user. See section below

Schedule toast notification

App can show a toast at a specific time. The app must not run at the given time.

This can be done using almost the same code as for displaying the notification. The only difference is, that a ScheduleToastNotification object must be created from the Xml.

This code will display the given notification at the specified time:

  1. Fetch one of the predefined templates as XML:
    XmlDocument xmlDoc = 
        ToastNotificationManager.GetTemplateContent(ToastTemplateType.ToastText02);
    
    // ToastTemplateType.ToastText02 will return xml like this:
    //<toast>
    //  <visual>
    //    <binding template="ToastText02">
    //      <text id="1"></text>
    //      <text id="2"></text>
    //    </binding>
    //  </visual>
    //</toast>
    

  2. Update the toast data:

    XmlDocument xmlDoc = 
        ToastNotificationManager.GetTemplateContent
    (
    ToastTemplateType.ToastText02); // ToastTemplateType.ToastText02 will return xml like this: //<toast> // <visual> // <binding template="ToastText02"> // <text id="1"></text> // <text id="2"></text> // </binding> // </visual> //</toast>

  3. Get a ToastNotifier and add the scheduled notification:
  4. ToastNotifier toastNotifier = 
    ToastNotificationManager.CreateToastNotifier();
    ScheduledToastNotification toastNotification =
    new ScheduledToastNotification (xmlDoc,

    new DateTimeOffset(DateTime.Now.AddSeconds(5)));

    toastNotifier.AddToSchedule(toastNotification);

 

Checking the notification setting


There are many possible ways to disable notifications. It can be done on user, app or global level. The current setting and the possible values can be fetched using this code:

var setting = ToastNotificationManager.CreateToastNotifier().Setting;
switch (setting)
{
    case NotificationSetting.DisabledByGroupPolicy:
        break;
    case NotificationSetting.DisabledByManifest:
        break;
    case NotificationSetting.DisabledForApplication:
        break;
    case NotificationSetting.DisabledForUser:
        break;
    case NotificationSetting.Enabled:
        break;
    default:
        break;
}

Categories: Metro, Windows 8