Blogs

The One With

May 2010 - Posts

  • OData Provider for XPO – Client Side

    In the previous posts, we have looked at how the WCF Data Service Provider for XPO works and how to expose existing XPO objects as OData. Now let’s take a look at how to consume them.

    First, create a service proxy. Let’s use a public OData feed from the DevExpress Channel.

    The wizard will generate proxy client side data objects from the OData metadata.

    public class Statistics : INotifyPropertyChanged {
        public Guid Oid { get; set; }
        public int CompletedCount { get; set; }
        public int Count { get; set; }
    }
    public class Video : INotifyPropertyChanged {
        public DateTime Date { get; set; }
        public string Description { get; set; }
        public bool Enabled { get; set; }
        public string Location { get; set; }
        public Guid Oid { get; set; }
        public Statistics Statistics { get; set; }
        public string Title { get; set; }
    }
    with these we can now make requests like so:

    DataContext context 
        = new DataContext(new Uri("http://media.devexpress.com/channel.svc"));
    foreach(var video in context.Video) {
        Console.WriteLine(video.Title);
    }

    What’s Next

    Cheers

    Azret

  • OData Provider for XPO - IDataServiceQueryProvider

    In the previous post, we have introduced a WCF Data Service Provider for XPO. Let’s now look at how it works under the hood.

    For a basic read-only data service provider we only need to implement two interfaces:

    • IDataServiceMetadataProvider : Provides the metadata information about your entities. The data service will query this for your resource types, resource sets etc…
    • IDataServiceQueryProvider : Provides access to the actual entity objects and their properties. Most importantly, it is responsible for the IQueryable on which data operations like $filter, $orderby, $skip are performed.

    Custom provider implementations are picked up via IServiceProvider.GetService

    public class XpoDataService : DataService<XpoDataContext>, IServiceProvider {
        XpoProvider _provider;
        public XpoProvider GetProvider() {
            if (_provider == null) {
                _provider = newXpoProvider(this);
            }
            return _provider;
        }
        object IServiceProvider.GetService(TypeserviceType) {
            if (serviceType == typeof(IDataServiceMetadataProvider)
                || serviceType == typeof(IDataServiceQueryProvider)) {
                return GetProvider();
            } else {
                return null;
            }
        }
    }

    IDataServiceMetadataProvider

    Implementing the IDataServiceMetadataProvider for XPO metadata is very straightforward. We already have all information needed in the form of XPClassInfo/XPMemberInfo. It’s just a matter translating it into ResourceTypes/ResourceProperties constructs.

    XPClassInfo classInfo = Dictionary.QueryClassInfo(entityType);
    if (classInfo == null) {
        return null;
    }

    AddResourceType(classInfo);

    foreach (XPMemberInfo memberInfo in classInfo.Members) {
        AddProperty(resourceType, memberInfo);
    }

    Than, if we want to make a specific entity queryable, we’ll create a resource set of it.

    if (resourceType.ResourceTypeKind == ResourceTypeKind.EntityType) {
        AddResourceSet(resourceType);
    }

    By default, our data provider will automatically do all of this for *all* XPO classes found in the assembly where the data service lives. You can control this behavior by overriding the RegisterClasses method.

    public override void RegisterClasses(XpoProviderMetadata metadata) {
        metadata.RegisterEntity(typeof(Customer));
        metadata.RegisterEntity(typeof(Order));
        metadata.RegisterEntity(typeof(Product));
    }

    IDataServiceQueryProvider

    Implementation of IDataServiceQueryProvider is centered around it’s GetQueryRootForResourceSet method. This is where we return an IQueryable root on which data service will apply the request criteria. Now because XPO already has a LINQ implementation, all we need to return is an XPQuery<T> : IQueryable<T>.

    public class XpoQueryBridgeFactory<T> : IXpQueryBridgeFactory {
        public object Create(Session session) {
            return new XPQuery<T>(session);
        }
    }

    public virtual IQueryable GetQueryRootForResourceSet(ResourceSet resourceSet) {
        IXpQueryBridgeFactory factory = (IXpQueryBridgeFactory)Activator.CreateInstance(
              typeof(XpoQueryBridgeFactory<>).MakeGenericType(resourceSet.ResourceType.InstanceType));
        return (IQueryable)factory.Create(this.Session);
    }

    Note: The real query root has an intercepting LINQ to LINQ wrapper to deal with special cases. 

    What’s next?

    Cheers

    Azret

  • OData Provider for XPO - Introduction

    The Open Data Protocol (OData) is quickly becoming the format of choice when it comes to exposing data. The growing number of client side libraries and all the new features from WCF Data Services is what makes the developers switch from proprietary (Custom REST APIs, SOAP, Binary Formats etc…) to OData.

    The simplest way to expose your data as OData is by using the WCF Data Services, which currently comes with a couple of out of the box providers (EF, Reflection etc…). Each provider requires it’s own data model and if you have made XPO your ORM of choice, switching to another model is out of the question. Adding an additional data layer is not something you would want to do either, maintaining more than one is rarely a good practice.

    The cool thing about the WCF Data Services is that you can plug in custom providers. A provider for XPO can be downloaded from CodePlex. We’ll develop it together in this series of blog posts, but first, I want to show you how easy it is to expose your XPO model using the XPO Data Service Provider.

    Step 1: Have your XPO Model Ready

    For demonstration purposes my persistent objects are mapped to the Nwind access database. I used the Add New Persistent Classes Wizard to generate mine.

    public class Customers: XPLiteObject {
        string fCustomerID;
        [Key]
        [Size(5)]
        public string CustomerID {
            get { return fCustomerID; }
            set { SetPropertyValue<string>("CustomerID", ref fCustomerID, value); }
        }
        ...
    }

    public class Products : XPLiteObject {
        int fProductID;
        [Key(true)]
        public int ProductID {
            get { return fProductID; }
            set { SetPropertyValue<int>("ProductID", ref fProductID, value); }
        }
        ...
    }

    Step 2 : Add a new WCF Data Service to your project

    public class Nwind : DataService< /* TODO: put your data source class name here */ >
    {
        // This method is called only once to initialize service-wide policies.
       
    public static void InitializeService(DataServiceConfiguration config)
        {
            // TODO: set rules to indicate which entity sets and service operations are visible, updatable, etc.
            // Examples:
            // config.SetEntitySetAccessRule("MyEntityset", EntitySetRights.AllRead);
            // config.SetServiceOperationAccessRule("MyServiceOperation", ServiceOperationRights.All);
           
    config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V2;
        }
    }

    Step 3: Add a Reference to DevExpress.Xpo.Services.v10.1.dll

    Step 4: Configure your WCF Data Service

    [XpoConnectionString("Nwind")]
    public class Nwind : XpoDataService
    {
        public static void InitializeService(DataServiceConfiguration config)
        {
            config.SetEntitySetAccessRule("*", EntitySetRights.AllRead);
            config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V2;
        }
    }

    File: Web.config

    <connectionStrings>
      <
    add name="Nwind" connectionString='Provider=Microsoft.Jet.OLEDB.4.0;Data Source="nwind.mdb"'/>
    </
    connectionStrings>

    And that’s it! We can now explore our data using a number of different clients that support OData or simply view the feeds in the browser.

    OData Feed for XPO

    What’s Next?

    Cheers

    Azret

  • WPF Grid Control – Multiple Cell Selection v2010 vol 1

    The WPF Grid Control (DXGrid) in DXperience v2010 vol 1 introduces support for multiple cell selection. To enable it, set the MultiSelectMode="Cell" on your table view.

    <dxg:GridControl x:Name="grid" >
    <dxg:GridControl.Resources>
    <DataTemplate
    x:Key="{dxg:RowIndicatorThemeKey ResourceKey=IconPresenterTemplate}">
    <dxe:TextEdit
    Text="{Binding Path=DataContext.Date, StringFormat=Y}"
    HorizontalAlignment="Right"
    EditMode="InplaceInactive"/>
    </DataTemplate>
    </dxg:GridControl.Resources>
    <dxg:GridControl.View>
    <dxg:TableView
    x:Name="view"
    MultiSelectMode="Cell"
    IndicatorWidth="100"
    ShowGroupPanel="False"
    SelectionChanged="view_SelectionChanged"/>
    </dxg:GridControl.View>
    </dxg:GridControl>

    When MultiSelectMode is set to Cell, TableView will fire a SelectionChanged event where we can process the selection. The actual selection can be acquired by calling TableView.GetSelectedCells which returns an array of GridCell[].

    Example of binding the selection to a line chart:

    class ChartFact {
    public string Series { get; set; }
    public DateTime Argument { get; set; }
    public int Value { get; set; }
    }

    void view_SelectionChanged(object sender, GridSelectionChangedEventArgs e) {
    List<ChartFact> list = new List<ChartFact>();

    GridCell[] cells = view.GetSelectedCells();
    foreach (GridCell cell in cells) {
    ChartFact fact = new ChartFact {
    Series = ((IDataColumnInfo)cell.Column).Caption
    };

    DataRowView rowView = (DataRowView)grid.GetRow(cell.RowHandle);
    fact.Argument = (DateTime)rowView.Row[0];
    fact.Value = (int)rowView.Row[(string)fact.Series];
    list.Add(fact);
    }

    chartControl.DataSource = list;
    }

    WPF Grid Control - Cell Selection

    Cheers

    Azret

  • WPF Pivot Control and Unbound Expressions – v2010 vol 1

    The WPF Pivot Grid Control in DXperience v2010 vol 1 introduces a long requested feature, Unbound Expressions. It’s very easy to setup an unbound column, all you need to specify is the type and the expression itself. For example let’s say we have a fact table LoanProgram with APRs for auto loans from different lenders.

    public class LoanProgram {
    public string Bank { get; set; }
    public int Term { get; set; }
    public double APR { get; set; }
    }

    WPF Pivot Grid Control

    and we want to calculate the monthly payment on principal P ($86000).

    <dxpg:PivotGridControl x:Name="pivotGrid" 
    ShowColumnTotals="False" ShowRowTotals="False"
    ShowColumnGrandTotals="False"
    ShowRowGrandTotals="False">

    <dxpg:PivotGridControl.Fields>
    <dxpg:PivotGridField x:Name="fieldBank" FieldName="Bank" Area="RowArea"/>
    <dxpg:PivotGridField x:Name="fieldAPR" Area="DataArea" FieldName="APR" CellFormat="p"/>
    <dxpg:PivotGridField x:Name="fieldTerm" Area="ColumnArea" FieldName="Term"/>

    <dxpg:PivotGridField x:Name="fieldRate"
    Visible="False"
    Area="DataArea"
    Caption="Rate"
    UnboundType="Decimal"
    UnboundFieldName="Rate"
    CellFormat="p"
    UnboundExpression="([APR] / 12) "/>

    <dxpg:PivotGridField x:Name="fieldMonthlyPayment"
    Area="DataArea"
    Caption="Payment"
    CellFormat="c"
    UnboundType="Decimal"
    UnboundFieldName="MonthlyPayment"
    UnboundExpression="86000 * ([Rate]*Power(1+[Rate],[Term]))/(Power(1+[Rate],[Term])-1)"
    />


    </dxpg:PivotGridControl.Fields>
    </dxpg:PivotGridControl>
     
    Note: Notice an unbound field [Rate] can be used in another unbound expression.

    WPF Pivot Grid - Unbound Expressions

    As a bonus, the WPF Pivot Control comes with a build-in Expression Editor. This is especially useful when you want to have your end-users build the expressions.

    WPF Pivot Grid - Unbound Expression Editor

    For a list of all supported Operators and Functions please refer to the following help document.

    Cheers

    Azret

  • WPF Pivot Grid and Cell Templates – v2010 vol 1

    The WPF Pivot Grid provides a way to format cell values via it’s CellFormat property. The standard format specifiers are used. (MSDN Link) . So for Currency values we can use “C” or “c”, for scientific values “E” etc…  But as powerful as the format specifiers might be, sometimes you need a better control over the display and/or the appearance of cell values. Luckily, the WPF Pivot Grid fully supports Cell Templates.

    The DataContext provided to the cell template is CellsAreaItem

    public class CellsAreaItem : ScrollableAreaItemBase {
    public int ColumnIndex { get; }
    public object ColumnTotalValue { get; }
    public object ColumnValue { get; }
    public object ColumnValueDisplayText { get; }
    public override string DisplayText { get; }
    public int RowIndex { get; }
    public object RowTotalValue { get; }
    public object RowValue { get; }
    public object RowValueDisplayText { get; }
    public override object Value { get; }
    }
     
    Here is a fun little template that uses a progress bar to display values.
     
    <Grid.Resources>
    <DataTemplate x:Key="CellTemplate">
    <Grid>
    <ProgressBar Minimum="0" VerticalAlignment="Stretch" Margin="3"
    Maximum="{Binding Path=RowTotalValue, Mode=OneWay, Converter={local:RoundConverter}}"
    Value="{Binding Path=Value, Mode=OneWay, Converter={local:RoundConverter}}"/>
    </Grid>
    </DataTemplate>
    </Grid.Resources>

    public class RoundConverter : MarkupExtension, IValueConverter {
    public object Convert(object value, Type targetType, object parameter,
    System.Globalization.CultureInfo culture) {
    return System.Convert.ToInt32(value);
    }
    public object ConvertBack(object value, Type targetType, object parameter,
    System.Globalization.CultureInfo culture) {
    throw new NotImplementedException();
    }
    public override object ProvideValue(IServiceProvider serviceProvider) {
    return this;
    }
    }

    WPF Pivot Grid - Custom Cell Template

    Cheers

    Azret

    PS: To see how to bind a chart to a pivot grid click here.

  • WPF Pivot Table and Chart Integration – v2010 vol 1

    Just like our WinForms Pivot Grid is able to act as an input data source for a Chart Control (read here), The WPF Pivot Control in v2010.1 can do the same…

    Please read here on how to setup a WPF Pivot Grid that is shown in the picture below

    WPF Pivot Grid Conrol integrated with the Chart Control

    Just like the WinForms version, the WPF Pivot Grid’s chart data source has 3 fields:

    1. "Series": This would be the the series legend.
    2. "Arguments": This would be the X-axis.
    3. "Values": This would be the Y-axis.

    but unlike the WinForms version, the chart data source is exposed via the ChartDataSource. (In WinForms, the control itself was a data source)

    Here’s an example mark up of a 2D Line Chart bound to a Pivot Grid Control.

    <dxc:ChartControl Grid.Row="1" x:Name="chartControl" 
    DataSource="{Binding ElementName=pivotGrid, Path=ChartDataSource}">
    <dxc:ChartControl.Legend>
    <dxc:Legend ReverseItems="True" />
    </dxc:ChartControl.Legend>
    <dxc:ChartControl.Diagram>
    <dxc:XYDiagram2D SeriesDataMember = "Series">
    <dxc:XYDiagram2D.SeriesTemplate>
    <dxc:LineSeries2D ValueDataMember="Values"
    ArgumentDataMember="Arguments"></dxc:LineSeries2D>
    </dxc:XYDiagram2D.SeriesTemplate>
    </dxc:XYDiagram2D>
    </dxc:ChartControl.Diagram>
    </dxc:ChartControl>

    Cheers

    Azret

  • WPF Pivot Grid Control – v2010 vol 1

    In DXperience v10.1, the WPF Pivot Grid Control has caught up with it’s WinForms counterpart feature-wise.

    If you were waiting for it to start your new WPF app wait no more. Let’s take a closer look at some of the features.

    Getting Started

    Pivoting is most fun when you understand the data (the fact table) you are working with.

    Let’s use a basic product-orders that all are familiar with.

    • Table
      • Price
      • Product
      • Order Date

    WPF Pivot Grid Control

    To mark this up:

    <Window x:Class="WpfApplication1.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:dxpg="http://schemas.devexpress.com/winfx/2008/xaml/pivotgrid">
    <Grid>
    <dxpg:PivotGridControl x:Name="pivotGrid">
    <dxpg:PivotGridControl.Fields>
    <dxpg:PivotGridField FieldName="Extended Price" Caption="Price" Area="DataArea" AllowedAreas="DataArea" CellFormat="c"/>
    <dxpg:PivotGridField FieldName="ProductName" Area="RowArea" Caption="Product" />
    <dxpg:PivotGridField FieldName="OrderDate" Area="ColumnArea" Caption="Order Date"/>
    <dxpg:PivotGridField FieldName="CategoryName" Area="FilterArea" Caption="Category"/>
    </dxpg:PivotGridControl.Fields>
    </dxpg:PivotGridControl>
    </Grid>
    </Window>

    There are 3 data field areas (dimensions).
    1. ColumnArea – (Order Date)
    2. RawArea – (Product)
    3. DataArea – (Price)
    the 4th one, FilterArea, does not participate in calculations, it is a placeholder for your filter fields.
     
    WPF Pivot Grid Control - Filter Area 
     

    Interval Grouping and Date Fields

    In a lot of cases, cross-tabbing raw values is not very useful. This is especially true for the date fields.

    While seeing the aggregates per date is applicable sometimes, in most cases however, it is much more interesting to see

    values broken down by date parts. To help with that, there is a set of group interval functions.

    public enum PivotGroupInterval {
    ...
    Date,
    DateDay,
    DateDayOfWeek,
    DateDayOfYear,
    DateWeekOfMonth,
    DateWeekOfYear,
    DateMonth,
    DateQuarter,
    DateYear,
    YearAge,
    MonthAge,
    WeekAge,
    DayAge
    ...
    }
     
    For example to see the Price by OrderDate.Year we can use the DateYear group interval.
     
    <dxpg:PivotGridControl x:Name="pivotGrid">
    <dxpg:PivotGridControl.Fields>
    <dxpg:PivotGridField FieldName="OrderDate" Area="ColumnArea" GroupInterval="DateYear" Caption="Year"/>
    ...
    </dxpg:PivotGridControl.Fields>
    </dxpg:PivotGridControl>
     
    The Pivot Grid is not restricted to 3 dimensions. I can expand the OrderDate into 3: Year, Month, Day 
     
    <dxpg:PivotGridControl x:Name="pivotGrid">
    <dxpg:PivotGridControl.Fields>

    <dxpg:PivotGridField FieldName="CategoryName" Area="FilterArea" Caption="Category"/>
    <dxpg:PivotGridField FieldName="Extended Price" Caption="Price" Area="DataArea" AllowedAreas="DataArea" CellFormat="c"/>
    <dxpg:PivotGridField FieldName="ProductName" Area="RowArea" Caption="Product" />

    <dxpg:PivotGridField FieldName="OrderDate" Area="ColumnArea" AllowedAreas="ColumnArea" GroupInterval="DateYear" Caption="Year"/>
    <dxpg:PivotGridField FieldName="OrderDate" Area="ColumnArea" AllowedAreas="ColumnArea" GroupInterval="DateMonth" Caption="Month"/>
    <dxpg:PivotGridField FieldName="OrderDate" Area="ColumnArea" AllowedAreas="ColumnArea" GroupInterval="DateDay" Caption="Day"/>
    </dxpg:PivotGridControl.Fields>
    </dxpg:PivotGridControl>

    WPF Pivot Grid Control - Group Interval
     
    In 10.1 we have added a new Groups feature to better organize fields.
     
    <dxpg:PivotGridControl x:Name="pivotGrid">
    <dxpg:PivotGridControl.Fields>

    <dxpg:PivotGridField FieldName="Extended Price" Caption="Price" Area="DataArea" AllowedAreas="DataArea" CellFormat="c"/>
    <dxpg:PivotGridField FieldName="ProductName" Area="RowArea" Caption="Product" />

    <dxpg:PivotGridField FieldName="OrderDate" Group="{Binding ElementName=PivotGridGroup1}" Area="ColumnArea" AllowedAreas="ColumnArea" GroupInterval="DateYear" Caption="Year"/>
    <dxpg:PivotGridField FieldName="OrderDate" Group="{Binding ElementName=PivotGridGroup1}" Area="ColumnArea" AllowedAreas="ColumnArea" GroupInterval="DateMonth" Caption="Month"/>
    <dxpg:PivotGridField FieldName="OrderDate" Group="{Binding ElementName=PivotGridGroup1}" Area="ColumnArea" AllowedAreas="ColumnArea" GroupInterval="DateDay" Caption="Day"/>

    <dxpg:PivotGridField FieldName="CategoryName" Area="FilterArea" Caption="Category"/>

    </dxpg:PivotGridControl.Fields>

    <dxpg:PivotGridControl.Groups>
    <dxpg:PivotGridGroup x:Name="PivotGridGroup1" Caption="Order Date" />
    </dxpg:PivotGridControl.Groups>

    </dxpg:PivotGridControl>

     
    WPF Pivot Grid Control - Groups

    Fields within a group are collapsible so you can create pivot repots as drilled down as you want without loosing the ability to
    aggregate by a specific interval.
     
    Cheers
    Azret
     

LIVE CHAT

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

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

FOLLOW US

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

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