Tag Archives: MVVM

Create Rich Outlook Style Silverlight Application in Minutes

Recently I was assigned to create a simple Silverlight project that shows a list of data with full editing support. The first thing that comes to my mind is using the ClientUI project template as a first step to start working on this task.

After spending about 30 minutes trying all the project templates that come with Intersoft WebUI Studio 2011 R2 SP1, I decided to start the project using Intersoft ClientUI Ribbon Application template. This project template allows the creation of rich Silverlight application with rich Ribbon interface and integrated navigation interfaces.

Intersoft ClientUI Ribbon Application template is ideal to build business applications with relatively large modules and features. The template ships with predefined MVVM infrastructure that demonstrates how to use UXRibbonBar as a command placeholder that dynamically change its content based on the active module. It also includes fully-functional MVVM examples such as Mail and Calendar which are implemented with the advanced data controls available in ClientUI.

Building rich application using this Ribbon project template is easy and straightforward. In this blog post, I’ll share some of my experiences building the project such as adding the navigation, customizing the ribbon through XML configuration file, and drop-in the data grid to display data.

Let’s get started!

Creating a new project from the Ribbon Application project template

We’ll start by creating a new Silverlight project using Intersoft ClientUI Ribbon Application project template. This project template is available after install the Premier edition or Intersoft WebUI Studio 2011 R2 (or newer) for Silverlight and WPF. To create a new Intersoft ClientUI Ribbon Application project, open Visual Studio and select File > New > Project… (or press Ctrl+Shift+N) from the menu bar. Select Intersoft ClientUI Ribbon Application from New Project window. Enter the appropriate details to create the new application project.

One nice feature of Intersoft project template on New Project window of Visual Studio is that you can have the Intersoft project template grouped under Intersoft Solutions node of Installed Templates tree view.

Intersoft ClientUI Ribbon Application Project Template

The project template contains several predefined configuration, assembly references, and code files such as Assets, Factory, Selectors and several XAML files. Click here to learn more about the structure of this project template.

When you run the project for the first time, you’ll see a fully-functional user interface such as shown below.

Project's User Interface

Creating Inventory UXRibbon Structure

I’m going to add a new module which will show list of products. The module will have its own ribbon bar control which employs three buttons: add new data; edit selected item; and delete selected item.

Inventory Module Ribbon Button

Three image files are added into the [SilverligthProject]\Assets\Images\Inventory folder as the icon for each of the button.

<?xml version="1.0" encoding="utf-8" ?>
<RibbonBar Name="Inventory">
  <RibbonTab Header="Home" IsSelected="True"
             ResizeOrder=""
             KeyTipAccessText="H">
    <RibbonTabGroup Name="Edit" Header="Products" MinimumSize="Large" IsCollapsible="false"
                    Icon="/ClientUIRibbon1;component/Assets/Images/Inventory/Inventory.png">
      <RibbonButton Content="Add New" MinimumSize="Large" TooltipHeader="New Item" TooltipContent="Create a New Item."
                    LargeIcon="/ClientUIRibbon1;component/Assets/Images/Inventory/AddExistingStandard_32.png"/>
      <RibbonButton Content="Edit" MinimumSize="Large" TooltipHeader="Edit Selected Item" TooltipContent="Edit Selected Item."
                    LargeIcon="/ClientUIRibbon1;component/Assets/Images/Inventory/Edit32.png"/>
      <RibbonButton Content="Delete" MinimumSize="Large" TooltipHeader="Delete Selected Item" TooltipContent="Delete Selected Item."
                    LargeIcon="/ClientUIRibbon1;component/Assets/Images/Inventory/Delete.png"/>
    </RibbonTabGroup>
  </RibbonTab>

</RibbonBar>

Instead of declaring the ribbon structure directly in the xaml page, the ribbon structure is defined in an xml file, RibbonInventoryData.xml. The file is located inside the [SilverlightProject]\Assets\Data folder.

RibbonFactory.cs class will read each element, attributes of the xml file; parse them to the appropriate object; and create the ribbon to be displayed.

Once the ribbon structure is configured, we need to initialize the ribbon data source and register the Inventory module so that the ribbon tab will be dynamically updated when user select Inventory module.

To initialize the ribbon data source, find InitializeRibbonBar() method in the RibbonPageViewModel.cs class and add a line as shown in the following code. *The class can be found in [SilverlightProject]\ViewModels folder.

private void InitializeRibbonBar()
{
    // Initializes application menu
    this.RibbonApplicationMenu = RibbonFactory.CreateMenu(RibbonDataFolder + "RibbonBarData.xml");

    // Initializes ribbon data sources
    this.RibbonData = new Dictionary<ModuleType, string>();
    this.RibbonData.Add(ModuleType.Overview, "RibbonOverviewData.xml");
    ...
    this.RibbonData.Add(ModuleType.Inventory, "RibbonInventoryData.xml");
}

Before running the project and showing the ribbon structure of Inventory module, we need to register the Inventory module in the UpdateRibbonTab method. UpdateRibbonTab is the method that will be invoked when users select a module.

internal void UpdateRibbonTab(ModuleType moduleType, object context)
{
    ...

    switch (moduleType)
    {
        case ModuleType.Calendar:
        case ModuleType.Contacts:
        case ModuleType.Inventory:
        case ModuleType.Mail:
            this.RibbonContextualGroups = RibbonFactory.CreateRibbonContextualTabGroups(RibbonDataFolder + this.RibbonData[moduleType]);
            this.RibbonTabs = RibbonFactory.CreateRibbonTabs(RibbonDataFolder + this.RibbonData[moduleType], context);
            break;

        default:
            this.RibbonTabs = RibbonFactory.CreateRibbonTabs(RibbonDataFolder + this.RibbonData[ModuleType.Overview], context);
            break;
    }

    this.ActiveModule = moduleType;
}

Save all the changes and run the Silverlight application project.

The ribbon structure for Inventory module has been successfully added. When users click/select the Inventory module from the navigation pane, the Add New button; Edit button; and Delete button will be shown.

UXRibbon for Inventory Module

Displaying The Product List with UXGridView

In this part, we are going to display a list of products. The list will be presented in an UXGridView control.

In this project, UXGridView is bound to WCF RIA Services. In this post, I will not describe in detail about how to configure the application to become WCF RIA Services-enabled; creating the data model; etc. I’d like to suggest you to refer to Intersoft ClientUI MVVM Data Application (WCF RIA SP1) project template. To learn more, see Walkthrough: Create New Intersoft ClientUI MVVM Data Application (WCF RIA SP1) Template.

Once the data repository of Products is completely added, Add UXGridView control and bind the ItemsSource property with Items property from ProductsViewModel; and bind each column of the UXGridView to their corresponding property of ProductsViewModel respectively.

<Intersoft:UXGridView Intersoft:DockPanel.IsFillElement="True" ItemsSource="{Binding Path=Items}"
                        AutoGenerateColumns="False">
    <Intersoft:UXGridView.Columns>
        <Intersoft:UXGridViewTextColumn Header="Category ID" Binding="{Binding CategoryID}"/>
        <Intersoft:UXGridViewTextColumn Header="Product ID" Binding="{Binding ProductID}"/>
        <Intersoft:UXGridViewTextColumn Header="Product Name" Binding="{Binding ProductName}"/>
        <Intersoft:UXGridViewTextColumn Header="Unit Price" Binding="{Binding UnitPrice}"/>
        <Intersoft:UXGridViewTextColumn Header="Units In Stock" Binding="{Binding UnitsInStock}"/>
        <Intersoft:UXGridViewTextColumn Header="Units On Order" Binding="{Binding UnitsOnOrder}"/>
        <Intersoft:UXGridViewTextColumn Header="Quantity Per Unit" Binding="{Binding QuantityPerUnit}"/>
    </Intersoft:UXGridView.Columns>
</Intersoft:UXGridView>

Save all the changes and run the project.

UXGridView in Inventory Module

The Inventory module now has had a ribbon structure and will display a list of product in the ContentFrame.

Adding Commanding and Enabling/Disabling UXRibbon Button Based on UXGridView Selected Item.

In this part, I’d like to set the enable/disable state of each ribbon button based on the selected item of UXGridView. By default, the Add New UXRibbonButton is enabled since user should be able to add new item at any time. When no item is selected in UXGridView, Edit and Delete button should be disabled. They will be enabled when item(s) are selected.

In UXGridView, when a row is selected, the SelectedItem property will be automatically synchronized. I can bind this property to my ViewModel to capture the currently selected item. This property is then converted to a Visible/Collapsed and then consumed by IsEnabled property of UXRibbon button to determine whether the UXRibbon button is enabled or not.

Several questions arise when I started to check the feasibility to implement this approach.

  • The Inventory.xaml page and the UXRibbon are located in different view. Each of them has their own ViewModel. Implementing converter seems not as easy as I thought earlier.
  • The xml file of ribbon structure is processed by RibbonFactory.cs class by implementing parser. I need to ensure whether the ribbon button parser is equipped with binding parser or not.

I’m pretty sure there must be an elegant solution for a simple scenario such as this. So I decided to explore this project and hope to find an example that can be applied to my scenario.

After spending about 15 minutes exploring the project, clues are spotted when Mail module is opened. Some of the ribbon buttons are disabled when no message is selected.

This is exactly what I’m looking for!

It turns out that DelegateCommand play an important role in such scenario as shown in the Mail module. ClientUI provides DelegateCommand, a specialized command object that can be used to handle a delegate directly in the view model, and still can be bound to the view through binding. Furthermore, the DelegateCommand takes advantage of the routed command concept in which the IsEnabled state of the command sources will be automatically synchronized depending on whether the command can execute.

Many thanks to ClientUI development team who has extended the commanding framework to support MVVM through built-in DelegateCommand class. Not only this, they also have made this project template brilliantly. I mean it and don’t intend to exaggerate about what I say. Building Silverlight application based on Intersoft’s project template is considerably easy, even for beginners. I started to learn the implementation of DelegateCommand on Mail module and reset the plan to implement this scenario to be as follow.

There are three UXRibbon button: Add New; Edit; and Delete. Each button is bound to the AddAction; EditAction; and DeleteAction DelegateCommand respectively.

RibbonInventoryData.xml

<?xml version="1.0" encoding="utf-8" ?>
<RibbonBar Name="Inventory">
  <RibbonTab ...>
    <RibbonTabGroup Name="Edit" ...>
      <RibbonButton Content="Add New" MinimumSize="Large" TooltipHeader="New Item" TooltipContent="Create a New Item."
                    LargeIcon="/ClientUIRibbon1;component/Assets/Images/Inventory/AddExistingStandard_32.png"
                    Command="{Binding AddAction}" CommandParameter="AddNew"/>
      <RibbonButton Content="Edit" MinimumSize="Large" TooltipHeader="Edit Selected Item" TooltipContent="Edit Selected Item."
                    LargeIcon="/ClientUIRibbon1;component/Assets/Images/Inventory/Edit32.png"
                    Command="{Binding EditAction}" CommandParameter="Edit"/>
      <RibbonButton Content="Delete" MinimumSize="Large" TooltipHeader="Delete Selected Item" TooltipContent="Delete Selected Item."
                    LargeIcon="/ClientUIRibbon1;component/Assets/Images/Inventory/Delete.png"
                    Command="{Binding EditAction}" CommandParameter="Delete"/>
    </RibbonTabGroup>
  </RibbonTab>
  ...  
</RibbonBar>

ProductsViewModel.cs

public class ProductsViewModel : EditableGridViewModelBase<Product>
{
    public ProductsViewModel()
    {
        this.AddAction = new DelegateCommand(AddCommandAction, CanAddAction);
        this.EditAction = new DelegateCommand(EditCommandAction, CanEditAction);
        this.DeleteAction = new DelegateCommand(DeleteCommandAction, CanDeleteAction);
    }

    public DelegateCommand AddAction
    {
        get;
        set;
    }

    public DelegateCommand EditAction
    {
        get;
        set;
    }

    public DelegateCommand DeleteAction
    {
        get;
        set;
    }

    ...

    private bool CanAddAction(object obj)
    {
        //this method validate whether or not AddNew button is active
        //In this sample, I will keep this button to be always active
        return true;
    }

    private bool CanEditAction(object obj)
    {
        if (this.SelectedProductItem != null)
            return true;
        return false;
    }

    private bool CanDeleteAction(object obj)
    {
        if (this.SelectedProductItem != null)
            return true;
        return false;
    }

    private void AddCommandAction(object obj)
    {
        MessageBoxServiceProvider.Show("add new row is performed", "Information",
                    Intersoft.Client.UI.Aqua.UXDesktop.MessageBoxButton.OK, Intersoft.Client.UI.Aqua.UXDesktop.MessageBoxImage.Information, null);
    }

    private void EditCommandAction(object obj)
    {
        MessageBoxServiceProvider.Show("edit selected row is performed", "Information",
                    Intersoft.Client.UI.Aqua.UXDesktop.MessageBoxButton.OK, Intersoft.Client.UI.Aqua.UXDesktop.MessageBoxImage.Information, null);
    }

    private void DeleteCommandAction(object obj)
    {
        MessageBoxServiceProvider.Show("delete selected row is performed", "Information",
            Intersoft.Client.UI.Aqua.UXDesktop.MessageBoxButton.OK, Intersoft.Client.UI.Aqua.UXDesktop.MessageBoxImage.Information, null);
    }
}

Binding Command to UXRibbonButton

In the next series of my blog post, I will add a final touch to this Ribbon application by displaying detail information of data (for adding and editing operation) in a form.

Download Sample Code

For your reference, the demo project can be downloaded here.

I hope that this project will help you to prepare a simple demo project and provide you with insights about how easy to start developing Silverlight project using Intersoft Silverlight project template.

I’d love to hear your feedback so be sure to drop your comments in the box below.

Regards,
Yudi

ClientUI 7 Preview Part 1: Built-in IoC Containers

Since its debut two years ago, ClientUI has been designed to facilitate application development toward loose coupling approach. This can be seen from the comprehensive MVVM-ready components and application framework included in ClientUI, then followed with the introduction of Event Aggregator in the latter release. In addition, most of our samples and tutorials are built with the MVVM design pattern as well. In the upcoming releases, we’ll take the design pattern to the next level by introducing a lightweight IoC container which is integrated to many important aspects of the ClientUI application framework.

In this blog post, I’m excited to share what ClientUI has to offer in the next major release. I will focus on the framework enhancements and new advanced library specifically designed to enable you write maintainable code with maximum loose coupling. Before I introduce these new libraries, I’ll discuss the basic purposes of the loose coupling design pattern, so you can see what the new library does, and how it addresses the programming challenges.

Dependency Injection Demystified

Unless you write prototypes or applications that never make it past release 1, you’ll
soon find yourself maintaining and extending existing code bases. To be able to work
effectively with such a code base, it must be as maintainable as possible. One of many ways to make code maintainable is through loose coupling. In short, the main point is that loose coupling makes code extensible, and extensibility makes it maintainable.

One of many techniques to enable loose coupling is Dependency Injection (often called as DI). A lot have been said and written about DI these days – it’s fascinating how most of these literatures make DI sound so complicated, yet it’s really simple in reality. Powerful yet simple. In this blog post, I hope to be able to give a decent and clear explanation about DI and its main concept, and how it differs from Inversion of Control (IoC).

Let’s dive in. Assume you run a new business that started using PayPal as your payment provider. Naturally, you’ll create a website that processes the transactions online, hence the following code.

public class MyStore
{
    public bool ProcessTransaction(Transaction trans)
    {
        PayPalPaymentProcessor paymentProcessor = new PayPalPaymentProcessor();
        return paymentProcessor.ProcessPayment(trans);
    }
}

The code above is very simple and straightforward, and does the job pretty well. First, it instantiates a new PayPalPaymentProcessor class and then call the ProcessPayment method. Nothing’s wrong.

As your business grows, you’d like to switch to different payment processor (or add a new option), let’s pick Google Checkout as an example. To make this happen, it’s obvious that you’ll have to find the piece of code that processes the transaction, modify the code to introduce the new payment option and rebuild your project. You’ll probably come up with the following results.

public class MyStore
{
    public bool ProcessTransaction(string type, Transaction trans)
    {
        if (type == "PayPal")
        {
            PayPalPaymentProcessor paymentProcessor = new PayPalPaymentProcessor();
            return paymentProcessor.ProcessPayment(trans);
        }
        else if (type == "Google")
        {
            GooglePaymentProcessor paymentProcessor = new GooglePaymentProcessor();
            return paymentProcessor.ProcessPayment(trans);
        }
        else
        {
            throw new ArgumentException("Payment processor not supported", "type");
        }
    }
}

Again, there’s nothing wrong with the code above as it does the job pretty well. However, doing the job well doesn’t always mean it has met the requirements to build good applications, for instances, in terms of maintainability and extensibility. In the case above, the code wasn’t really maintainable as you have to repetitively make changes on the same piece of code when you add new payment processors. This, naturally, makes your application more difficult to extend, not to mention if you want to hand over the code to be maintained by different developers.

Architecturally, the main problem with the code above is the referenced dependencies where the MyStore class depends on the concrete payment processor class such as PayPalPaymentProcessor or GooglePaymentProcessor. The concrete type dependency makes it impossible for you to plug-in new payment processors without modifying the code. So what we’re going to do next is take out the dependencies and revamp our code into the following.

public class MyStore
{
    public MyStore(IPaymentProcessor paymentProcessor)
    {
        if (paymentProcessor == null)
            throw new ArgumentNullException("paymentProcessor");

        this.PaymentProcessor = paymentProcessor;
    }

    public bool ProcessTransaction(Transaction transaction)
    {
        return this.PaymentProcessor.ProcessPayment(transaction);
    }

    protected IPaymentProcessor PaymentProcessor { get; set; }
}

Now what do you think? Looks much neater and easier to read, isn’t it? In the code above, the dependencies to the concrete types have been eliminated and replaced by the interface abstraction of the payment processor. The MyStore class now requires the payment processor to be passed in the constructor, which is a common technique known as constructor injection while the Guard in the constructor ensures a valid instance of payment processor is passed, thus ensuring the availability of the payment processor when consumed throughout the methods in the class. Ultimately, this resolution also addresses the extensibility issue as you can now instantiate the payment service externally and simply pass-in the instance.

In essence, the technique of passing (or injecting) the instance (PaymentProcessor) on to the depending class (MyStore) class is called Dependency Injection.

As we’ve just demystified the DI concept, it’s now becoming clear that DI has nothing to do with Inversion of Control (IoC) or any other programming frameworks, although in reality, both are often paired together to achieve the ultimate design goal – “Loose Coupling”.

At this point, still using the payment service scenario above, you will likely consume the MyStore class by instantiating it through manual construction. At the simplest, the code will look like:

public class MainPageViewModel : ViewModelBase
{
    private void ExecuteProcess()
    {
        MyStore myStore = new MyStore(new PayPalPaymentProcessor());
        myStore.ProcessTransaction(transaction);
    }
}

While the code above is much neater and easier to read, there’s still one last problem that violates the law of loose coupling design pattern. Without you realizing it, the MainPageViewModel class (the consumer) now depends on two classes: MyStore and PayPalPaymentProcessor.

Eliminating the dependencies completely in such scenario can be achieved by inverting the flow of control of the system in a way where the objects and its dependency graphs can be instantiated through an external assembler. This technique is called Inversion of Control (further abbreviated as IoC), and that’s where the IoC containers comes into the picture.

IoC Container Comes to the Rescue

IoC is a design pattern that inverts the flow of the application logic, which is achieved through the use of Dependency Injection for its binding process. This approach allows maximum loose coupling where dependencies can be minimized or completely eliminated. This also means that such code allows great extensibility as the concrete implementation can be easily swapped at runtime.

The payment service scenario earlier with the state where it left off is perfectly ideal for our IoC example, so let’s move on revamping our code and see what IoC container has to offer, see the following code.

public class MainPageViewModel : ViewModelBase
{
    private void ExecuteProcess()
    {
        IStore store = Container.Resolve<IStore>();
        store.ProcessTransaction(transaction);
    }
}

To remove dependencies on concrete implementation, one of the common approaches is by abstracting the implementation into abstract class or interface, as shown in the code above. Leveraging IoC container in this piece of code enables us to resolve an instance of the concrete store implementation – anywhere and anytime when required in the business logic flow – without knowing the exact type that contains concrete implementation. This is so powerful because it allows you to change the concrete implementation externally without ever touching this piece of code.

At the heart of IoC container are the Register and Resolve methods, which perform the following:

  • Register: Register a dependency by associating the abstract type or interface to the concrete type
  • Resolve: Resolve an instance of the dependency by looking up the exact registration in the container

Most of the dependency registrations are usually done in a centralized place, commonly invoked when the program initializes. This centralized place is called Composition Root, which allows you to manage the composition of all components and services in a single place. Using the payment service scenario above, the registration looks like the following.

public class AppInitializer : IApplicationInitializer
{
    public void Initialize(ApplicationPackage package)
    {
        IDependencyContainer container = UXShell.Current.Container; // or new IocContainer() for standalone container;

        // Register the IStore interface to compose a new PayPalPaymentProcessor through a direct construction
        container.Register<IStore>(o => new MyStore(new PayPalPaymentProcessor()));
    }
}

The code above is self explanatory – it registers the IStore interface type to a function that returns a new MyStore class complete with the required dependencies which is the PayPalPaymentProvider in this case.

The IoC container along with a set of comprehensive APIs are the new libraries introduced in next major release of ClientUI. It features full-blown IoC container features yet lightweight enough to deliver high-performing and scalable applications. At a glance, the key features are:

  • High-performance object factory
  • Abstract and interface type resolution
  • Open generic support
  • Instance-based resolution
  • Lazy resolution
  • Named containers
  • Lifetime Manager

Integration with ClientUI Application Framework

The IoC container implemented in the ClientUI Framework supports both standalone usage and integration with UXShell. For most common scenarios, it’s recommended that you use the default container instance which is accessible from the shell’s RootApplication.Container property. Using this approach enables you to resolve the registered dependencies anywhere in your code, including the dynamic XAP applications that are loaded on demand at runtime. Click here to learn more about ClientUI Application Framework.

In addition, the application framework now introduces a built-in bootstrapper to facilitate the dependencies composition and registration. Simply add a class that implements IApplicationInitializer interface in your Silverlight project, the Initialize method will be invoked as the application starts. In dynamic XAP scenario, the Initialize method will be automatically invoked when the XAP package is downloaded and loaded to the application domain.

Download Sample Code

In summary, the combination of design pattern best practices – such as MVVM, Event Aggregator, Dependency Injection and Inversion of Control – along with extensible application framework enable you to build great business applications that are easily maintainable and extensible. We see this as important milestones in our development roadmap as we geared our tools toward enterprise and line-of-business apps.

Another important point to keep in mind is that these design patterns aren’t exclusive only for Silverlight or WPF platforms although I picked Silverlight for the samples. We will bring forward these patterns to new platforms as they become available.

To test drive the DI concept and IoC container, I’ve prepared a small Silverlight sample that demonstrates how to achieve good architectural design by implementing Inversion of Control through Dependency Injection. The download package also includes the developer preview version of ClientUI Framework. Click here to download the sample package, and feel free to ask any questions or provide feedback in the comment box below.

In the next series of my blog post, I’ll discuss about several interesting new stuff such as View Regions, View Discovery and View Injection – and how they play well with IoC containers. Stay tuned.

Warning: Do not use the preview Framework assembly in your “live” projects as it will cause version incompatibility issues with the other assemblies in the current release.

All the best,
Jimmy
Chief Software Architect

Introducing Event Aggregator in ClientUI 5 SP1

In my recent blog posts, I have covered two of the major new features introduced in ClientUI 5 service pack 1. Check out my post for LightSwitch support here, and the real-time streaming capability in XPS Document Viewer here.

Since its debut last year, ClientUI has been well recognized not only with its amazing and beautiful user interface controls, but also a rock-solid framework that built the foundation of the entire control library. ClientUI was the first in the industry that pioneering the adoption of MVVM design pattern in both Silverlight and WPF application, as well as setting new standards for MVVM-ready control architecture. Click here to read the overview of MVVM development, and here for in-depth technical details.

ClientUI supports MVVM development through comprehensive built-in libraries such as delegate command, command reference, and advanced data binding support. This allows developers to build full-blown MVVM applications without any third party frameworks. Confused which MVVM framework to choose, or should you roll out your own? Check out Bill’s latest blog post as he shares his journey finding one that works best for him.

In this blog post, I will discuss about one of the top requested features that we’ve added in the latest service pack release. I’m pleased to introduce our advanced event aggregator library, now built right into the ClientUI Framework. Let’s start with the basics.

Event Aggregator Basics

One of the key principles of MVVM development is data binding. And data binding is all about communication.  By the means of communication, it is exactly how the View talks to the ViewModel for user interaction, and how the ViewModel talks to the Model for data processing and transactions. What’s really cool is that one layer doesn’t require dependencies to another thus enabling great separation of concern that yield some real benefits as detailed here.

As you’re building MVVM applications toward more complex requirements, you will eventually find certain scenarios where the communication flow becomes too difficult to achieve. This is particularly true for scenarios that require communication across different ViewModels; or across different modules in a large, composite application.

Consider a basic scenario where you have a data grid that displays member list and a form to edit the selected member. With MVVM pattern, you will create two distinct ViewModels, one for the member list and another for the editing form. Now consider a quite common business requirement where the member list should be refreshed whenever a member is updated. How would you achieve such requirement? What options do you have? Let’s explore the possibilities.

It’s natural to think about using standard CLR event as your first bet since that’s the only built-in event handling available in .NET Framework. While you’re declaring the new events, you will realize that you’re going to create dependencies between these ViewModels because CLR event requires strong reference to the target instance. Consequently, it will add significant maintenance overhead in the long run.

The second approach, you can create a parent-child link between the two ViewModels and simply call the method in the parent from the child ViewModel. This might seem to work at first, but you will soon realize the shortfall as more ViewModels are required to link to the parent. Although there could be workarounds such as interface refactoring, this approach is definitely still far from ideal.

Since we’re unable to find a solid solution in the existing framework, we need a better design pattern that dictates how event communication works – one that allows the event to be listened and raised across different ViewModels without strong type reference; and more importantly, one that works consistently, reliably and easy to maintain in the long run. That event pattern is so-called Event Aggregator.

Event Aggregator addresses the challenges above by allowing a ViewModel to listen to an event without strong referencing to the target ViewModel. This means that there could be multiple ViewModels listening to an event at the same time, and the event can also be raised from different ViewModels – all without requiring the knowledge of existence of one and another.

See the following illustration to get the big picture of Event Aggregator’s conceptual view.

EventAggregator Overview

At this point, I hope you already get some insights on the key challenges around communication flow in MVVM, and understand why Event Aggregator is needed.

Usage and Examples

ClientUI 5 service pack 1 includes a built-in event aggregator service that works consistently in both Silverlight and WPF – and certainly, with the same API. ClientUI’s event aggregator is implemented accordingly to match Martin Fowler’s description and concept of an event aggregator.

ClientUI’s event aggregator is designed to be simple and easy-to-use, yet powerful enough to cover a number of advanced scenarios. It takes only a single line of code to subscribe to an event, the same is true for the event publication. See the following examples.

// Subscribe to an event
EventAggregator.Default.Subscribe<MailNotificationEvent, Mail>(OnMailReceived);

// Publish an event
EventAggregator.Default.Publish<MailNotificationEvent, Mail>(this.MailEntity);

As shown in the above example, the event aggregator is designed with default static instance allowing developers to subscribe or publish an event in code-efficient manner. Both the Subscribe and Publish methods comprised of two generic parameters for the method signature which are TEventType and TPayLoad. The TEventType represents the type of the event to subscribe or publish, while the TPayLoad represents the type of the message to pass to the event.

In summary, at the heart of ClientUI’s event aggregator is the six methods listed below. You basically deal with three things, subscribing to an event, publishing an event, and unsubscribe from a previous subscription.

public TEventType GetEvent<TEventType>() 
                   where TEventType : DelegateEventBase, new();

public void Publish<TEventType, TPayload>(TPayload payload) 
                   where TEventType : DelegateEventBase, new();

public SubscriptionToken Subscribe<TEventType, TPayload>(Action<TPayload> action) 
                   where TEventType : DelegateEventBase, new();

public SubscriptionToken Subscribe<TEventType, TPayload>(Action<TPayload> action, SubscribeOptions options) 
                   where TEventType : DelegateEventBase, new();

public SubscriptionToken Subscribe<TEventType, TPayload>(Action<TPayload> action, SubscribeOptions options, 
                   Predicate<TPayload> filter) where TEventType : DelegateEventBase, new();

public void Unsubscribe<TEventType, TPayload>(Action<TPayload> action)
                   where TEventType : DelegateEventBase, new();

In addition, ClientUI’s Event Aggregator also supports several advanced features such as event filtering, use background thread, reference keep alive and more. However, we don’t include the support for UI thread invocation which is intentionally decided. The reason is that accessing the View (UI) in the ViewModel would break the nature of MVVM which emphasizes on clear separation, hence the decision is consistent with our goal to build libraries that enforce design pattern and development best practices.

To wrap up this post, I’ve prepared a reference sample that demonstrates how event aggregator works in the simplest way. I chosen the mail notification scenario for this sample where the notification event is subscribed and published from different ViewModel instances, see the following illustration.

Event Aggregator Sample

Finally, download the sample bits and get yourself familiar with the event aggregator basics. The sample package includes both Silverlight and WPF projects which demonstrate the event aggregator using the same codebase. Again, please make sure you have ClientUI 5 SP1 installed to enjoy this new addition, or click here to download it.

As usual, I welcome any questions and feedback. Please drop them in the comment box. Thanks!

Best,
Jimmy

ClientUI 5: Unlock The Amazing Possibilities

The latest ClientUI brings so many new innovations and technology advancement available no-where else. The release debuts with a host of various data visualization controls like grid view, tree view, document viewers, and more. Even better, the deep integration with IdeaBlade’s DevForce provides the fastest way to build MVVM-enabled business applications. All of this innovations are geared towards a better development experience to build any business applications of any size and any complexity.

In this blog post, I will review the new shinny samples demonstrating the new products and the features, as well as sharing my top favorite new samples.

Below are the top 10 my favorite picks of new ClientUI 5 samples

  1. Assets Management

    The assets managements sample is a good demonstration of the latest UXGridView with many features enabled such as Column Freezing, data grouping, column sorting, and the powerful data editing capability.

    Data editing is a crucial feature in any grid view control. You can add a new row, edit, or delete a row. UXGridView extends this behavior further with many innovative features such as custom editing control, data validation, read-only binding, value list, and more.

    Read-only binding is a unique feature that lets you lock certain columns or a row based on a column’s edited value. For example when an asset status is sold, the Service Date column is lock for editing. Value list is a unique feature which translates a foreign key column into a more meaningful data. For example Department column refers to DepartmentId from  Department table. Instead of showing the number, the department name is showed instead. This feature also works with data editing.

    In addition, various user experience features are also demonstrated like column freezing, paging, and more. UXGridView’s column freezing is closely similar to the on in Excel. You can lock certain columns from the left side and prevent it from being horizontally scrolled when the available viewport can’t accommodate all columns. Explore the sample.Assets management with rich UI/X features

  2. eMagazine Viewer
    Like to read books, magazine in your portable inch+ thick digital reader? With the latest XPSDocumentViewer, you can add the same rich reading experience to your Silverlight or WPF applications. Try to click on the Browse Library to select and load different magazine.
     
    The high-performance rendering engine displays the document brilliantly. Images are vibrant and text is crisp. Especially when using the various zooming feature, you will notice that the document is displayed at its best quality even during the zooming process. Explore the sample.e-Magazine Reader
     
  3. Getting Started Viewer
    If the above scenario shows XPSDocumentViewer loading rich media content, this specific sample demonstrate its powerful multiple page document loading capability without any slow down.
     
    The innovative feature behind all this is the load-on-demand engine. It prioritizes visible pages to be loaded and rendered while the rest are loaded conditionally. Another great feature is the background loading. It allows pages to be preloaded in the background during application’s idle time. In this sample, you will notice that both document and applications is loaded at the same time.
     
    You should try the built-in page navigation. There are two types, thumbnail and outline. Thumbnail mode displays a small preview image of every page, while outline provide the entire document’s TOC hierarchically (depending on the document’s structure). Explore the sample.Getting Started Document Viewer
     
  4. Baseball Player
    Rejoice baseball fan, now you can see your all-time favorite baseball player attractively in UXGridView. Try to select a row and notice that the detailed information is displayed under. This row detail feature is enhanced with selector functionality to easily incorporate certain business rules. You can also change the row detail behavior, whether it is shown all the time or on selected item only. Explore the sample.UXGridView Baseball Sample
  5. Employee Leave Records
    One of the most unique sample in UXGridView is the Employee Leave Records – emphasizing on the grid’s various data interaction features. Click on the filter button on a column to reveal the filter box. You can use the check box to filter the row or type, or use type in the textbox to narrow down the available filter options.
     
    Sorting feature is available out-of-the-box controlled by a property. In addition to single column sorting, UXGridView is enhanced to support multiple sorting. Click on the first column to sort. Hold shift and click on the second column, and so on. To change the sort direction, click on the same column while holding shift to maintain the multiple sorting behavior or UXGridView will discard the previous sorting order.
     
    The loosely coupled architecture adoption enables users to externally execute certain grid view features. The most notable implementation is the Export and Refresh button. The default location is on the grid footer, but in this sample a second button is added above the grid.
     
    Try the sample here to discover more features.Employee Leave Records
     
  6. My Outlook
    UXNavigationPane is a flexible, space-saving navigation control adopted after Office 2010. User can easily collapse the entire control to when more screen estate is required and restore it when needed. It also feature real-time resizing feature with “snapping” feature. You can also try to explore various pane items and see its content. Explore the sample.My Outlook
     
  7. Corporate File Explorer
    In most business applications, tree view is often used as the primary navigation system for its hierarchical display – enabling users to directly jump into a sub page. And in most cases, it gets sluggish when the structure gets too complex with many nodes.
     
    This sample demonstrates UXTreeView with its blazing-fast loading regardless of the structure. Using a custom Load-on-Demand technique, UXTreeView allows developer to custom-code the child node retrieval process. When enabled, the expand toggle indicator will be shown. Explore the sample.File Explorer
  8. Online Book Store
    Despite the nature as a navigation control, UXTreeView can be used to display a list of items in hierarchical order, just like the following online book store sample. User can use the checkbox to select or deselect the desired category.
     
    UXTreeView’s checkbox is designed to accommodate non-linear structure selection with three-state mode, checked, unchecked, and indeterminate. Indeterminate is a state indicating a parent, whose child nodes are partially checked. If all child nodes are selected, the parent’s checked status is checked. You can also check on the parent to select all of its child nodes. Explore the sample.TreeView Bookstore
     
  9. My Tasks and Events
    This “My Tasks and Events’ sample uses UXTreeView as its category navigator. Click on a node to select different category. You can also move an event to different category by dragging it and drop it on the desired node. Explore the sample.My Events
     
  10. Order List
    This sample demonstrates UXGridView displaying data in hierarchical order. Depending on your data structure, you can have unlimited nested table with on-demand data retrieval. You can click on the plus sign to expand the child table.This sample also demonstrate the visual customizability. You can easily experiment and apply any custom color and theme to UXGridView, for example the black color. Explore the sample.UXGridView OrderList

Above are only some small collection of business-inspiring samples featured on ClientUI live demo page. Please visit live.clientui.com to experience all. Want to build an amazing application such as shown above? Grab the 30-day trial now. Existing customers with valid subscription can obtain the latest WebUI Studio from Developer Network, under My Components shortcut.

Happy developing.

Best regards,
Jemmy Haryono

Get Started with ClientUI 5

Now that ClientUI 5 is officially released and the new license keys are delivered, you’ve got the most comprehensive and  powerful tools in your fingertips. The first thing you will be doing after installation is probably to figure out what you can do with the new ClientUI. There are really a lot of exciting and never-before-possible capabilities that you can now add to your business applications. Let’s take a look at some of them in this blog post.

Discover the New Possibilities

I have been extensively blogging about UXGridView in the past several months since it was in the planning phase and all the time through the CTP and beta releases. There are many other new controls that are not less important in this new release which I haven’t been blogging about before due to the milestone readiness. It’s now the time to discover all these exciting new tools.

At a glance, the ClientUI 5 release is strongly focused on essential line-of-business controls which consisted of three key areas: high-performance data presentation, advanced navigation, and rich document controls. Let’s start from the document controls.

Silverlight Document Management Made Easy

I’ve been often asked by business friends and clients, “What’s the best way to store our corporate documents and make them available for rich viewing in client apps?” And some often added with “And ones that support printing, zooming and navigation?”. Some geeks would add another requirement, “And definitely one that supports cross-platform development”. Wow, I think these are all interesting stuff, yet challenging. I couldn’t satisfy everyone with a confident single answer back then – because it was never been done before.

Earlier this year, I sat down with our top engineers discussing these business challenges and we don’t even have ideas if such capabilities can be done at that time. And today, I’m excited that we have turned these dreams into reality – thanks to the team’s great passion and high dedication to defy the challenges found all the way during the development until it’s delivered today.

Introducing ClientUI document controls, this brand-new lineup includes a range of feature-rich document viewers, engineered from the bottom-up with a solid architecture to allow room for future extensibility. That said, these viewers aren’t merely fancy controls with sleek toolbars and glassy interface. They are built on the top of document framework, a set of comprehensive document interface and APIs that the viewers understand.

Enough introduction, so what can you do with these document controls, you might asked. There are a lot to say – from presenting sales invoices, project plans, business documents to high-fidelity chart reports. The fact that Microsoft has been working hard to bring XPS to becoming an industrial standard for easy document exchange has further confirmed the adoption of using XPS as the first-class document format in business organization. Essentially, all documents in the form of XML Paper Specification (XPS) are supported – whether they are produced from Microsoft Word, Powerpoint, or Excel; or generated by the XPS Printer Writer which is installed in both Windows Vista and Windows 7 by default.

The ClientUI document viewer lineups such as XPSDocumentViewer enables not only pixel-perfect document viewing, but also WYSIWYG printing. This means that whatever you seen in the screen should print out exactly the same in 1:1 ratio, which makes it ideal for online business document sharing. See an example below.

Online document sharing made easy

Sharing a knowledge base document with rich content makes much sense as well, such as a comprehensive getting started. Thanks to the state-of-the-art virtual rendering, working with a large multi-page document won’t slow down your apps at all.

Getting started document

More importantly, XPSDocumentViewer includes world-class user interface that matches the industry’s popular readers such as Adobe PDF Reader. As shown above, it has a sleek navigation pane supporting thumbnails and outlines navigation mode, search box, minimalistic tool bar, and rich controls such as dropdown and slider for easy zooming. And of course, view presets is also supported, including fit to width, fit to height and actual size mode.

Furthermore, the page canvas, resizable layout concept, industrial theme with natural design and subtle drop shadow effect have all been thoughtfully designed by our experienced UX artists – ensuring the best viewing experiences for your users. And for you, developers, that means you can just drop an instance of the viewer in your apps, set the source and deploy.

We shipped a host of business-inspiring samples that showcase the key features of the document viewers. You can access and try all of them here.

So with all these compelling solutions available, the answer to earlier questions is now obvious. And if you’re either asked or tasked with the similar requirements, you know you can count on ClientUI’s rich document controls.

Complex Navigation Interface Simplified

As the leading UI tools provider, we aren’t merely creating new controls without prior knowing the nature and concept of the design patterns, unlike many other competing vendors. Since the invention of ClientUI, we’ve been extensively focusing in UI design patterns and create tools that uniquely and consistently satisfy the UI requirements of line-of-business application development.

With design patterns, we have a solid answer for everything. If you wanted to create a rich MDI application, use our windowing and dock interface. If you wanted to create a rather classical SDI application, use a simple list for navigation. For containers, choose either group box, expandable group box, or accordion; while using toolbar and status bar for commands interaction. As we’re also providing UI/UX consultant and professional services, we have most UI patterns well predefined to be able to address clients’ requirements that are specific to their business.

In this new release, we’ve developed a new pattern targeting medium to big-sized applications that employ complex and hierarchical navigation. That said, three new controls have been introduced, a hierarchical tree view, a resizable container, and a versatile navigation pane.

The combination of these three new controls, and together with ClientUI’s powerful navigation framework, enable you to create immersive business applications that “scale” along with the growth of your business. The scope of the “scale” here may be too general, so let’s scope it in the context of user interface and navigation. The essence of the scalable navigation support means that you can create applications with fewer modules/features initially and add them later without have to revamp the entire navigation and user interface.

Naturally, this means that your navigation interface should employ a fluid design pattern, where new modules can be consistently accessible regardless of the real screen estate. Here is the true challenge, because real screen estate has limitation. Another challenge is that the real screen estate might be various depending on the user’s display device. Users with larger resolution display will expect to see more navigation items, while users with lower resolution will expect the screen estate that arranged accordingly and makes sense to them. This is what fluid design pattern is all about – smartly adapting to the environment while still consistent in function and behaviors.

Our solution to the fluid design requirements above is the UXNavigationPane control. You can place any number of navigation items to the control as you desire. If the screen estate is not sufficient, they will overflow to the footer area, and smartly hidden when the footer area is full which is easily accessible through the context menu. See an example of a UXNavigationPane below.

UXNavigationPane displays navigation items in fluid fashion

Notice that each navigation item can consisted of sub navigation items. This design provides an elegant solution to nearly all complex navigation challenges. For instances, you can use a simple flat list for one-level sub navigation. If you need a two-level sub navigation, use UXAccordion. Or if you need a nested hierarchical sub navigation, use UXTreeView.

This navigation control is also very versatile in the way that you can resize, expand and collapse it to maximize real screen estate. You can still access the navigation item’s content through the “Quick Access” button. See the illustration below.

Versatile navigation pane control

Finally, this navigation pane control is unlike the others in the market in many ways such as the support for real navigation functionality. Most of the similar controls I seen provide only the “UI” part, which means you can click an item to reveal its content. True, you can also put sub navigation controls like buttons or treeviews. But they aren’t real navigation controls, which means that they won’t let you navigate to a specific page, or have the items synchronized with the current navigation state.

What’s really cool in UXNavigationPane and also one of my favorite features is the fully-functional navigation features in addition to the sleek and fluid user interface. This means that clicking on “Mail” item would let you navigate to Mail.xaml with a simple NavigateUri definition. It also adheres to the entire ClientUI navigation framework, where you can specify a friendly address instead of raw address, such as /Mail/Inbox to go the Mail page with Inbox selected.

Not only that. UXNavigationPane can also intelligently synchronize its user interface elements based on the current navigation state consistently – all without additional code. It’s so smart that it will not only synchronize the first level state of the navigation item – but also the sub navigation item that matches the current navigation state. For users, this means that they can access the applications in the way they expected it to be. Typing /Contacts in the address bar to go to contacts, typing /Documents/Corporate to see all business documents, or loading the Mail from browser’s bookmark for an instant access to inbox. See the following illustration for details.

Automatic navigation synchronization

You can browse many of the new navigation control samples from the ClientUI Showcase.

As a business application developer, these are exactly the tools I need and the one that I will seriously invest and use in my mission-critical applications. Why? Because it lets me focus on what’s matter the most – the business requirements – I don’t have to write even single code to maintain the navigation stuff. And more importantly, it enables me to rapidly create pages without have to concern about code maintenance, because there’s no code needed to maintain. I could create as much as XAML pages, bind them to the Source, design the View and bind them to the ViewModel and entities – and get my tasks done in realistically shorter time frame.

I hope this post gives some insights on what you can do with ClientUI 5. In my next post, I will delve into more learning resources and development aspects using Visual Studio. For now, feel free to expand your creativity and get ready to create your next-generation applications with amazing user experiences. Click here to get your trial copy of ClientUI 5. For technical support, please post your questions to Intersoft ClientUI Forum.

Best,
Jimmy

Use UXSliderBar to Simplify Data Entry

One of the powerful controls introduced in ClientUI 4 is UXSliderBar, an input control that enables users to select a value or range of values by sliding the UXThumb along the slider track through drag and drop operation in the thumb.

In this post, I will share how to use UXSliderBar to create a simple application to input grade for student.

Configuring the UXSliderBar

The scenario that I want to achieve is, create a sliderbar and set the value from 0 to 100. When user selects a value in the slider (let’s say 60, 85), the grade (A, B, C, D) will be displayed in the TextBox based on the selected value.

First of all, drag a UXSliderBar control from Visual Studio Toolbox. You need to configure its basic settings, such as Maximum, Minimum, SmallChange, and LargeChange.

Minimum and Maximum property indicates the possible lowet and highest value in the slider bar. SmallChange and LargeChange indicates the value to be added or subtracted from the value of UXSliderBar.

<Intersoft:UXSliderBar Minimum="0" Maximum="100" LargeChange="10"
                       SmallChange="1" TickPlacement="BottomRight"
                       HandlesVisibility="Visible"/>

UXSliderBar1

As you can see, the value becomes crowded because I want to display the value range from 0 to 100. This is where Ticks property is very useful. It is used to represent the position of the tick bar items displayed in the tick bar.

I’m going to set the ticks to 0, 55, 65, 75, 85. Therefore, the UXSliderBar will display something like following:

<Intersoft:UXSliderBar Minimum="0" Maximum="100" LargeChange="1"
                       SmallChange="0.1" TickPlacement="BottomRight"
                       HandlesVisibility="Visible" Ticks="0 55 65 75 85"/>

UXSliderBar2

In the case where the ticks are only displayed in specific positions, it is difficult to select a specific value, for example 79, in the slider bar. Using AutoTooltipVisibility property, you can display a tooltip containing the selected value when you drag the thumb. In addition, AutoTooltipFormat is used to set the format string applied to the content of the tooltip.

<Intersoft:UXSliderBar Minimum="0" Maximum="100" LargeChange="1"
                       SmallChange="1" TickPlacement="BottomRight"
                       HandlesVisibility="Visible" Ticks="0 55 65 75 85"
                       AutoTooltipVisibility="Visible"
                       AutoTooltipFormat="F0"/>

UXSliderBar3

Initially, when you bind the value from UXSliderBar into the Textbox control, it will only display the number. In this case, I want to show the Grade instead. Means that I need to add a converter in order to achieve this scenario.

Creating Grade Converter

In order to show the grade in Textbox, we need to bind slider’s value to Textbox and use data conversion to convert the grade into string.

Here is the code on how to bind the slider’s value to Textbox.

<TextBox Text="{Binding Value, ElementName=UXSliderBar1}" />

Now, you have successfully bound slider’s value to Textbox. But, in order to convert the number into string, you need to add a converter.

For more information on how to use a converter, please refer to Data Binding Overview on Data Conversion topic.

I create a class called GradeConverter.cs. In this class, I will create a converter by creating a class that inherits from IValueConverter and put a validation to convert the grade value into a string.

The GradeConverter.cs looks like the following:

using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Data;

namespace ClientUIMVVMBlogApp.Converters
{
    public class GradeConverter : IValueConverter
    {
        public object Convert(object value, Type targetType,
                              object parameter,
                              System.Globalization.CultureInfo culture)
        {
            Double grade = (Double)value;
            String result = value.ToString();

            if (grade < 55)
            {
                result = "E";
            }

            else if (grade >= 55 && grade < 65)
            {
                result = "D";
            }

            else if (grade >= 65 && grade < 75)
            {
                result = "C";
            }

            else if (grade >= 75 && grade < 85)
            {
                result = "B";
            }

            else
            {
                result = "A";
            }
            return result;
        }

        public object ConvertBack(object value, Type targetType,
                                  object parameter,
                                  System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
}

Now, add the converter to the Textbox control that has been bound to the slider’s value:

<TextBox Text="{Binding Value, ElementName=UXSliderBar1,
                Converter={StaticResource GradeConverter}}"/>

There are some properties that you can optionally add to the UXSliderBar such ValueRangeVisibility and IsMoveToPointEnabled. ValueRangeVisibility is used to get/set whether the value range visual element is visible. You can see the value range visual element is in blue color.

IsMoveToPointEnabled is used to get/set a value that indicates whether the UXThumb moves immediately to the location of the mouse click that occurs while the mouse pointer pauses on the slider bar track.

Hence, the final code will look like following:

<StackPanel>
   <Intersoft:FieldLabel>
      <Intersoft:FieldLabel.Header>
         <TextBlock Text="Name :"/>
      </Intersoft:FieldLabel.Header>
      <TextBox Width="200" Text="John Doe"></TextBox>
   </Intersoft:FieldLabel>
   <Intersoft:FieldLabel>
      <Intersoft:FieldLabel.Header>
         <TextBlock Text="Grade :"/>
      </Intersoft:FieldLabel.Header>
      <StackPanel Orientation="Horizontal">
         <Intersoft:UXSliderBar Name="UXSliderBar1" Width="517"
                                Minimum="0" Maximum="100" LargeChange="1"
                                SmallChange="0.1" TickPlacement="BottomRight"
                                HandlesVisibility="Visible"
                                ValueRangeVisibility="Visible" Value="55"
                                AutoTooltipVisibility="Visible"
                                AutoTooltipFormat="F0" Ticks="0 55 65 75 85"
                                IsMoveToPointEnabled="True" Height="50" />
         <TextBox Height="27" Width="33" HorizontalAlignment="Left"
                  Text="{Binding Value, ElementName=UXSliderBar1,
                         Converter={StaticResource GradeConverter}}"/>
      </StackPanel>
   </Intersoft:FieldLabel>
</StackPanel>

When you run the project, the final results will look like the following illustration.
UXSliderBar control

When you drag the slider bar to determine the value, it will automatically convert the value into string, and place the grade into the Textbox.

Summary

In this post, you have learned how to initially create UXSliderBar and configure its basic settings. You also have been guided on how to create data conversion and bind it to a Textbox control.

For more information about the scenario, you can download the sample here. To see all available features, see UXSliderBar Overview. If you have questions or feedback about UXSliderBar or other ClientUI controls, please feel free to post them to our Community Forum.

Regards,

-Martin-

UXGridView Part 4: Data Editing the MVVM-way with Commands

In the previous post, Jimmy announced the latest CTP for UXGridView with the CUD (Create, Update and Delete) capability. In this post, I will provide the step-by-step instructions to work with these new features.

Enabling the CUD capability

First of all, let’s enable the CUD (Create, Update, Delete) capability in UXGridView. You can enable these features by simply setting the CanUserAdd, CanUserEdit, and CanUserDelete properties to True.

<Intersoft:UXGridView CanUserAdd="True" 
                      CanUserDelete="True" 
                      CanUserEdit="True"/>
        

Notice that there will be a NewRow element at the top of the Grid when you set the CanUserAdd property to True.

Furthermore, you can also delete or edit the selected item(s) when the CanUserEdit or CanUserDelete properties are set to True.

To edit a row you can use either mouse or keyboard. The following list shows you some configuration that you can change to edit a record using mouse / keyboard.

To edit a row using mouse:

  • EditMouseGesture
    • Single Click

      Directly begin edit to the current selected cell.

    • Second Click

      Begin edit to the current selected cell after the row is selected.

    • Double Click

      Directly begin edit to the current selected cell when double click fires.

To edit a row using keyboard:

  • EditKeyGEditKeyGesture
    • F2

      Directly begin edit to the current selected cell using F2 key.

    • Any Keystroke

      Directly begin edit to the current selected cell from any key stroke.

  • EnterKeyAction
    • EnterEdit

      Directly begin edit to the current selected cell using Enter key.

    • MoveToNextRow

      Move to next row (does not edit the cell).

  • EditEnterKeyAction
    • CommitAndMovetoNextRow

      Commit the changes at current edited row and move to the next row.

    • ExitEdit

      Exit the cell edit of the current edited cell.

    • MoveToNextEditableCell

      Move to next editable cell. (Will move to next row’s cell when it reach the end of the row)

Beside these options, you can also use several common keystroke as listed below during editing.

  • Tab / Shift + Tab

    To move to next / previous editable cell.

  • Shift + Enter

    Commit the changes at current edited row and stay in the current selection

  • Delete

    Delete the current selected record(s)

  • Escape

    Cancel current changes. If currently you are in an active edit cell, it will cancel the cell changes. If you are in current active edit row, it will cancel the row changes.

Handling the CUD operation

To handle the CUD operation, UXGridView provides several command-related properties that you can specify to execute a method depending on the actions. These command- properties are listed as follows:

  • PrepareNewRowCommand

    Called when you begin edit at the NewRow element. Used to initialized the NewRowItem.

  • ValidateRowCommand

    Validate the row before the row is committed.

  • InsertRowCommand

    Called when a new row is committed. You can directly save the changes and/or refresh the UXGridView if necessary.

  • UpdateCellCommand

    Called when the cell is committed.

  • UpdateRowCommand

    Called when an existing row is committed. You can directly save the changes and/or refresh the UXGridView if necessary.

  • DeleteRowCommand

    Called when a row is deleted. You can directly save the changes and / or refresh the UXGridView if necessary.

  • RejectRowCommand

    Called when the changes in the row is cancelled. This command is used to reject the changes in the data entity if required (such as in DevForce).

  • SaveChangesCommand

    Called when the save changes command is executed. You handle this command to save all the pending changes made in the UXGridView.

  • RejectChangesCommand

    Called when the reject changes command is executed. You handle this command to reject all the pending changes made in the UXGridView.

These command properties can be bound to your ViewModel using delegate command. Next, I will show you how to bind these commands along with some important properties that are necessary for the CUD operation.

Binding the CUD Commands to UXGridView using MVVM Pattern

Let’s create the ViewModel for our example. First, define the delegate commands and the required selection properties, then instantiate them in the constructor.

using System.Collections;
using Intersoft.Client.Framework;
using Intersoft.Client.Framework.Input;
using Intersoft.Client.UI.Data;
using UXGridView.Samples.ModelServices;

namespace UXGridView.Samples.ViewModels
{
    public class ServerEditingViewModel : ServerSideOperationViewModel
    {        
        public ServerEditingViewModel()
            : base()
        {            
            this.DeleteRowCommand = 
                new DelegateCommand(ExecuteDeleteRow);
            this.InsertRowCommand = 
                new DelegateCommand(ExecuteInsertRow);
            this.PrepareNewRowCommand = 
                new DelegateCommand(ExecutePrepareNewRow);
            this.UpdateCellCommand = 
                new DelegateCommand(ExecuteUpdateCell);
            this.UpdateRowCommand = 
                new DelegateCommand(ExecuteUpdateRow);
            this.RejectRowCommand = 
                new DelegateCommand(ExecuteRejectRow);
            this.RejectChangesCommand = 
                new DelegateCommand(ExecuteRejectChanges);
            this.SaveChangesCommand = 
                new DelegateCommand(ExecuteSaveChanges);
            this.ValidateRowCommand = 
                new DelegateCommand(ExecuteValidateRow);
        }

        #region Fields

        private bool _hasChanges;
        private bool _isRefreshed;        
        private object _newProduct;
        private object _selectedProduct;
        private IEnumerable _selectedProducts;

        #endregion

        #region EditableProductsSource

        private IEditableDataRepository EditableProductsSource
        {
            get
            {
                return this.ProductsSource as IEditableDataRepository;
            }
        }

        #endregion

        #region Selection and Editing Properties

        public object NewProduct
        {
            get { return this._newProduct; }
            set
            {
                if (this._newProduct != value)
                {
                    this._newProduct = value;
                    this.OnPropertyChanged("NewProduct");
                }
            }
        }

        public object SelectedProduct
        {
            get { return this._selectedProduct; }
            set
            {
                if (this._selectedProduct != value)
                {
                    this._selectedProduct = value;
                    this.OnPropertyChanged("SelectedProduct");
                }
            }
        }

        public IEnumerable SelectedProducts
        {
            get { return this._selectedProducts; }
            set
            {
                if (this._selectedProducts != value)
                {
                    this._selectedProducts = value;
                    this.OnPropertyChanged("SelectedProducts");
                }
            }
        }

        public bool IsRefreshed
        {
            get { return this._isRefreshed; }
            set
            {
                if (this._isRefreshed != value)
                {
                    this._isRefreshed = value;
                    this.OnPropertyChanged("IsRefreshed");
                }
            }
        }

        public bool HasChanges
        {
            get { return _hasChanges; }
            set
            {
                if (_hasChanges != value)
                {
                    _hasChanges = value;
                    OnPropertyChanged("HasChanges");
                }
            }
        }

        #endregion

        #region Commands

        public DelegateCommand DeleteRowCommand { get; set; }
        public DelegateCommand InsertRowCommand { get; set; }
        public DelegateCommand PrepareNewRowCommand { get; set; }
        public DelegateCommand UpdateCellCommand { get; set; }
        public DelegateCommand UpdateRowCommand { get; set; }
        public DelegateCommand RejectRowCommand { get; set; }
        public DelegateCommand RejectChangesCommand { get; set; }
        public DelegateCommand SaveChangesCommand { get; set; }
        public DelegateCommand ValidateRowCommand { get; set; }

        #endregion
    }
}
    

Next, we will bind these commands to the UXGridView.

<Intersoft:UXPage 
	xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
	xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
	xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
	xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
	mc:Ignorable="d"
	xmlns:Intersoft="http://intersoft.clientui.com/schemas"
          xmlns:IntersoftModel="clr-namespace:Intersoft.Client.Data.Component
Model.CollectionViews;assembly=Intersoft.Client.Data.ComponentModel" xmlns:ViewModels="clr-namespace:UXGridView.Samples.ViewModels" x:Class="UXGridView.Samples.Views.ServerSideOperation.Editing" Title="Editing Page" d:DesignWidth="1024" d:DesignHeight="800"> <Grid x:Name="LayoutRoot"> <Grid.DataContext> <ViewModels:ServerEditingViewModel/> </Grid.DataContext>
<Intersoft:DockPanel> <Intersoft:UXGridView AutoGenerateColumns="False" QueryOperation="Server" CanUserPage="True" PageSize="20" RowHeaderVisibility="Visible" IsBusy="{Binding IsBusy, Mode=TwoWay}" IsRefreshed="{Binding IsRefreshed, Mode=TwoWay}" ItemsSource="{Binding Products}" SortDescriptors="{Binding QueryDescriptor.SortDescriptors, Mode=TwoWay}" PageDescriptor="{Binding QueryDescriptor.PageDescriptor}" GroupFootersVisibility="Visible" GroupByBoxVisibility="Visible" CanUserAdd="true" CanUserDelete="true" CanUserEdit="true" NewItem="{Binding NewProduct, Mode=TwoWay}" SelectedItem="{Binding SelectedProduct, Mode=TwoWay}" ValidateRowCommand="{Binding ValidateRowCommand}" InsertRowCommand="{Binding InsertRowCommand}" DeleteRowCommand="{Binding DeleteRowCommand}" PrepareNewRowCommand="{Binding PrepareNewRowCommand}" UpdateCellCommand="{Binding UpdateCellCommand}" UpdateRowCommand="{Binding UpdateRowCommand}" SaveChangesCommand="{Binding SaveChangesCommand}" RejectRowCommand="{Binding RejectRowCommand}" RejectChangesCommand="{Binding RejectChangesCommand}" HasChanges="{Binding HasChanges}"> <Intersoft:UXGridView.GroupDescriptors> <Intersoft:UXGridViewGroupDescriptor PropertyName="CategoryID"/> </Intersoft:UXGridView.GroupDescriptors> <Intersoft:UXGridView.Columns> <Intersoft:UXGridViewTextColumn Header="Category ID" Binding="{Binding CategoryID}"/> <Intersoft:UXGridViewTextColumn Header="Product ID" Binding="{Binding ProductID}" IsReadOnly="True" Aggregate="Count" FooterFormatString="Count = {0}"/> <Intersoft:UXGridViewTextColumn Header="Product Name" Binding="{Binding ProductName}"/> <Intersoft:UXGridViewTextColumn Header="Units In Stock" Binding="{Binding UnitsInStock}" Aggregate="Max" FooterFormatString="Max = {0}"/> <Intersoft:UXGridViewTextColumn Header="Unit Price" Binding="{Binding UnitPrice}" Aggregate="Avg" FooterFormatString="Avg = {0:n2}"/> <Intersoft:UXGridViewTextColumn Header="Units On Order" Binding="{Binding UnitsOnOrder}" Aggregate="Min" FooterFormatString="Min = {0}"/> <Intersoft:UXGridViewTextColumn Header="Quantity Per Unit" Binding="{Binding QuantityPerUnit}"/> </Intersoft:UXGridView.Columns> </Intersoft:UXGridView> </Intersoft:DockPanel> </Grid> </Intersoft:UXPage>

Handling the CUD Operation in ViewModel Using DevForce

After the commands are bound to the ViewModel, it is up to you how you want to handle the CUD operation.

If you prefer to automatically update the records after each CUD operation, you can do that in the InsertRowCommand, UpdateRowCommand and DeleteRowCommand respectively, and probably followed up by RefreshCommand to refresh the data. However, if you prefer a batch update, you can notify the UXGridView by setting the HasChanges property to True, and later call the SaveChanges method to perform the batch update.

This batch update capability might not be available in all data providers such as WCF RIA. When you enable server query in WCF RIA such as paging, sorting, and filtering; you always get a new fresh data from the database regardless of the changes in the client. This behavior is due to the WCF RIA not supporting client-side caching. In this case, you might want to do automatic update and/or refresh after each CUD operation. There are samples that show how to do this in our CTP package.

Next, I will show you how to handle the CUD Operation in the ViewModel. To save time, I will only cover the one using DevForce which allows you to enable batch update.

Since the sample used ProductsRepository to encapsulate all data operation, I’ll show you first what I’m doing in the ProductsRepository.

using System;
using System.Collections;
using System.ComponentModel;
using IdeaBlade.EntityModel;
using IdeaBlade.Validation;
using Intersoft.Client.Data.ComponentModel;
using Intersoft.Client.Data.Provider.DevForce;
using UXGridView.Samples.Data.DevForce;

namespace UXGridView.Samples.ModelServices
{
    public class ProductsRepository : IEditableDataRepository
    {
        public ProductsRepository(NorthwindEntities entityManager)
        {
            this.Manager = entityManager;
        }

        private static IDataRepository _repository;

        public static IDataRepository Instance
        {
            get
            {
                return _repository ?? (_repository = CreateRepository());
            }
            set
            {
                _repository = value;
            }
        }

        private NorthwindEntities Manager { get; set; }

        public static IDataRepository CreateRepository()
        {
            return new ProductsRepository(EntityManager.Create());
        }

        public void GetData(Action<IEnumerable> onSuccess, 
Action<Exception> onFail) { this.Manager.Products .ExecuteAsync( op => { if (op.CompletedSuccessfully) { if (onSuccess != null) onSuccess(op.Results); } else { if (onFail != null) { op.MarkErrorAsHandled(); onFail(op.Error); } } } ); } public void GetData(QueryDescriptor queryDescriptor, Action<IEnumerable> onSuccess, Action<int> onItemCountRetrieved, Action<Exception> onFail) { this.Manager.Products.OrderBy(p => p.ProductID).Parse(queryDescriptor) .ExecuteAsync( op => { if (op.CompletedSuccessfully) { if (onSuccess != null) onSuccess(op.Results); if (onItemCountRetrieved != null) onItemCountRetrieved(-1); // not applicable; } else { if (onFail != null) { op.MarkErrorAsHandled(); onFail(op.Error); } } } ); } public void GetTotalItemCount (QueryDescriptor queryDescriptor, Action<int> onSuccess) { var op = this.Manager.Products .Parse(queryDescriptor, false).AsScalarAsync().Count(); op.Completed += (o, e) => { if (onSuccess != null) onSuccess(e.Result); }; } public void Insert(object entity) { this.Manager.AddEntity(entity); } public void Delete(IList entities) { foreach (object o in entities) { this.Delete(o); } } public void Delete(object entity) { Product product = entity as Product; product.EntityAspect.Delete(); } public void RejectChanges() { this.Manager.RejectChanges(); } public void SaveChanges( Action onSuccess, Action<Exception> onError) { this.Manager.SaveChangesAsync ( op => { if (op.IsCompleted) { if (op.HasError) { // handle error op.MarkErrorAsHandled(); onError(op.Error); } else { onSuccess(); } } }, null ); } public object Create() { return this.Manager.CreateEntity<Product>(); } public void Validate(object entity) { Product product = (Product)entity; product.EntityAspect.ValidationErrors.Clear(); product.EntityAspect.VerifierEngine.Execute(product); if (product.CategoryID < 1 || product.CategoryID > 8) product.EntityAspect.ValidationErrors .Add(new VerifierResult( VerifierResultCode.Error, "Specified CategoryID does not exist", new string[] { "CategoryID" })); if (product.UnitPrice < 0) product.EntityAspect.ValidationErrors .Add(new VerifierResult (VerifierResultCode.Error, "Unit Price can not be less than 0", new string[] { "UnitPrice" })); if (product.UnitsInStock < 0) product.EntityAspect.ValidationErrors .Add(new VerifierResult( VerifierResultCode.Error, "Units in Stock can not be less than 0", new string[] { "UnitsInStock" })); if (product.UnitsOnOrder < 0) product.EntityAspect.ValidationErrors .Add(new VerifierResult( VerifierResultCode.Error, "Units on Order can not be less than 0", new string[] { "UnitsOnOrder" })); } public void RejectChanges(object entity) { IRevertibleChangeTracking revertible =
(IRevertibleChangeTracking)entity;
revertible.RejectChanges(); } } }

Finally, let’s handle the CUD commands in our ViewModel.

For Create Operation

public void ExecuteInsertRow(object parameter)
{
    this.NewProduct = null;

    if (!this.IsBatchUpdate)
        this.SaveChanges();
    else
        this.HasChanges = true;
}

public void ExecutePrepareNewRow(object parameter)
{

    // It's possible to initialize the new row with default values
    // Example:
    // product.ProductName = "New Product";

    this.NewProduct = this.EditableProductsSource.Create();
    this.EditableProductsSource.Insert(this.NewProduct);
}
    

For Update Operation

public void ExecuteUpdateCell(object parameter)
{
    object[] updateCellParameters = (object[])parameter;
    object product = updateCellParameters.GetValue(0);
    string property = updateCellParameters.GetValue(1).ToString();

    // perform cell-level validation if required
}

public void ExecuteUpdateRow(object parameter)
{
    if (!this.IsBatchUpdate)
        this.SaveChanges();
    else
        this.HasChanges = true;
}

For Delete Operation

public void ExecuteDeleteRow(object parameter)
{
    this.EditableProductsSource.Delete(parameter as IList);

    if (!this.IsBatchUpdate)
        this.SaveChanges();
    else
        this.HasChanges = true;
}

For Validation, Reject Row and Refresh Operation

public void SaveChanges()
{
    this.IsBusy = true;

    this.EditableProductsSource.SaveChanges
    (
        () =>
        {
            this.IsRefreshed = true;
            this.LoadProducts(); // refresh
            this.HasChanges = false;
            this.IsBusy = false;
        },
        exception =>
        {
            this.IsBusy = false;

            MessagePresenter presenter = new MessagePresenter();
            presenter.ShowErrorMessage("An unexpected error has occurred: " 
+ exception.Message); } ); } public void ExecuteValidateRow(object parameter) { this.EditableProductsSource.Validate(parameter); } public void ExecuteRejectRow(object parameter) { if (parameter != null) this.EditableProductsSource.RejectChanges(parameter); this.NewProduct = null; }

For Batch Operation

public void ExecuteRejectChanges(object parameter)
{
    this.EditableProductsSource.RejectChanges();
    this.HasChanges = false;
}

public void ExecuteSaveChanges(object parameter)
{
    // if users click on the save changes while the new row is being edited,
    // presume the new row isn't intended
    if (this.NewProduct != null)
        this.EditableProductsSource.RejectChanges(this.NewProduct);

    this.SaveChanges();
}

I hope this post gives you a comprehensive understanding on handling the CUD (Create, Update, Delete) operation in UXGridView using MVVM design pattern. In the next post, I will blog about customizing editing controls in UXGridView, for instance, customizing the editing control of certain columns to more advanced input controls such as UXDateTimePicker, UXNumericUpDown, UXSliderBar, and so forth.

If you have any questions regarding the CUD operation, please post some questions in our community website.

Regards,

Andry