Tag Archives: DevForce

DevForce 2012 Support in ClientUI for Silverlight & WPF

Since 2010, we’ve partnered with IdeaBlade to provide our customers with a comprehensive and robust solution for building highly scalable line-of-business applications. The successful integration between IdeaBlade’s DevForce and our flagship ClientUI toolset significantly improves developer’s productivity – allowing them to leverage the MVVM pattern to build beautiful interface and at the same time enjoying the client-side LINQ query capability as well as many other advanced features available in DevForce.

As DevForce 2012 is now officially released to the market, we’re committed to continue supporting the latest DevForce version and leverage its new features in our toolset.  DevForce 2012 is the sevent-generation of the DevForce n-tier architecture released by IdeaBlade. This version has supported some noteworthy features such as .NET 4.5 asynchronous programming support, Entity Framework 5 support, and Windows Store Apps support. For more details, please visit DevForce 2012 information page.

DevForce 2012 Support

The latest suite of Intersoft WebUI Studio 2012 R2 ships with DevForce 2010 (version 6.1.7.0). In the next release, we’ll include full support for DevForce 2012. However, we’ll make available the new DevForce 2012 support assemblies so you can start using them today. In this blog post, I’ll share how to implement DevForce 2012 support in your existing applications.

We provide two kind of support for DevForce 2012 which are detailed in the following sections.

Using Backward Compatibility

This solution is intended for existing DevForce 2010 .NET and Silverlight projects which uses the “operation/callback” asynchronous API.

Migrating from existing DevForce 2010 projects to DevForce 2012 are made easy by applying the following rule.

  • Add a using/Imports statement to your code file for IdeaBlade.EntityModel.Compat.
  • Add a using/Imports statement to your code file for the new Intersoft data provider of DevForce 2012, Intersoft.Client.Data.Provider.DevForce2012.
  • Add a using/Imports statement of Intersoft.Client.Data.Provider.DevForce2012.Compatibility.

With this approach, you don’t need to change a single line of code in your project, while enjoying the benefits and new features available in DevForce 2012 and Entity Framework 5. I recommend you to go with this approach if your existing application is considerably large and you prefer to do the transition in progressive fashion.

Click here to browse the sample project which was created using Intersoft ClientUI MVVM Data Application using DevForce 2010. The project was later modified by migrating the DevForce 2010 to DevForce 2012.

Using Native DevForce 2012 API

Asynchronous patterns

The Task-based Asynchronous Pattern (TAP) is based on the Task and Task<TResult> types in the System.Threading.Tasks namespace, which are used to represent arbitrary asynchronous operations. TAP is the recommended asynchronous design pattern for new development.

DevForce 2012 has implemented the use of TAP. By implementing this, we are able to use the await keyword, which makes asynchronous method calls feel synchronous when we’re writing code.

Instead of writing callback, lambda expressions, or coroutines, we now use await. Here is an example about the implementation of await.

Using lambda expression in DevForce 2010

public virtual void GetData(Action<IEnumerable> onSuccess, Action<Exception> onFail)
{
    if (Intersoft.Client.Framework.ISControl.IsInDesignModeStatic)
        return;

    var query = this.EntityQuery;

    query.ExecuteAsync(
        op =>
        {
            if (op.CompletedSuccessfully)
            {
                if (onSuccess != null)
                    onSuccess(op.Results);
            }
            else
            {
                if (onFail != null)
                {
                    op.MarkErrorAsHandled();
                    onFail(op.Error);
                }
            }
        });
}

Using await in DevForce 2012

public virtual async Task<IEnumerable> GetData()
{
    if (Intersoft.Client.Framework.ISControl.IsInDesignModeStatic)
        return null;

    var query = this.EntityQuery;

    IEnumerable results = await query.ExecuteAsync();
    return results;
}

GetData() method which previously doesn’t return anything (void) now returns Task. The lambda expression is replaced with following line of code.

IEnumerable results = await query.ExecuteAsync();
return results;

onSuccess and onFail parameters – the callback to invoke when the operation succeeded or failed – are no longer available. You handle them in the same way and manner as you wrote synchronous code, that is by wrapping them in a try-catch syntax.

We now provide a new version of DevForce data provider that supports async and await operations which conforms to DevForce 2012 native API. For example, you can now use the following code to query a list of customers from the repository.

private async void LoadCustomers()
{
    try
    {
        var customers = await this.CustomersSource.GetData();
        this.Customers = customers;
        this.IsCustomersLoaded = true;
    }
    catch (Exception ex)
    {
        this.Presenter.ShowErrorMessage(
                "An exception has occurred during data loading\n." +
                "Message: " + ex.Message +
                "Stack Trace: " + ex.StackTrace);
    }
}

Click here to browse the sample project in github which was created using Intersoft ClientUI MVVM Data Application using DevForce 2012. Note that the new DevForce support assemblies can be found in the sample project.

Definitely there are so much exciting stuff in the continuing collaboration of ClientUI and DevForce 2012. Let me know if you have any questions or feedback about the DevForce 2012 support, or how we can improve it better for you.

Warm Regards,
Yudi

New Silverlight Tutorials: Building business applications with ClientUI and DevForce

By the latest release, we’ve shipped a whopping 300+ rich controls for Silverlight and WPF development – and that’s not to mention the included advanced frameworks like MVVM, commands, event aggregators and more! Fortunately, we included a comprehensive documentation and dozens of new tutorial videos to help you getting on the board fast. If those are still not enough, make sure you check out the new ClientUI tutorials focusing on line-of-business application development – thanks to our friend, Bill Gower, for such the great contributions.

In the first series of his post, Bill overviews the application that he’s going to build using Intersoft ClientUI for the presentation layer and IdeaBlade DevForce for the data service layer. And Bill picks up the line just right, you’ll be surely excited to explore through the steps of creating a fully-functional sales/retail application – from the Customers, Inventory, Sales Invoices to Purchases and more.

Best of all, you can learn how to build the applications right using the best design and architectural patterns. You can check out the post here.

Furthermore, Bill has written a series of great articles to share his experiences while developing in Silverlight and WPF. Some of the noteworthy links are as follows.

Best,
Jimmy

ClientUI & DevForce Part 3: Enhance Editing Experiences with MVVM Advanced Input Controls

In the previous series of the joint ClientUI and DevForce sample, you have learnt how to build a simple Contacts application that runs in both Silverlight and WPF using the architectural best practice such as MVVM design pattern. The first series discussed about the fundamental data access architecture, while the second series talked about sandboxed editing. You can read the first blog post here, and the second post here.

In this blog post, I’m pleased to introduce the third series of our joint Contacts sample which is strongly focused on improving the editing experiences. The upgraded Contacts sample guides you how to add rich editing capabilities to your Silverlight and WPF applications using the new ClientUI’s advanced input controls. More interestingly, it also addresses a number of challenging technical implementation such as adding a nice photo upload capability using MVVM design pattern. Let’s get it started!

Eliminate Input Errors with UXMaskedInput

In the original Contacts application, the Contact Editor uses basic textbox controls to capture the data input such as the Id, name and address of the contact. However, using basic textboxes to accept patterned data input – such as found in zip code or a phone number – is often prone of entry errors which lead to data inconsistency and corruption in the application’s functionality.

Fortunately, the latest ClientUI release now comes with dozens of advanced input controls with various built-in features, each designed to address different needs. For example, UXMaskedInput is designed to restrict data input with patterned format such as zip code or SSN, UXCurrencyEditor for entering number and currency input, and UXDateTimePicker for entering date and time.

Back to our Contacts application, the Contact Editor definitely needs some improvements to provide users with richer editing capabilities which ultimately minimize data entry errors. Some of the possible improvements are as following:

  • Add automatic uppercase conversion to the ID input
  • Limit the zip code to accept only five optional digits
  • Add phone number masking to Phone, Cell and Fax input

Most of the above requirements can be achieved with UXMaskedInput, thanks to its powerful and comprehensive masking features. Its MVVM-ready architecture also enable us to implement rich masked editing complete with validation in just a few minutes – all without writing code.

The following example shows how to use UXMaskedInput to accept only input with phone number pattern.

<Intersoft:UXMaskedInput Width="120" EditMask="0-000-000-0000"
     ErrorMessage="Please enter a valid phone number, i.e., 1-510-555-1212"
     Value="{Binding Contact.Phone, ValidatesOnDataErrors=true, Mode=TwoWay}" 
     Intersoft:DataBinding.ClearErrorOnTextInput="True" 
     IsSaveLiteral="True" />

And the results below.

Rich Contact Editor with Masked Input

To learn more about the features available in UXMaskedInput, please see UXMaskedInput Documentation.

Implement MVVM Photo Upload with UXFileUpload

Most of modern web applications today leverage the power of multimedia such as images and videos more than ever before to create more engaging user experiences. Even Twitter, the 140 character-limited microblogging social tool, has now evolved allowing people to post and share their photos – announced two days ago.

While file upload might sound easy and is something already common in the web, it’s not so common in Silverlight. The complexity grows up particularly when you’re tasked to implement it using MVVM pattern, not to mention you still have bunch of other things to take care such as the user experiences and the reliability of the file upload process itself. This could take weeks, or  months of coding time just to add a file upload capability that really works. The good news is that we have a solution for you. Read on.

In this third joint Contacts sample, we’d love to share how easy it is to add an impressive photo upload feature to the Contact Editor. With UXFileUpload, we’ve got everything we needed – from multiple files upload, progress indicator, upload cancellation, to a fully customizable look and feel. Better yet, it fully supports MVVM pattern which means that you can start the uploading process, identify the progress and capture the uploaded results – all within the ViewModel.

With photo upload implementation that satisfies the MVVM pattern, it enables us to easily reflect the changes to the DevForce’s entity through a two-way data binding. The following code snippet shows the photo upload implementation with UXFileUpload using MVVM pattern.

<Intersoft:UXFileUpload ServiceUrl="http://localhost:1215/UXFileUploadHandler.ashx" 
     TargetFolder="~/Assets/Photos" TargetWebUrl="./" MaxFileSize="512000" 
     OverwriteExistingFiles="True" IsAutomaticUpload="True" CanSelectMultiple="False" 
     ShowStatisticsOnCompleted="False" FileTypeFilter="Image Files (*.jpg)|*.jpg" 
     EnforceFileTypeValidation="True" 
     UploadedFileUrl="{Binding Contact.PhotoUrl, Mode=TwoWay}"/>

Notice that the UploadedFileUrl is bound two-way to the contact’s PhotoUrl property. When the upload completes, the PhotoUrl reflects the changes immediately. As the results, you don’t even have to add any code in the ViewModel, because the existing SaveChanges function will automatically take account the changes in the PhotoUrl property.

The following screenshot shows the polished Contact Editor with photo upload capability.

Contact Editor with photo upload capability

When saved, the newly uploaded photo in the Contact List will be automatically updated as well without any additional effort, this is made possible with a two-way binding between the image source and the image property in the DevForce’s entity, see below.

image

All in all, the advanced input controls with solid MVVM architecture combined are true productivity booster! It helps make development faster, easier and more maintainable.

To learn more how to implement the advanced input controls and the photo upload in depth details, please read the PDF walkthrough.

Download the Solution

Click here to download the latest Contacts project source code along with the walkthrough document. Please note that the download package contains updated files and a number of bug fixes, thus is newer than the one installed in ClientUI 5. The latest project source will be shipped in the upcoming ClientUI 5 service pack.

As usual, the release includes both Silverlight and WPF projects which are built with identical codebase. Feel free to play around with the code and use it in your apps! Note that you will need the latest version of ClientUI and DevForce to run this sample. You can download the latest ClientUI release here, and DevForce here.

Any feedback and thoughts are warmly welcomed.

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

WebUI Studio 2011 Goes Gold!

The past few weeks were probably the busiest days in this first quarter as we are preparing for the huge 2011 volume release. Even sparing a few minutes to write blogs seems to be uneasy to the team due to super tight schedules. Nevertheless, our diligent works are well paid off as we managed to (still) release on schedule. 

The wait is over! The highly-anticipated WebUI Studio 2011 finally goes gold today, which includes the new data controls lineup that have been made available in several beta releases. It delivers a total of 30 new controls for ASP.NET, Silverlight and WPF development – another fantastic release! To see what the new WebUI Studio has in store for you, please head to What’s New in WebUI Studio 2011.

Next, please refer to the following links for more details on the new release.

In addition, major sites such as Intersoft Support Site, Online Documentation   and ASP.NET live demos have been updated as well to reflect the new releases. Be sure to check out the updated ClientUI demos too where we have added around 80   business-inspiring samples with amazing user experiences. To try the demos now, jump to ClientUI live demos.

In this blog post, I will share a quick recap on the key highlight of the new release. In addition to many new exciting stuff as you can read in the 2011 Tour page, the new 2011 release is highly focused in improving the overall user experiences in an end-to-end approach – from the installation and getting started to licensing and deployment.

To that end, WebUI Studio 2011 now ships with a new installation experience that integrates with the operating system’s look and feel. So if you’re using Windows 7 with Aero-glass enabled, you will see the new WebUI Studio setup to use the same glass theme. The overall user interface has also been redesigned for simplicity and elegancy. To stimulate your appetite, let’s see some of the new installation shots below.

WebUI Studio 2011 New Installation Experiences

WebUI Studio 2011 New Installation Experiences

However, the new installation experience isn’t just about the glassy user interface. More importantly, the new WebUI Studio setup has been further simplified to require only a few clicks to complete a common installation – reducing from 8 to 4 in the total number of clicks. In this “automatic” setup mode, the installer detects your computer configuration and smartly decides the best settings to apply to your installation session. For instances, if you have Visual Studio 2011 installed, then all the samples and help files for Visual Studio 2010 will be automatically chosen.

Of course, you can still customize the installation the way you accustomed to, by checking the customize checkbox in the initial screen before hitting the Next button, see the screenshot below for a close-up.

WebUI Studio 2011 Setup Customization

All in all, WebUI Studio 2011 is our best release yet. It ships with a dramatically improved user experience, 12 new time-saving business project templates, native DevForce integration, and delivers over 30 new and essential business controls to the already comprehensive portfolio – positioning it as the developer’s top choice for all .NET application development needs.

Definitely there are so much exciting stuff to share in this new release, but I decided to not polluting this blog post with product-specific and new samples coverage. I’ll surely recap those topics in my next post. For now, download the new WebUI Studio if you haven’t done so.

Last but not least, we hope you enjoy the new release as much as we enjoy building it!

All the best,
Jimmy

UXGridView RC Adds MVVM Data Exporting, Multi Aggregates, Selectors, and more

After going through a series of technology preview releases,  UXGridView is finally topping off with the complete feature sets. Today, I’m excited to announce the immediate availability of UXGridView Release Candidate.

In case you missed the stories, UXGridView is Intersoft’s brand-new data grid built to handle the most demanding line-of-business development requirements – from server-side paging and filtering support, data editing and validation, batch update to data aggregates and data exporting. Each feature is thoughtfully engineered to work best with MVVM pattern implementation. UXGridView runs on both Silverlight and WPF with single identical markups. Learn more about UXGridView here.

In this post, I will share the key highlights of the new features implemented in the UXGridView RC. As defined in the roadmap that I posted in my blog post, the RC milestone will include advanced data-centric features such as data exporting, row virtualization improvements, multi aggregates, custom grouping logics, and a bunch of style selectors and template selectors.

Data Exporting the MVVM-way

In the previous CTPs, you have learned how UXGridView handles real-world data access scenarios like paging, filtering, data validation and editing – all implemented entirely with MVVM design pattern. In this RC release, UXGridView adds data exporting capability which you can implement using the solid MVVM pattern. Unlike other grids, the data exporting in UXGridView supports both server-side and client-side mode. The most advanced mode is the server-side data exporting which allows you to export all rows in the data source even though the UXGridView is paged.

Just because UXGridView supports displaying millions of rows, that doesn’t mean you should. In real-world scenarios, most users browse and look only for a piece of data at a time. So in most cases, you would enable the server-side paging in the UXGridView so it loads only a subset of data at a time. For instances, a Grid with the page size set to 20 will load only 20 rows per page. The data exporting, quite the opposite, requires all data to be fetched before the exporting can execute. That’s one of the key challenges that we managed to address in UXGridView, enabling data exporting to work in harmony with the server paging and other features using the MVVM pattern implementation.

To handle the server-side data operation consistently, we built the data exporting upon the same key component that powers the server paging and filtering, the QueryDescriptor. Perhaps you still recall, QueryDescriptor encapsulates the query definitions which consisted of FilterDescriptors, SortDescriptors and PageDescriptor. That’s just perfect because we can simply use the existing instance of the QueryDescriptor in the ViewModel, and perform re-query that doesn’t include the paging descriptor. If you need a refresh on QueryDescriptor, please head to Data-access the MVVM-way.

The best way to handle the data exporting using MVVM is to implement a DelegateCommand in the ViewModel and bind it to the ExportCommand, a new command property introduced in the RC release. In the Executed handler, you call a server query that returns complete data, and finally pass it to the collection in the ViewModel which is bound to the ExportItems property of UXGridView. Take a look at the following code snippet to learn how it’s done.

public class ServerExportingViewModel : ServerSideOperationViewModel
{
    public ServerExportingViewModel()
        : base()
    {
        this.CanUserExport = true;
        this.ExportCommand = new DelegateCommand(ExecuteExportCommand);
    }

    public void ExecuteExportCommand(object parameter)
    {
        QueryDescriptor exportQueryDescriptor =
                     this.QueryDescriptor.CreateCopy(true, true, false);

        this.ProductsSource.GetData
        (
            exportQueryDescriptor,
            (products) =>
            {
                PagedCollectionView current =
                                   this.Products as PagedCollectionView;
                PagedCollectionView exportedItems =
                                   new PagedCollectionView(products);                    

                exportedItems.CopyDefinitionsFrom(current, true,
                                   false, false, false);

                this.ExportItems = exportedItems;
            },
            (totalItemCount) =>
            {

            },
            (error) =>
            {

            }
        );
    }
}

Quite simple and straightforward, isn’t it? Also notice that the QueryDescriptor now has a CreateCopy, a new time-saving method that returns a clone based on the given source and options. The most important point here is the flexibility that UXGridView offered since it gives you full control over how the data retrieval is done in the ViewModel.

4 Built-in Exporting Data Format

UXGridView allows you to export the data source into four data format – not only one, or two. Users have the choice to export data to HTML, Excel, CSV or just a plain text file. From the user interface perspective, all you need to do is to set the CanUserExport property to true. A tiny, stylish dropdown button will then appear in the status bar, next to the data pager. The available data format is listed in the menu when the dropdown button is clicked, such as shown below.

Exporting user interface

Although the user interface has been well predefined, they are fully customized thanks to the loosely-coupled UI architecture. For instances, you can change the dropdown button to a more stylish callout, or just a plain command button if you preferred.

When the data exporting process completes, you’ll be prompted to save the results to your local computer. The following illustration shows the Excel spreadsheet that contains the exported results.

UXGridView data exported to Excel

UXGridView also offers a number of exporting options such as whether to include column footers, column headers or the group footers in the exported results. For even more fine-grained HTML results, you can customize the style of each generated row and cell output through the ExportCssStyleSelector, another big plus for MVVM implementation!

Style and Template Selectors

UXGridView implements a wealth of style selectors and template selectors, giving the freedom you need to create rich data presentation the way you want. The selector pattern is a first-class MVVM citizen that enables you to write custom logics in a separate class instead of in the view level. You get two benefits immediately: greater reusability and cleaner implementation due to the view/code separation.

One of the most common scenarios, for instances, is to show discontinued products in a different background color, allowing users to quickly distinguish the useful information they need to work with. The following illustration shows the results of a RowStyleSelector implementation.

RowStyleSelector in UXGridView

Another common scenario is to display different information based on specific conditions. For instances, showing a Reorder hyperlink button in the case that the products were out-of-stock. This can be done through an implementation of CellTemplateSelector, see the results below.

CellTemplateSelector in UXGridView

Or how about a more advanced scenario like applying a different background brush in the row header of each different group level? That’s also possible to be done through an implementation of RowGroupHeaderStyleSelector.

RowGroupHeaderStyleSelector in UXGridView

I hope the above illustrations give you a clear idea what the style and template selectors are all about.

To be more exact, UXGridView provides 13 selectors for the row, cell, column header, column footer and group elements. The complete list is as follows:

  • Row Style Selector
  • Row Template Selector
  • Cell Style Selector
  • Cell Template Selector
  • Column Header Style Selector
  • Column Header Template Selector
  • Column Footer Style
  • Column Footer Cell Style
  • Column Footer Cell Template
  • Row Details Template Selector
  • Row Group Header Style Selector
  • Row Group Footer Style
  • Row Group Footer Cell Style

Note that the above selectors have not included the selectors of other elements such as editing and exporting.

Multi Aggregates

Another nice addition in the RC release is the support for multiple aggregates in both the column footer and group footer. It will be definitely useful for line-of-business applications, particularly in financial extensive applications. So here the feature is when you need it.

Multi aggregates support in UXGridView

Custom Grouping

The RC release adds more powerful features allowing developers to fine-tuning the grouping results in UXGridView. While most competing grids used locked-down approaches, UXGridView is quite the opposite. You can now define your own custom groups by writing custom logics in a separate class which is then instantiated in the XAML and assigned to the GroupConverter property of the UXGridViewGroupDescriptor.

The sample in the following illustration groups the products data based on a range of CategoryID values.

Grouping with custom logic

Another popular scenario that can be achieved using the group converter is the value list capability where more meaningful information can be displayed in the group header instead of useless IDs, for instances, displaying the actual name of a category instead of the ID such as shown below.

Grouping with value list

Read-only Binding

Last but not least, among the top requested features is the read-only binding which we managed to ship in the RC release. With the read-only binding expression, you can write a custom logic that determines when a particular row or cell should be read-only (not editable).

UXGridView provides read-only binding at both the row and cell level. The read-only binding expression at row level, if returns true when evaluated, will supersede the read-only binding expression at the cell level. This means that if the read-only binding is specified at the row level and returns a true value, the entire row will no longer editable regardless of the value of the binding expression specified in the cells.

For  examples, consider a scenario where discontinued products should be not editable. In such case, the IsReadOnlyBinding of the UXGridView is bound to the Discontinued property of the product entity. To prevent users to accidentally uncheck the Discontinued value, the same property can be bind to the IsReadOnlyBinding of the UXGridViewColumn. The binding expression at the UXGridView level applies to the rows, while the one at the UXGridViewColumn applies to the cells.

Luckily, the RC release shipped with an example based on the above scenarios. The following illustration shows the discontinued product which can no longer be edited.

IsReadOnlyBinding in UXGridView

WCF RIA SP1 Support

The UXGridView, UXDataPager and UXDataFilter controls in the RC release have been updated to support the recently released WCF RIA SP1. Most notable is the paging support for new data model returned in the children of the navigator properties. The data controls are also backward compatible with the previous WCF RIA.

Download the RC Bits

UXGridView Release Candidate includes complete feature sets and near-RTM quality, which means that you can start using UXGridView to build amazingly rich data-centric applications for the Silverlight and WPF platforms. As you have learned through the series of technology preview releases, each UXGridView feature is uniquely engineered to work best for many MVVM scenarios, making it the industry’s first and most advanced MVVM-ready data grid for the Silverlight and WPF development.

To summarize, the RC release adds a host of exciting new and essential features such as data exporting, style and template selectors, multi aggregates, and much more. We’ve also added many new samples that demonstrate real-world development scenarios such as using different sort member for value list and displaying an image in the cells. The RTM version will add a couple “extra” features, so stay tuned for the next announcement!

Click here to download the RC bits and test-drive the new UXGridView features today. The download package includes latest ClientUI assemblies as well as updated and new samples for both Silverlight and WPF platforms.

Please note that the UXGridView RC is the last public community release. The next milestone would be the UXGridView RTM release together with dozens of new members in ClientUI 5. For now, we’d love to hear what you think about the new features and enhancements available in the RC. Please post your feedback, questions or issues to our community forum.

Best,
Jimmy
Chief Software Architect

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