Blogs

The Progress Bar - DevExpress XPF Blog

August 2011 - Posts

  • WPF and Silverlight Themes – Introducing the Seven Theme

         

    As part of our continuous effort to enhance the visual experience of using our WPF and Silverlight controls, we have been working hard to complement our products with new themes. With the latest release of DXperience vol 2011 v1.7, we have introduced the new “Seven” theme, which matches (but doesn't completely imitate) the appearance of the Microsoft Windows 7 operating system. This elegant theme can be immediately applied to your WPF and Silverlight based business applications.

    Here are some screenshots to demonstrate the look and feel of the theme:

    docking-layout

    grid-card-view

    docking-dashboard

    grid-using-printing-templates

    pivot-field-customization

  • WPF Data Grid Control – PLINQ Data Support

         

    Starting with the latest v2011 vol1 update (11.1.7), we have introduced PLINQ data source support for the DXGrid Control for WPF. The DevExpress Data Grid for WPF can now operate on any in-memory IEnumerable data sources using Parallel LINQ (PLINQ), improving performance for data-intensive operations (e.g. sorting, grouping, filtering, summary calculation, etc.) by making full use of all the available processors/cores on the system.

    For this, DevExpress offers two new components (PLINQ data sources), each designed to address a specific data-processing mode (synchronous and asynchronous) – PLinqServerModeDataSource and PLinqInstantFeedbackDataSource, respectively.

    To make it easier for you to access and use them at design-time, both data sources are presented in WPF Designer Toolbox. Note that these are non-visual components for WPF.

    DevExpress_WPF_Grid_PLINQ

    To get started with enabling support for Parallel LINQ, you should specify the source collection for a PLINQ data source and bind it to the grid. The source collection must implement IEnumerable<T>. The exact type of its elements should not be specified as the type is automatically evaluated at runtime.

    There are three ways to specify the source collection:

    1. Use the ItemsSource property if a source collection implements IEnumerable<T>
    2. Use the ListSource property if a source collection implements IListSource.
    3. If PLinqInstantFeedbackDataSource is used, you can dynamically specify the source collection within the GetEnumerable event handler.
    1. <dx:PLinqInstantFeedbackDataSource Name="pLinqInstantSource" ListSource="{Binding Path=DataContext.ListSource}" />
    2. <dxg:GridControl Name="grid" ItemsSource="{Binding ElementName=pLinqInstantSource, Path=Data}">

    When using PLinqInstantFeedbackDataSource, the source collection can be dynamically populated by the IListSource.GetList() method or within the GetEnumerable event handler. In these instances, data objects are loaded in a separate thread, allowing you to perform time-consuming operations (e.g. create large volumes of data) without UI freezing. You should however ensure that the operations remain thread safe.

    One thing to be aware of when using PLinqInstantFeedbackDataSource, is that this PLINQ data source must be disposed of to terminate the processing thread and release all the resources that it owns. This can be done either by calling its Dispose() method or by executing DisposeCommand. For instance, you can execute this command in an MVVM-friendly manner using EventTrigger after a window has been closed (Example: http://www.devexpress.com/example=E3382).

    1. <i:Interaction.Triggers>
    2.     <i:EventTrigger EventName="Closed">
    3.         <i:InvokeCommandAction Command="{Binding ElementName=pLinqInstantSource, Path=DisposeCommand}" />
    4.     </i:EventTrigger>
    5. </i:Interaction.Triggers>

    Our PLINQ data sources provide properties (DefaultSorting, AreSourceRowsThreadSafe), allowing you to specify default sorting and whether data objects in a source collection are thread safe.

    Since PLINQ is not implemented in Silverlight, we’ve introduced a new data source for Silverlight – LinqToObjectsInstantFeedbackDataSource, which processes in-memory data in Instant FeedbackTM UI Mode. This data source is similar to PLinqInstantFeedbackDataSource for WPF. The only difference is that all data-intensive tasks (sorting, grouping, etc.) are run in a single separate thread (Example: http://www.devexpress.com/example=E3383).

    PLinqServerModeDataSource and PLinqInstantFeedbackDataSource are WPF specific wrappers around PLinqServerModeSource and PLinqInstantFeedbackSource. These two data sources are not platform-dependent and can be bound to DevExpress data-aware controls (e.g. XtraGrid) in WinForms applications. PLinqServerModeSource can also be used with DevExpress ASPxGridView control in ASP.NET applications.

    Benchmark Test

    We’ve made an internal performance testing on Intel Core i5 4-cores processor that compares the performance of the DevExpress WPF Data Grid control bound to PLinqServerModeDataSource and plain List<T>. The source collection has included 10,000,000 records.

    PLINQ_Performance_Table

    This superb performance has been achieved by using compiled lambda-expressions in our PLINQ data sources.

    The test application for this demo is available on CodeCentral: http://www.devexpress.com/example=E3382

  • WPF & Silverlight Tree List Control - Tree Derivation Modes

         

    In data bound mode, the TreeListView can display information in a tree from either self-referential (flat) or hierarchical data structure. For each type of data structure, corresponding tree derivation mode(s) can be specified using the TreeDerivationMode property:

    DevExpress_Silverlight_WPF_Grid_Tree_Derivation

    Self-Referential Data Structure

    This data structure (e.g. a table or list of business objects) should contain two special (service) fields:

    • Key Field

      This field must contain unique values used to identify nodes. Its name should be assigned to the TreeListView.KeyFieldName property.
    • Parent Field

      This field contains values (pointers) that reference parent nodes. Its name should be assigned to the TreeListView.ParentFieldName property.

    The only requirement is that service fields must contain data of the same type.

    The image below illustrates how the TreeListView generates a tree based on Key-Parent pairs:

    Tree_Generation

    An example can be found on CodeCentral: http://www.devexpress.com/example=E3127

    Hierarchical Data Structure

    In this context, a hierarchical data structure is any set of nested business objects that have a structure where the children of a node are in a ‘children’ field. Parents and children can be different object types.

    Assume a Project-Stage-Task business class structure:

    1. public class ProjectObject : BaseObject
    2. {
    3.     public ObservableCollection<ProjectStage> Stages { get; set; }
    4. }
    5.  
    6. public class ProjectStage : BaseObject
    7. {
    8.     public ObservableCollection<Task> Tasks { get; set; }
    9. }
    10.  
    11. public class Task : BaseObject
    12. {
    13.     State state;
    14.     // ...
    15. }

    When working with such data structures, the tree list’s ItemsSource contains only data items that correspond to root nodes. In the example above, these are ProjectObject items.

    To display the entire hierarchy, you can use one of the two approaches offered by the DevExpress TreeList Control:

    1. Using Hierarchical Data Templates

    With this option, you can take advantage of hierarchical data templates:

    1. <UserControl.Resources>
    2.     <ResourceDictionary>
    3.         <local:CustomHierarchicalDataTemplateSelector x:Key="selector">
    4.             <local:CustomHierarchicalDataTemplateSelector.ProjectDataTemplate>
    5.                 <sdk:HierarchicalDataTemplate ItemsSource="{Binding Path=Stages}" />
    6.             </local:CustomHierarchicalDataTemplateSelector.ProjectDataTemplate>
    7.             <local:CustomHierarchicalDataTemplateSelector.ProjectStageDataTemplate>
    8.                 <sdk:HierarchicalDataTemplate ItemsSource="{Binding Path=Tasks}" />
    9.             </local:CustomHierarchicalDataTemplateSelector.ProjectStageDataTemplate>
    10.         </local:CustomHierarchicalDataTemplateSelector>
    11.     </ResourceDictionary>
    12. </UserControl.Resources>

    Create a template selector which implements System.Windows.Controls.DataTemplateSelector and override the SelectTemplate method.

    1. public class CustomHierarchicalDataTemplateSelector : DataTemplateSelector
    2. {
    3.     public HierarchicalDataTemplate ProjectDataTemplate { get; set; }
    4.     public HierarchicalDataTemplate ProjectStageDataTemplate { get; set; }
    5.  
    6.     public override System.Windows.DataTemplate SelectTemplate(object item, System.Windows.DependencyObject container)
    7.     {
    8.         if (item is ProjectObject)
    9.             return ProjectDataTemplate;
    10.         if (item is ProjectStage)
    11.             return ProjectStageDataTemplate;
    12.         return null;
    13.     }
    14. }

    Assign the template selector to the TreeListView’s DataRowTemplateSelector property and switch to HierarchicalDataTemplate tree derivation mode:

    1. <dxg:TreeListControl.View>
    2.     <dxg:TreeListView DataRowTemplateSelector="{StaticResource selector}"
    3.                         TreeDerivationMode="HierarchicalDataTemplate" />
    4. </dxg:TreeListControl.View>

    If all business objects have the same ‘children’ field, create a single template and assign it to the TreeListView’s DataRowTemplate property.

    In WPF, you can define hierarchical data templates without a key in your resources. Instead, you specify the data type it should be applied to, like this:

    1. <ResourceDictionary>
    2.     <HierarchicalDataTemplate DataType="{x:Type local:ProjectObject}" ItemsSource="{Binding Path=Stages}" />
    3.     <HierarchicalDataTemplate DataType="{x:Type local:ProjectStage}" ItemsSource="{Binding Path=Tasks}" />
    4. </ResourceDictionary>
    5.  
    6. <dxg:TreeListControl.View>
    7.     <dxg:TreeListView TreeDerivationMode="HierarchicalDataTemplate" />
    8. </dxg:TreeListControl.View>

    How does the TreeListView select a template?

    First, the TreeListView verifies its DataRowTemplateSelector property. If the specified node selector returns null or the DataRowTemplateSelector property is not specified, a template specified by the DataRowTemplate property is used. If this property is not specified, an implicit hierarchical data template is used.

    Once the required HierarchicalDataTemplate is defined for a node, its ItemTemplate and ItemTemplateSelector properties take priority over the corresponding properties specified by the TreeListView (DataRowTemplate and DataRowTemplateSelector).

    Examples of these are available for WPF and Silverlight: http://www.devexpress.com/example=E3410 (WPF), http://www.devexpress.com/example=E3411 (Silverlight)

    2. Building a Tree in ‘Code Behind’

    In this case, you should manually write code to specify where a data object’s child items come from. So, create a selector class which implements DevExpress.Xpf.Grid.IChildNodeSelector and returns the list of child nodes for the specified node.

    For the Project-Stage-Task business class structure, a selector class will be as follows:

    1. public class CustomChildrenSelector : IChildNodesSelector
    2. {
    3.     public IEnumerable SelectChildren(object item)
    4.     {
    5.         if (item is ProjectStage)
    6.             return ((ProjectStage)item).Tasks;
    7.         else if (item is ProjectObject)
    8.             return ((ProjectObject)item).Stages;
    9.         return null;
    10.     }
    11. }

    Finally, you should assign the Child Nodes Selector to the TreeListView’s ChildNodesSelector property and set the TreeDerivationMode property to ChildNodeSelector.

    1. <dxg:TreeListControl x:Name="treeList"
    2.                         ItemsSource="{Binding DataItems}"
    3.                         DataContext="{StaticResource viewModel}">
    4.     <dxg:TreeListControl.Resources>
    5.         <local:CustomChildrenSelector x:Key="childrenSelector"/>
    6.     </dxg:TreeListControl.Resources>
    7.     <dxg:TreeListControl.Columns>
    8.         <dxg:TreeListColumn FieldName="Name" />
    9.         <dxg:TreeListColumn FieldName="Executor" />
    10.         <dxg:TreeListColumn FieldName="State" />
    11.     </dxg:TreeListControl.Columns>
    12.     <dxg:TreeListControl.View>
    13.         <dxg:TreeListView x:Name="view" TreeDerivationMode="ChildNodesSelector"
    14.                             ChildNodesSelector="{StaticResource childrenSelector}"/>
    15.     </dxg:TreeListControl.View>
    16. </dxg:TreeListControl>

    If all business objects have the same ‘children’ field, assign its name to the TreeListView’s ChildNodesPath property. Otherwise, a Child Nodes Selector should be created.

    An example of this is also available CodeCentral: http://www.devexpress.com/example=E3298

  • MVVM Enhancements in WPF and Silverlight versions of Toolbar, Ribbon and Gallery Controls

         

    In my previous blog post, I introduced the enhanced MVVM support for our WPF & Silverlight Data Grid Control to enable binding for column and summary creation. In this post, I’ll introduce new improvements in three of our other Silverlight and WPF components - DXBars, DXRibbon and GalleryControl. These features make it easy to use the controls when building applications following the MVVM pattern.

    The main scenario addressed by this new feature is the automatic generation of visual objects in DXBars, DXRibbon and GalleryControl based on data provided by underlying objects (i.e. by View Model classes).

    For the BarManager, the ideal MVVM support case would be as follows: The developer provides 1) a collection of objects each of which describes a toolbar and 2) a collection describing bar commands. As a result the BarManager automatically generates bars and populates them with bar items based on the provided data.

    As an example, let's see how one could write an application using the BarManager and the MVVM pattern prior to the introduction of the enhanced features. Here is the markup that creates bars from an underlying collection:

    1. <UserControl.Resources>
    2.     <local:MyBarModelToBarValueConverter x:Key="barValueConverter"/>
    3. </UserControl.Resources>
    4. <Grid>
    5.     <dxb:BarManager x:Name="barManager1">
    6.         <Grid>
    7.             <dxb:BarContainerControl ItemsSource="{Binding Path=BarsCollecton, Converter={StaticResource barValueConverter}}"/>
    8.         </Grid>
    9.     </dxb:BarManager>
    10. </Grid>

    In the code, a bar container is populated with bars from a BarsCollection, which is a View Model class. At first glance, this code looks quite simple. However, if you go deeper you will see that it requires additional code to be written:

    • A custom ValueConverter that will convert collection elements into bar objects
    • Code that initializes a bar's properties via data binding
    • Code that synchronizes the bar collection and underlying View Model collection

    That’s not all though as the Bar’s own bar items will also need to be populated from another View Model collection. Therefore an additional ValueConverter must be implemented to convert collection elements into bar items. The code complexity increases with increasing the hierarchy level of children in a control. For instance, in DXRibbon, a four level hierarchy will need to be dealt with – requiring more complex code in your project.

    So, we looked at these scenarios and made some changes to our controls to make it easier to work with them using the MVVM pattern.

    Let’s start with the new properties we’ve added to our DXBars, DXRibbon and GalleryControl controls:

    • ItemsSource
    • ItemStyle
    • ItemTemplate
    • ItemTemplateSelector

    All controls will follow the same naming convention for these properties.

    Using these properties you can easily generate a control's items (including nested items) from collections by writing only XAML code, with one exception - code for TemplateSelectors should be written in code-behind files.

    So let’s take a look at a View Model that contains a Bars collection:

    1. public class BarManagerViewModel : DependencyObject
    2. {
    3.     public static readonly DependencyProperty BarsProperty =
    4.         DependencyProperty.Register("Bars", typeof(ObservableCollection<BarViewModel>), typeof(BarManagerViewModel), new PropertyMetadata(null));
    5.  
    6.     public ObservableCollection<BarViewModel> Bars
    7.     {
    8.         get { return (ObservableCollection<BarViewModel>)GetValue(BarsProperty); }
    9.         set { SetValue(BarsProperty, value); }
    10.     }
    11.     //...
    12. }

    Then suppose we also have another View Model that provides items for bars:

    1. public class BarViewModel : BarViewModelBase
    2. {
    3.     public static readonly DependencyProperty CommandsProperty;
    4.  
    5.     static BarViewModel()
    6.     {
    7.         CommandsProperty = DependencyProperty.Register("Commands", typeof(ObservableCollection<BarCommand>), typeof(BarViewModel), new PropertyMetadata(null));
    8.     }
    9.     public ObservableCollection<BarCommand> Commands
    10.     {
    11.         get { return ((ObservableCollection<BarCommand>)GetValue(CommandsProperty)); }
    12.         set { SetValue(CommandsProperty, value); }
    13.     }
    14.     //...
    15. }

    In the code, we'll set a DataContext for the main window to BarManagerViewModel. This DataContext will be propagated to window's children, including a BarManager component:

    1. BarManagerViewModel viewModel = new BarManagerViewModel();
    2. this.DataContext = viewModel;

    Once we ensure that the BarManager gets the correct DataContext, we can populate a BarManager from the BarManagerViewModel.Bars collection using data binding:

    1. <local:BarsDemoModule.Resources>
    2.     <DataTemplate x:Key="barTemplate">
    3.         <ContentControl>
    4.             <dxb:Bar Caption="{Binding Name}"
    5.                      ItemLinksSource="{Binding Commands}"/>
    6.         </ContentControl>
    7.     </DataTemplate>
    8. </local:BarsDemoModule.Resources>
    9. <dxdb:DemoModuleControl>
    10.     <Grid>
    11.         <dxb:BarManager
    12.             BarsSource="{Binding Bars}"
    13.             BarTemplate="{StaticResource barTemplate}"
    14.         />
    15.     </Grid>
    16. </dxdb:DemoModuleControl>

    In this example, a DataTemplate is used to generate each bar from an underlying View Model (BarViewModel). You’ll notice that BarManagerViewModel.Bars is a collection of BarViewModel objects – this collection's objects are automatically assigned to the DataTemplate's DataContext, allowing us to initialize a bar's settings with properties on BarViewModel.

    When defining a DataTemplate for a Bar, the DataTemplate's root element must be ContentControl with a Bar object as the content.

    It is also possible to define a style that will be automatically applied to each bar created via a template. For instance, in the markup below, a style defines an item template selector (an object that selects templates for bar items based on your logic).

    1. <local:BarCommandTemplateSelector x:Key="itemTemplateSelector"/>
    2.  
    3. <Style x:Key="barStyle" TargetType="dxb:Bar">
    4.     <Setter Property="ItemTemplateSelector" Value="{StaticResource itemTemplateSelector}"/>
    5. </Style>
    6. <dxb:BarManager
    7.     BarsSource="{Binding Bars}"
    8.     BarTemplate="{StaticResource barTemplate}"
    9.     BarStyle="{StaticResource barStyle}"
    10. />

    As seen above, all bindings between View Models and View are set up in XAML, without using code-behind files. However, there is one exception: template selectors must be written in code-behind files. The BarCommandTemplateSelector below chooses between two DataTemplates (subItemTemplate or itemTemplate) based on our model:

    1. public class BarCommandTemplateSelector : DataTemplateSelector
    2. {
    3.     public override DataTemplate SelectTemplate(object item, DependencyObject container)
    4.     {
    5.         if (item is BarSubMenuCommand) return (DataTemplate)MVVMBar.SharedResources["subItemTemplate"];
    6.         return (DataTemplate)MVVMBar.SharedResources["itemTemplate"];
    7.     }
    8. }

    The complete code of this sample can be found in the "MVVM Bars" demos for WPF and Silverlight shipped with the installation.

    The described approach is extremely efficient and can also be applied when writing MVVM applications with the DXRibbon and GalleryControl. These controls provide corresponding properties (ItemsSource, ItemStyle, ItemTemplate and ItemTemplateSelector) that allow the controls to be populated with items from underlying collections.

    For implementation details, you may refer to the "MVVM Ribbon" demos for WPF and Silverlight included in the installation. The online demos can be launched from our Demo Center at:

    http://demos.devexpress.com/DemoCenter/

    Finally, below you will find a list of DevExpress classes and properties in DXBars, DXRibbon and GalleryControl that support the MVVM pattern:

     

    Class

    Properties

    BarManager

    BarsSource

    BarTemplate

    BarStyle

    BarTemplateSelector

    Bar, BarLinkContainerItem, BarSubItem, PopupMenu, PopupMenuInfo, RibbonPageGroup, ApplicationMenu

    ItemLinksSource

    ItemTemplate

    ItemStyle

    ItemTemplateSelector

    RibbonControl , RibbonStatusBarControl

    CategoriesSource

    CategoryTemplate

    CategoryStyle

    CategoryTemplateSelector

    RibbonPageCategory

    PagesSource

    PageTemplate

    PageTemplateSelector

    PageStyle

    RibbonPage

    GroupsSource

    GroupTemplate

    GroupStyle

    GroupTemplateSelector

    GalleryControl

    GroupsSource

    GroupTemplate

    GroupStyle

    GroupTemplateSelector

    GalleryItemGroup

    ItemsSource

    ItemTemplate

    ItemStyle

    ItemTemplateSelector

More from DevExpress
Live Chat
Have a pre-sales question?
Need assistance with your evaluation?
We are here to help.
Chat is one of the many ways you can contact members of the DevExpress Team. We are available Monday-Friday between 8:30am and 5:00pm Pacific Time.
If you need additional product information, require pre-sales assistance, or want help with your order, write to us at info@devexpress.com or call us at
+1 (818) 844-3383.