WPF

DevExpress MVVM Framework. TaskbarButtonService, ApplicationJumpListService and NotificationService.

OTHER RELATED ARTICLES:

  1. Getting Started with DevExpress MVVM Framework. Commands and View Models.
  2. DevExpress MVVM Framework. Introduction to Services, DXMessageBoxService and DialogService.
  3. DevExpress MVVM Framework. Interaction of ViewModels. IDocumentManagerService.
  4. DevExpress MVVM Framework. Introduction to POCO ViewModels.
  5. DevExpress MVVM Framework. Interaction of ViewModels. Messenger.
  6. DevExpress MVVM Framework. Using Scaffolding Wizards for building Views.
  7. DevExpress MVVM Framework. Data validation. Implementing IDataErrorInfo.
  8. DevExpress MVVM Framework. Using DataAnnotation attributes and DevExpress Fluent API.
  9. DevExpress MVVM Framework. Behaviors.
  10. THIS POST: DevExpress MVVM Framework. TaskbarButtonService, ApplicationJumpListService and NotificationService.
  11. DevExpress MVVM Framework. Asynchronous Commands.
  12. DevExpress MVVM Framework. Converters.


In a previous post we mentioned three new services which made their way into 14.1. This post details their purpose and usage. These services will be available in both the free and commercial versions of the DevExpress MVVM Framework. If you don't have access to DevExpress controls, but would like to use our MVVM Framework, refer to this blog post to learn more about the free MVVM Framework.

You can find the Free DevExpress MVVM Framework on GitHub or download the NuGet package.

TaskbarButtonService

TaskbarButtonService is a simple, powerful service for customizing an application taskbar button. The service consists of several properties which when changed immediately update the taskbar button. You can dynamically animate a progress bar or set the button background to red (error), yellow (pause), etc.

buttons.shadow

The service is essentially a wrapper around the standard TaskbarItemInfo class and especially easy to use in the MVVM pattern to simplify taskbar button customizations from a ViewModel.

As with any MVVM service, you must first declare it in XAML.

<dxmvvm:Interaction.Behaviors>
    <dxmvvm:TaskbarButtonService/>
</dxmvvm:Interaction.Behaviors>

Now, write a backing POCO view model with a property of type ITaskbarButtonService.

public class ViewModel {
    protected virtual ITaskbarButtonService
        TaskbarButtonService { get { return null; } }
}

You can access this view model from XAML with POCO. POCO automatically generates a property getter to return the service instance we declared in XAML.

DataContext="{dxmvvm:ViewModelSource Type=local:ViewModel}"

Alternatively, without POCO, just inherit your ViewModel from ViewModelBase and declare the service property as follows

public ITaskbarButtonService TaskbarButtonService {
    get { return GetService<ITaskbarButtonService>(); }
}

You can display a progress bar as follows

TaskbarButtonService.ProgressState =
    TaskbarItemProgressState.Normal;
TaskbarButtonService.ProgressValue = 0.5;

Set the OverlayIcon property to set an icon to show over the button.

TaskbarButtonService.OverlayIcon = new BitmapImage(...);

These properties can be set from XAML, but since they're meant to be updated at runtime, setting them in code often makes more sense.

Apart from the button, the service can customize the window thumbnail displayed when the button is hovered.

Change the text in the hover popup by setting the Description property. Use the ThumbnailClipMargin property to control the window clipping of the thumbnail image. This may be useful for calling attention to a relevant section of the application window. For fine control over clipping, handle the ThumbnailClipMarginCallback event raised when the window is resized.

The following image is an example of clipping. The original window thumbnail is on the left and the clipped version is on the right.

clipped.shadow

It's useful for a media player or an instant messenger program to grant special control over the application without opening the application window. Taskbar thumb buttons, displayed while the taskbar button is hovered, provide this functionality.

taskbarbutton.main.shadow

Use the ThumbButtonInfos property to customize the thumb buttons of the taskbar.

<dxmvvm:TaskbarButtonService>
    <dxmvvm:TaskbarButtonService.ThumbButtonInfos>
        <dxmvvm:TaskbarThumbButtonInfo 
            ImageSource="/Images/Modules/icon-nav-employees-32.png"
            Command="{Binding NavigateCommand}"
            CommandParameter="Employees"
            Description="Employees"/>
        <dxmvvm:TaskbarThumbButtonInfo
            ImageSource="/Images/Modules/icon-nav-customers-32.png"
            Command="{Binding NavigateCommand}"
            CommandParameter="Customers"
            Description="Customers"/>
        ...
    </dxmvvm:TaskbarButtonService.ThumbButtonInfos>
</dxmvvm:TaskbarButtonService>

The CanExecute method of this command is respected, so buttons are disabled as appropriate.

Some auxiliary properties, not referenced above, are DismissWhenClicked, IsBackgroundVisible, IsEnabled, IsInteractive and Visibility.

Complete example.

ApplicationJumpListService

Windows 7 introduced a new taskbar feature called Jump Lists. A jump list pops up in response to upward swipes on the taskbar button. The jump list is generally useful for managing recent items and providing fast access to frequently used functionality without actually displaying the application. If the application is pinned to the taskbar, the user can still access the application jump list while the app is not running.

jump-list.shadow

Although WPF has enabled jump list customization for a long time, using this functionality within MVVM was never easy. A proper MVVM solution required writing your own service.

The standard WPF support for jump lists is also fairly basic. It doesn't allow for simply creating a new jump list item and registering a handler. You need to provide a path to an executable to start if the user clicks on the jump list item. This scatters the jump list logic all over the application – inevitably making it harder to develop in MVVM.

In light of these concerns, a comprehensive MVVM library should address these issues with a simple solution.

Our own ApplicationJumpListService is usable from a ViewModel, but that's not all it enables. The service also makes it easy to populate a jump list with items and their corresponding handlers. Each handler is a method in the ViewModel. There's no need to worry about parsing command line arguments and dispatching to the correct application instances. The service knows what instance owns that particular window and calls the handlers as needed.

When the user clicks a jump list item, its corresponding application is started (if it hasn't been started already), and the associated handler is called.

The most straightforward way to add items to a jump list is to specify it directly in XAML or use one of many available AddOrReplace method overloads of the IApplicationJumpList instance.

<dxmvvm:ApplicationJumpListService>
    <dxmvvm:ApplicationJumpTask
        Title="New Employee"
        Icon="/Images/icon-new-employee-16.png"
        Command="{Binding NewEmployeeCommand}"/>
    <dxmvvm:ApplicationJumpTask
        Title="Customers"
        Icon="/Images/Modules/icon-nav-customers-32.png"
        Command="{Binding NavigateCommand}"
        CommandParameter="Customers"/>
    <dxmvvm:ApplicationJumpTask
        Title="Opportunities"
        Icon="/Images/Modules/icon-nav-opportunities-32.png"
        Command="{Binding NavigateCommand}"
        CommandParameter="Opportunities"/>
</dxmvvm:ApplicationJumpListService>

It is important to keep in mind that the jump list is available even after the application exits, in which case the handlers attached to list items no longer exist. If an end-user then clicks a list item, the application that owns the list starts up. The application will execute the ApplicationJumpListService.Apply() method (either explicitly or via list items in XAML) to call any pending handlers. This means that you have to initialize the list every time the application starts.

Complete example.

NotificationService

Microsoft added a new notification system for Windows 8. The new toast notifications are unique to Windows Store Apps and are a must if you want to interact nicely with Windows Store Apps.

native-notifications.shadow

Unfortunately, it's tricky to use these notifications in desktop apps. First of all wrappers only exist for .NET 4.5, which many applications can't afford to target. An Application Model ID is also necessary to create a required shortcut – more over, this model ID can only be assigned programmatically. Finally, your customization options are limited; four very similar predefined templates are available and, in the case of a desktop application, even the notification background can't be changed.

We implemented our NotificationService to simplify matters. NotificationService operates in one of two modes. The native mode amounts to a wrapper around the Windows 8 native notifications, inheriting their pros and cons (including the restriction to four templates and a required shortcut).

Displaying native notifications requires some work. First, you need to create a shortcut. Doing so requires interacting with COM interfaces, not exposed in .NET, so we provide a helper method ShellHelper.TryCreateShortcut() to do just that. You can also create the shortcut in another way, most likely during the install process, but it's handy to call this method while developing.

If you call TryCreateShortcut() like this

ShellHelper.TryCreateShortcut("MyApplication_ID", "MyApplication", iconPath);

a new shortcut will appear inside the %APPDATA%\Microsoft\Windows\Start Menu\Programs directory.

The application ID is just a unique arbitrary string: by convention, it usually includes the application name. The second parameter is the shortcut name, displayed on the Start screen. Make sure you specify an iconPath because the system will use the shortcut icon to decide which notification background color to use.

More information on Application Model IDs is available on MSDN.

You can now use the service. Select a template and set other options in XAML

<dxmvvm:Interaction.Behaviors>
    <dxmvvm:NotificationService
        ApplicationId="MyApplication_ID"
        PredefinedNotificationDuration="Long"
        PredefinedNotificationTemplate="ShortHeaderAndLongText"/>
</dxmvvm:Interaction.Behaviors>

The notification templates are documented on MSDN here. We use different names for these templates for our NotificationTemplate enum.

public enum NotificationTemplate {
    LongText,
    ShortHeaderAndLongText,
    LongHeaderAndShortText,
    ShortHeaderAndTwoTextFields
}

We can display a predefined notification.

try {
    NotificationResult result = await NotificationService
        .CreatePredefinedNotification(headerLine, bodyLine, "")
        .ShowAsync();
    switch(result) {
        case NotificationResult.Activated:
            // the user clicked on the notification
            break;
        case NotificationResult.TimedOut:
            // the user ignored the notification
            break;
        case NotificationResult.UserCanceled:
            // the user dismissed the notification
            break;
        case NotificationResult.Dropped:
            // the notification wasn't shown as the queue is full,
            // you should show the notification again later
            break;
    }
} catch(AggregateException e) {
    // some error occurred
}

Native notifications are only supported on Windows 8 and later. Regardless, notifications will still appear when running your application on older versions of Windows. The notification will have a very similar appearance to a native Windows 8 notification. So NotificationService provides a generic API to display notifications in any version of Windows.

If you don't want to bother with a shortcut, and don't expect end-users to use Windows Store Applications much, you can opt out from native notifications. This eliminates the requirement to include a shortcut with the application ID. Set UseWin8NotificationsIfAvailable to false to never use native notifications.

Predefined notifications are great when you need to display basic notifications. But given the extensibility of WPF, it's only logical to provide full DataTemplate support instead of limiting customization to a few predefined options. Which leads us to custom notifications...

Custom notifications expose more settings than predefined notifications, and also accept a DataTemplate. The service can be customized in XAML.

<Style x:Key="CustomNotificationStyle" TargetType="ContentControl">
    <Setter Property="Width" Value="380"/>
    <Setter Property="Height" Value="100"/>
</Style>
...
<dxmvvm:Interaction.Behaviors>
    <dxmvvm:NotificationService
        CustomNotificationDuration="00:00:06.0"
        CustomNotificationPosition="BottomRight"
        CustomNotificationVisibleMaxCount="5"
        CustomNotificationStyle="{StaticResource CustomNotificationStyle}"
        CustomNotificationTemplate="{StaticResource CustomNotificationTemplate}"/>
</dxmvvm:Interaction.Behaviors>

You can show custom notifications as with predefined notifications.

NotificationResult result = await NotificationService
    .CreateCustomNotification(new CustomNotificationViewModel())
    .ShowAsync();

Note that the ViewModel passed as an argument is the DataContext for the data template.

This is how a custom notification might look like.

custom-notifications.shadow

Complete example.



		    
	    
Published Jul 25 2014, 08:40 AM by
Filed under: , , ,
Bookmark and Share

Comments

gabriel caro

Thank you a lot for this great and useful article. Maybe a link for Recent documents added or updates at main page will be useful for us.

Regards

César Qüeb

July 29, 2014 2:06 PM

gabriel caro

The supplied sample for NotificationService, does not work, always return "null" in the CustomNotificationService object, because it is never instantiated from service declared in the XAML side. The code that fixes the issue was:

[ServiceProperty(Key = "customNotificationService")]

public INotificationService CustomNotificationService

{

   get { return GetService<INotificationService>(); }

}

replacing original code:

[ServiceProperty(Key = "customNotificationService")]

protected virtual INotificationService CustomNotificationService { get { return null; } }

at ViewModel class.

Regards

César Qüeb

August 7, 2014 11:29 AM

Vladimir M (DevExpress)

Thanks for your feedback.

I've just reviewed the sample and can confirm that it works correctly, so I assume you encounter the issue while using NotificationService in your code.

Please make sure you create your ViewModel via the ViewModelSource static class (either in XAML or in code using the ViewModelSource.Create method). Without using ViewModelSource, the POCO mechanism won't work.

August 12, 2014 6:08 AM
LIVE CHAT

Chat is one of the many ways you can contact members of the DevExpress Team.
We are available Monday-Friday between 7:30am and 4:30pm Pacific Time.

If you need additional product information, write to us at info@devexpress.com or call us at +1 (818) 844-3383

FOLLOW US

DevExpress engineers feature-complete Presentation Controls, IDE Productivity Tools, Business Application Frameworks, and Reporting Systems for Visual Studio, along with high-performance HTML JS Mobile Frameworks for developers targeting iOS, Android and Windows Phone. Whether using WPF, ASP.NET, WinForms, HTML5 or Windows 10, DevExpress tools help you build and deliver your best in the shortest time possible.

Copyright © 1998-2016 Developer Express Inc.
All trademarks or registered trademarks are property of their respective owners