Windows 10 on ioProgrammo

26/02/2015 Leave a comment

I have written an article for the n°196 of ioProgrammo (March/April 2015) in which I talk about the latest news on Windows 10 and how they will impact the world of developers.

ioProgrammo March/April 2015

ioProgrammo March/April 2015

Categories: General

An improved NavigationService for MVVM Light in Universal apps

24/02/2015 1 comment

Some times ago we talked about the new NavigationService that has been introduced with MVVM Light 5.

The implementation for Universal apps is very useful as it covers all the basic needs. However, at this time it lacks some important features, like a way to determine whether the navigation can go back and a method to remove the most recent available entry from the back stack.

So, we can extend the built-in NavigationService defining an interface like this:

public interface INavigationServiceEx : INavigationService
{
    bool CanGoBack { get; }
    
    bool RemoveBackEntry();       
}

And the corresponding implementation:

public class NavigationServiceEx : NavigationService, INavigationServiceEx
{
    public bool CanGoBack
    {
        get
        {
            var frame = this.GetMainFrame();
            if (frame != null)
                return frame.CanGoBack;

            return false;
        }
    }

    public bool RemoveBackEntry()
    {
        var frame = this.GetMainFrame();
        if (frame.CanGoBack)
        {
            frame.BackStack.RemoveAt(frame.BackStackDepth - 1);
            return true;
        }

        return false;
    }

    private Frame GetMainFrame()
    {
        return (Frame)Window.Current.Content;
    }
}

In this class, we simply get the current Frame and then access its CanGoBack and BackStack property.

Now we can use the new NavigationServiceEx in the usual way:

static ViewModelLocator()
{
    ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);

    var navigationService = CreateNavigationService();
    SimpleIoc.Default.Register<INavigationServiceEx>(() => navigationService);

    // ...
}

private static INavigationServiceEx CreateNavigationService()
{
    var navigationService = new NavigationServiceEx();
    navigationService.Configure(Constants.SecondPage, typeof(SecondPage));

    return navigationService;
}

Of course, all ViewModels need to refer the new INavigationServiceEx interface (instead of the default INavigationService provided by MVVM Light).

Categories: C#, MVVM, Windows Phone, WinRT

How to open and close Flyouts in Universal apps using MVVM

15/01/2015 5 comments

Some times ago we talked about how to open attached Flyouts and close them using custom behaviors and MVVM. This was necessary because the Flyout control doesn’t expose properties to control its visibility, so we need to use its ShowAt and Hide methods explicitly.

While this approach works correctly, we can obtain the same result in a more elegant way with two simple Attached Properties. The following is a generic version of the implementation shown in the article Using Windows 8.1 Flyout with MVVM and works with every control, not only buttons (remember, in fact, that we can attach a Flyout on any FrameworkElement).

Let’s start creating a FlyoutHelper class:

public static class FlyoutHelper
{
    public static readonly DependencyProperty IsVisibleProperty = 
        DependencyProperty.RegisterAttached(
        "IsOpen", typeof(bool), typeof(FlyoutHelper), 
        new PropertyMetadata(true, IsOpenChangedCallback));

    public static readonly DependencyProperty ParentProperty = 
        DependencyProperty.RegisterAttached(
        "Parent", typeof(FrameworkElement), typeof(FlyoutHelper), null);

    public static void SetIsOpen(DependencyObject element, bool value)
    {
        element.SetValue(IsVisibleProperty, value);
    }

    public static bool GetIsOpen(DependencyObject element)
    {
        return (bool)element.GetValue(IsVisibleProperty);
    }

    private static void IsOpenChangedCallback(DependencyObject d, 
        DependencyPropertyChangedEventArgs e)
    {
        var fb = d as FlyoutBase;
        if (fb == null)
            return;

        if ((bool)e.NewValue)
        {
            fb.Closed += flyout_Closed;
            fb.ShowAt(GetParent(d));
        }
        else
        {
            fb.Closed -= flyout_Closed;
            fb.Hide();
        }
    }

    private static void flyout_Closed(object sender, object e)
    {
        // When the flyout is closed, sets its IsOpen attached property to false.
        SetIsOpen(sender as DependencyObject, false);
    }

    public static void SetParent(DependencyObject element, FrameworkElement value)
    {
        element.SetValue(ParentProperty, value);
    }

    public static FrameworkElement GetParent(DependencyObject element)
    {
        return (FrameworkElement)element.GetValue(ParentProperty);
    }
}

This code adds an IsOpen Attached Property to flyout objects. When it changes (lines 22-39), we check whether we want to open or close the Flyout: in the first case, we call the ShowAt method (lines 32), that actually displays it. Since this method requires a FrameworkElement that represents the flyout’s placement target, we need also to specify the target control for the popup, so we have defined a Dependecy Property named Parent that holds the container of the Flyout. If, instead, we are about to dismiss the control, when IsOpen is set to false, we invoke its Hide method (line 37).

Note that we also need to register for the Closed event (line 31), that occurs when the flyout is hidden. The Flyout, in fact, implements the light-dismiss behavior: it can be closed simply touching anywhere on the screen outside of it, so it is necessary to handle the Closing event and set the IsOpen property to false, to reflect the correct state of the Flyout.

Now we can define a ViewModel like this:

public class MainViewModel : ViewModelBase
{
    private bool isOpen;
    public bool IsOpen
    {
        get { return isOpen; }
        set { this.Set(ref isOpen, value); }
    }

    public RelayCommand OpenCommand { get; set; }
    public RelayCommand CloseCommand { get; set; }

    public MainViewModel()
    {
        OpenCommand = new RelayCommand(() => IsOpen = true);
        CloseCommand = new RelayCommand(() => IsOpen = false);
    }
}

We have a command to open the Flyout (setting the IsOpen variable to true, line 15) and, similarly, a command to close it (line 16). In this way, in the View we can use the following XAML:

<Button Content="Open Flyout" x:Name="button" Command="{Binding OpenCommand}">
    <FlyoutBase.AttachedFlyout>
        <Flyout controls:FlyoutHelper.IsOpen="{Binding IsOpen, Mode=TwoWay}" 
                controls:FlyoutHelper.Parent="{Binding ElementName=button}">
            <StackPanel>
                <TextBlock Text="Awesome Flyout!" Margin="10" />
                <Button Content="Close" Command="{Binding CloseCommand}" 
                        HorizontalAlignment="Right" />
            </StackPanel>
        </Flyout>
    </FlyoutBase.AttachedFlyout>
</Button>

Moveover, using the Behavior SDK, we can use the same approach to attach a Flyout to any control:

<Page
    ...
    xmlns:i="using:Microsoft.Xaml.Interactivity"
    xmlns:core="using:Microsoft.Xaml.Interactions.Core"
    ...>

    ...
    <Image x:Name="image" Source="/Assets/Logo.scale-100.png" 
           Height="100" Width="100">
        <FlyoutBase.AttachedFlyout>
            <Flyout controls:FlyoutHelper.IsOpen="{Binding IsOpen, Mode=TwoWay}" 
                    controls:FlyoutHelper.Parent="{Binding ElementName=image}">
                <StackPanel>
                    <TextBlock Text="Awesome Flyout!" Margin="10" />
                    <Button Content="Close" Command="{Binding CloseCommand}" 
                            HorizontalAlignment="Right" />
                </StackPanel>
            </Flyout>
        </FlyoutBase.AttachedFlyout>
        <i:Interaction.Behaviors>
            <core:EventTriggerBehavior EventName="Tapped">
                <core:InvokeCommandAction Command="{Binding OpenCommand}" />
            </core:EventTriggerBehavior>
        </i:Interaction.Behaviors>
    </Image>
    ...
</Page>

The EventTriggerBehavior declared at lines 21-23 invokes the OpenCommand action as soon as the Tapped event raises. As seen before, this sets the IsOpen property of the ViewModel to true, so the Flyout attached property displays the popup.

Categories: .NET, C#, MVVM, Windows Phone, WinRT

Using “AndContinue” methods in Windows Phone Store apps with MVVM

07/01/2015 1 comment

As MSDN says, “Certain memory-intensive API on Windows Phone 8.1 contain AndContinue methods. When you call an AndContinue method, your app is deactivated while the operation completes in order to conserve memory. On low-memory devices, your app might even be terminated. Because of this possibility, you have to call different methods in a Windows Phone Store app than you call in a Windows Store app to continue your app after these operations.”.

This happens, for example, when we want to select an image using the FilePicker. On Windows Phone Store apps, we need to call the PickSingleAndContinue method. In this case, we have the problem to continue our apps after calling this method.

The topic How to continue your Windows Phone Store app after calling an AndContinue method on MSDN introduces the ContinuationManager, a class that works together with the SuspensionManager to make it easier to continue our app.

This code, however, is based on a code-behind approach. If we’re following the MVVM pattern, we need to change it in order to invoke continuation methods on a ViewModel. So, we can rewrite the Continue method as follows:

public class ContinuationManager
{
    // ...
    
    private FrameworkElement GetCurrentView()
    {
        var frame = Window.Current.Content as Frame;
        if (frame != null)
            return frame.Content as FrameworkElement;

        return Window.Current.Content as FrameworkElement;
    }

    internal void Continue(IContinuationActivatedEventArgs args)
    {
        var view = this.GetCurrentView();
        if (view == null)
            return;

        this.Continue(args, view.DataContext);
    }

    internal void Continue(IContinuationActivatedEventArgs args, object dataContext)
    {
        if (args == null)
            throw new ArgumentNullException("args");

        if (this.args != null)
            throw new InvalidOperationException("Can't set args more than once");

        this.args = args;
        this.id = Guid.NewGuid();

        if (dataContext == null)
            return;

        switch (args.Kind)
        {
            case ActivationKind.PickFileContinuation:
                var fileOpenPickerViewModel = dataContext as IFileOpenPickerContinuable;
                if (fileOpenPickerViewModel != null)
                    fileOpenPickerViewModel.ContinueFileOpenPicker
                        (args as FileOpenPickerContinuationEventArgs);
                break;

            case ActivationKind.PickSaveFileContinuation:
                var fileSavePickerViewModel = dataContext as IFileSavePickerContinuable;
                if (fileSavePickerViewModel != null)
                    fileSavePickerViewModel.ContinueFileSavePicker
                        (args as FileSavePickerContinuationEventArgs);
                break;

            case ActivationKind.PickFolderContinuation:
                var folderPickerViewModel = dataContext as IFolderPickerContinuable;
                if (folderPickerViewModel != null)
                    folderPickerViewModel.ContinueFolderPicker
                        (args as FolderPickerContinuationEventArgs);
                break;

            case ActivationKind.WebAuthenticationBrokerContinuation:
                var wabViewModel = dataContext as IWebAuthenticationContinuable;
                if (wabViewModel != null)
                    wabViewModel.ContinueWebAuthentication
                        (args as WebAuthenticationBrokerContinuationEventArgs);
                break;
        }
    }
}

The GetForCurrentView method, at lines 5-12, retrieves the view (i.e., the page) that is currently shown. Then, in the Continue method at lines 23-67, we check the Kind property of IContinuationActivatedEventArgs (that comes from the OnActivated method of App.xaml.cs file): based on its value, we try to cast the DataContext of the page (i.e., its ViewModel) to a particular interface (that is declared below in the file).

If the conversion succeeds, it means that the ViewModel supports this kind of continuation, so the corresponding method is invoked. For example, in case of PickFileContinuation (lines 39-44), we cast the DataContext to IFileOpenPickerContinuable and then call its ContinueFileOpenPicker method passing information about the selected file.

In this way, our ViewModel looks like (the example is based on MVVM Light):

public class PhotoViewModel : ViewModelBase, IFileOpenPickerContinuable
{
    private string photoPath;
    public string PhotoPath
    {
        get { return photoPath; }
        set { this.Set(ref photoPath, value); }
    }

    public RelayCommand SelectPhotoCommand { get; set; }

    public PhotoViewModel()
    {
        this.CreateCommands();
    }

    private void CreateCommands()
    {
        SelectPhotoCommand = new RelayCommand(() =>
        {
            // Calls the method that opens the FilePicker page.
            // When selected, the method "ContinueFileOpenPicker"
            // from IFileOpenPickerContinuable interface
            // will be invoked.
            var picker = new FileOpenPicker();

            picker.SuggestedStartLocation = PickerLocationId.PicturesLibrary;
            picker.SettingsIdentifier = "continuationmanagerdemo";
            picker.ViewMode = PickerViewMode.List;
            picker.FileTypeFilter.Add(".jpg");

            picker.PickSingleFileAndContinue();
        });
    }

    public void ContinueFileOpenPicker(FileOpenPickerContinuationEventArgs args)
    {
        // The "args" object contains information about selected file(s).
        if (args.Files.Any())
        {
            var file = args.Files[0];
            PhotoPath = file.Path;
        }
        else
        {
            PhotoPath = null;
        }
    }
}

The SelectPhotoCommand (lines 19-33) calls the FileOpenPicker.PickSingleFileAndContinue method, that opens a page allowing the selection of a file (a JPG image, in this case). Thanks to the ContinuationManager, as the ViewModel implements the IFileOpenPickerContinuable interface, the ContinueFileOpenPicker method will be automatically invoked when the user selects a file. We retrieve the first one and save its Path property, so we can show it, for example, in an Image control that is bound to it.

You can download a working example of the ContinuationManger with MVVM using the link below:

Using AndContinue methods in Windows Phone Store apps with MVVM

Categories: .NET, C#, MVVM, Windows Phone

Windows Phone and Mobile Services on ioProgrammo

24/10/2014 1 comment

A new article of mine has been published on n°194 of ioProgrammo (November/December 2014). This time I show how to create an agenda app for Windows Phone that uses an Azure Mobile Service with the .NET Backend.

ioProgrammo November/December 2014

ioProgrammo November/December 2014

DialogService in MVVM Light V5

14/10/2014 Comments off

Some days ago we talked about the new release of MVVM Light Toolkit and, in particular, we presented the new NavigationService.

The other service that is shipped with MVVM Light V5 is DialogService, that is able to show message dialogs in our apps. To use it, we simply need to register this type in the ViewModelLocator class:

public ViewModelLocator()
{
    ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);

    SimpleIoc.Default.Register<IDialogService, DialogService>();
    // Other registrations...

    SimpleIoc.Default.Register<MainViewModel>();
}

Basically, the IDialogService interface contains the ShowMessage method, with some overloads. For example:

public class MainViewModel : ViewModelBase
{
    private IDialogService dialogService;

    public RelayCommand TestDialogServiceCommand { get; set; }

    public MainViewModel(IDialogService dialogService)
    {
        this.dialogService = dialogService;

        TestDialogServiceCommand = new RelayCommand(async () =>
        {
            // Simple message without callback.
            await dialogService.ShowMessage("Simple message text", "Title");

            // Message with custom buttons and callback action.
            await dialogService.ShowMessage("Are you sure you want to continue?", 
                "Confirmation",
                buttonConfirmText: "Continue", buttonCancelText: "Discard", 
                afterHideCallback: (confirmed) =>
                {
                    if (confirmed)
                    {
                        // User has pressed the "confirm" button.
                        // ...
                    }
                    else
                    {
                        // User has pressed the "cancel" button
                        // (or has discared the dialog box).
                        // ...
                    }
                });
        });
    }
}

At line 15, we use the simplest version of ShowMessage: we just show a dialog box with a message and a title. Instead, the second example (lines 18-25) shows a message box with two buttons, Continue and Cancel; when the user taps one of them (or discard the question), the afterHideCallback action will be invoked. It will get a boolean parameter indicating if the “confirm” button (true) or the “cancel” button (false) was pressed (or if the dialog was discarded).

The IDialogService interface exposes also the ShowError method, that can be used to display information about an error (it accepts an Exception as first argument). However, we must notice that on some platforms, like Windows Store and Windows Phone, ShowError has the same output of ShowMessage (because these platforms don’t have the concept of error message box).

Categories: C#, MVVM, Windows Phone, WinRT

NavigationService in MVVM Light V5

10/10/2014 20 comments

Two days ago, at Xamarin Evolve conference in Atlanta, has been announced the availability of MVVM Light V5. This release contains interesting updates for Xamarin, as we can read in the official blog post.

Another important news is the inclusion of the INavigationService and IDialogService interfaces with corresponding implementations on supported platforms. They are objects that very often are created in each project, so now we can use the existing classes instead of creating new ones.

Let’s see how to use the INavigationService interface in our Universal Windows apps. First of all, we need to add a reference to MVVM Light V5 using NuGet:

Adding MVVM Light V5 to the project

Adding MVVM Light V5 to the project

Creating the NavigationService is straightforward. In the ViewModelLocator class we write something like this:

public ViewModelLocator()
{
    ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);

    var navigationService = this.CreateNavigationService();
    SimpleIoc.Default.Register<INavigationService>(() => navigationService);

    SimpleIoc.Default.Register<IDialogService, DialogService>();

    SimpleIoc.Default.Register<MainViewModel>();
    SimpleIoc.Default.Register<DetailsViewModel>();
}

private INavigationService CreateNavigationService()
{
    var navigationService = new NavigationService();
    navigationService.Configure("Details", typeof(DetailsPage));
    // navigationService.Configure("key1", typeof(OtherPage1));
    // navigationService.Configure("key2", typeof(OtherPage2));

    return navigationService;
}

In the CreateNavigationService method (lines 14-22), we create a new instance of the NavigationService class (that is contained in the new GalaSoft.MvvmLight.Views namespace). We need to call its Configure method to associate each page type with a key. For example, at line 17 we associate the Details key with the DetailsPage page. Then, in the class constructor, we register the INavigationService interface specifying the concrete object that must be returned when it is requested (line 6).

Now, we can define the MainViewModel as follows:

public class MainViewModel : ViewModelBase
{
    private INavigationService navigationService;

    public RelayCommand DetailsCommand { get; set; }

    public MainViewModel(INavigationService navigationService)
    {
        this.navigationService = navigationService;

        DetailsCommand = new RelayCommand(() =>
        {
            navigationService.NavigateTo("Details", "My data");
        });
    }
}

When the DetailsCommand command is executed, at line 13, we invoke the NavigateTo method on the INavigationService reference, specifying the key that corresponds to the page to navigate to (DetailsPage, in this example). We’re using simple strings to control the navigation, so ViewModels don’t need to know the Views that will be actually opened (and thus without breaking the MVVM pattern).

We’re calling an overload of the NavigateTo method that accepts an object parameter that will be passed to the OnNavigatedTo method of the requested page (in the Parameter property of NavigationEventArgs):

public sealed partial class DetailsPage : Page
{
    // ...

    protected override void OnNavigatedTo(NavigationEventArgs e)
    {
        var parameter = e.Parameter as string;  // "My data"
        base.OnNavigatedTo(e);
    }
}

Of course, as we’re following the MVVM pattern, we don’t want to use code-behind. So, the preferred approach to get navigation parameters is the one presented in the article Calling ViewModel methods in response to Page navigation events using MVVM Light in WinRT to automatically pass this parameter to the ViewModel.

Lastly, the INavigationService interface exposes also the GoBack method, that allows to return to the previous page in the navigation stack.

Categories: C#, MVVM, Windows Phone, WinRT
Follow

Get every new post delivered to your Inbox.

Join 36 other followers