Providing Data
Basic Concepts > Manipulating Data > Providing Data > Providing Data

Glossary Item Box

Prerequisite Knowledge
Object Model Overview: DataGridCollectionView Class

The data items that populate a grid are provided by the DataGridCollectionView or DataGridCollectionViewSource (in XAML) assigned to the ItemsSource property of the DataGridControl class. These views allow the data items contained in a grid to be grouped sorted, and/or filtered (see Example 1).  

In order for the DataGridCollectionViewSource to create a custom view for the data items that will eventually be displayed in a grid, it must be bound to the underlying data source or data items must be provided manually via the SourceItems property. In turn, a grid will be bound to the DataGridCollectionViewSource that contains the customized data-item view (see also GroupingSorting, and Filtering).

DataRow objects are the UI representation of data items. They have a limited lifespan and exist only while they are visible in a grid's viewport; this is called virtualization and is the reason that the Items property accesses the data items and not the data rows. The SelectedItem, SelectedItems, and CurrentItem properties of the DataGridControl class also reference data items and not data rows (see Example 3).

Programmatically, when the DataGridCollectionView is bound to a data source, the ItemProperties.Clear method must be called prior to adding DataGridItemProperty objects to the ItemProperties collection to remove items that were automatically added when the DataGridCollectionView was instantiated.

Detail Data (Master/Detail)

When a grid is in a table-view layout, its data items can display detail data that is usually provided by the detail descriptions defined in the DataGridCollectionView or DataGridCollectionViewSource to which the grid is bound. Each data item in the grid and any resulting details can have one or more sibling details as well as one or more grandchild details. By default, detail descriptions are automatically created for:

How same-level details are displayed depends on their associated DetailConfiguration, which can be defined by a grid or by any other detail configuration. Detail configurations can be automatically detected by setting the AutoCreateDetailConfigurations property of a grid or another detail configuration to true (by default, false), or they can be explicitly provided by adding DetailConfiguration objects to the their DetailConfigurations property (see Detail Configurations topic).

Inserting Data

The DataGridCollectionView supports insertion as long as the underlying DataGridCollectionView-wrapped collection implements the IBindingList interface and its AllowNew property returns true. In this case, the AddNew method can be used to add new data items to the underlying collection, while the EndNew and CancelNew methods can be used to commit the new item or cancel its addition.

At runtime, new data items can be inserted by end users into a grid, through the use of an InsertionRow, which can be added to the fixed header, fixed footer, header, or footer sections of a grid (see Header and Footers). Programmatically, rows can be inserted directly through the data source to which a grid is bound.


Figure 1: Insertion row
EnlargeClick to enlarge

The content of the cells contained in an insertion row can be initialized through the use of a grid's InitializingInsertionRow event (see Example 4).

Examples 

All examples in this topic assume that the grid is bound to the Orders table of the Northwind database, unless stated otherwise.

ShowExample 1: Binding to a data table

This first code example demonstrates how to create a connection to the Access version of the Northwind database and create a property named "Orders" to which the grid will be bound. The code should be placed in the App.xaml.as file.

VB.NET Copy Code

Imports System.Data.OleDb
Imports System.Data

Shared Sub New()
  Dim dataSet As New DataSet()
  Dim mdbfile As String = "Data\Northwind.mdb"
  Dim connString As String = String.Format("Provider=Microsoft.Jet.OLEDB.4.0; Data Source={0}", mdbfile)
  Dim conn As New OleDbConnection(connString)
  Dim adapter As New OleDbDataAdapter()

  adapter.SelectCommand = New OleDbCommand("SELECT * FROM Orders;", conn)
  adapter.Fill(dataSet, "Orders")
  m_orders = dataSet.Tables("Orders")
End Sub

Public Shared ReadOnly Property Orders() As DataTable
  Get
    Return m_orders
  End Get
End Property
Private Shared m_orders As DataTable
C# Copy Code

using System.Data.OleDb;
using System.Data;

static App()
{
 DataSet dataSet =
new DataSet();
 
string mdbFile = @"Data\Northwind.mdb";
 
string connString = String.Format( "Provider=Microsoft.Jet.OLEDB.4.0; Data Source={0}", mdbFile );

 OleDbConnection conn =
new OleDbConnection( connString );
 OleDbDataAdapter adapter =
new OleDbDataAdapter();

 adapter.SelectCommand =
new OleDbCommand( "SELECT * FROM Orders;", conn );
 adapter.Fill( dataSet,
"Orders" );

 m_orders = dataSet.Tables[
"Orders" ];
}

public static DataTable Orders
{
 get
 {
   
return m_orders;
 }
}

private static DataTable m_orders;

The next example demonstrates how to bind a grid to the Orders table, which is retrieved through the Orders property implemented in the code above.

XAML Copy Code
<Grid xmlns:xcdg="http://schemas.xceed.com/wpf/xaml/datagrid">
  <Grid.Resources>      
  <xcdg:DataGridCollectionViewSource x:Key="cvs_orders"
                                  
Source="{Binding Source={x:Static Application.Current},
                                                      
Path=Orders}"/>

  </Grid.Resources>

  <xcdg:DataGridControl x:Name="OrdersGrid"
                        
ItemsSource="{Binding Source={StaticResource cvs_orders}}"/>
</Grid>

ShowExample 2: Binding to an array

The following example demonstrates how to bind a grid to an array defined in the resources of the containing grid.

XAML Copy Code

<Grid xmlns:s="clr-namespace:System;assembly=mscorlib"
      xmlns:xcdg="
http://schemas.xceed.com/wpf/xaml/datagrid">                     
  <Grid.Resources>

  <x:Array x:Key="data_list" Type="{x:Type s:String}">
    
<s:String>Sunday</s:String>
    
<s:String>Monday</s:String>
    
<s:String>Tuesday</s:String>
    
<s:String>Wednesday</s:String>
    
<s:String>Thursday</s:String>
    
<s:String>Friday</s:String>
    
<s:String>Saturday</s:String>
  
</x:Array>

  </Grid.Resources>

  <xcdg:DataGridControl x:Name="OrdersGrid"
                        
ItemsSource="{StaticResource data_list}"/>

</Grid>

ShowExample 3: Retrieving values from the current item

The following example demonstrates how to retrieve the value of the ShipCountry and ShipCity properties of the current item and display them in TextBlocks located above the grid. Note that an item in a grid must be current in order for the information to be displayed.

XAML Copy Code
<Grid xmlns:xcdg="http://schemas.xceed.com/wpf/xaml/datagrid">
  <Grid.Resources>
    <xcdg:DataGridCollectionViewSource x:Key="cvs_orders"
                                    Source="{Binding Source={x:Static Application.Current},
                                                      Path=Orders}"/>
   </Grid.Resources>
   <DockPanel>   
      <StackPanel Orientation="Horizontal" DockPanel.Dock="Top">
        <TextBlock Text="{Binding ElementName=OrdersGrid, Path=CurrentItem[ShipCountry]}"/>
        <TextBlock Text=" - "/>
        <TextBlock Text="{Binding ElementName=OrdersGrid, Path=CurrentItem[ShipCity]}"/>
      </StackPanel>    
      <xcdg:DataGridControl x:Name="OrdersGrid"
                            ItemsSource="{Binding Source={StaticResource cvs_orders}}"
                            DockPanel.Dock="Bottom">
      </xcdg:DataGridControl>
   </DockPanel>
</Grid>

ShowExample 4: Initializing an insertion row

The following example demonstrates how to initialize the values of the ShipCountry, ShipCity, and ShipVia columns in an insertion row located in the fixed headers. The handler for the InitializingInsertionRow event is defined in the code-behind class.

The columns that are contained in the grid will be limited to those specified in the ItemProperties of the DataGridCollectionViewSource.

XAML Copy Code
<Grid xmlns:xcdg="http://schemas.xceed.com/wpf/xaml/datagrid">
  <Grid.Resources>
    <xcdg:DataGridCollectionViewSource x:Key="cvs_orders"
                                    Source="{Binding Source={x:Static Application.Current},
                                                        Path=Orders}">
      <xcdg:DataGridCollectionViewSource.ItemProperties>
        <xcdg:DataGridItemProperty Name="ShipCountry" Title="Country"/>
        <xcdg:DataGridItemProperty Name="ShipCity" Title="City"/>
        <xcdg:DataGridItemProperty Name="ShipVia" Title="Ship With"/>
      </xcdg:DataGridCollectionViewSource.ItemProperties>
    </xcdg:DataGridCollectionViewSource>
   </Grid.Resources>

   <xcdg:DataGridControl x:Name="OrdersGrid"
                         
ItemsSource="{Binding Source={StaticResource cvs_orders}}"
                         
InitializingInsertionRow="InitInsertion">
       <xcdg:DataGridControl.View>
         <xcdg:CardView>
           <xcdg:CardView.FixedHeaders>
              
<DataTemplate>
                 
<xcdg:InsertionRow/>
              
</DataTemplate>
           
</xcdg:CardView.FixedHeaders>
         </xcdg:CardView>
      </xcdg:DataGridControl.View>
   </xcdg:DataGridControl>
</Grid>
VB.NET Copy Code
Private Sub InitInertion( ByVal sender As Object, ByVal e As InitializingInsertionRowEventArgs )

   e.InsertionRow.Cells( "ShipCountry" ).Content =
              Me.ParseCountry( System.Globalization.CultureInfo.CurrentCulture.DisplayName )

   e.InsertionRow.Cells( "ShipCity" ).Content = "Enter City Here"
   e.InsertionRow.Cells( "ShipVia" ).Content = 1

End Sub

Private Function ParseCountry( ByVal name As String ) As String

   Dim startIndex As Integer = name.IndexOf( "(" )
   Return name.SubString( startIndex + 1, name.Length - startIndex - 2 )
End Function

C# Copy Code
private void InitInsertion( object sender, InitializingInsertionRowEventArgs e )
{

   e.InsertionRow.Cells[ "ShipCountry" ].Content =
         this.ParseCountry( System.Globalization.CultureInfo.CurrentCulture.DisplayName );

   e.InsertionRow.Cells[ "ShipCity" ].Content = "Enter City Here";
   e.InsertionRow.Cells[ "ShipVia" ].Content = "1";

}

private string ParseCountry( string name )
{
   int startIndex = name.IndexOf( "(" );
   return name.Substring( startIndex + 1, name.Length - startIndex - 2 );
}

ShowExample 5: Providing unbound data

The following example demonstrates how to add Person data to a custom ObservableCollection of Person objects. 

XAML Copy Code

<Grid xmlns:xcdg="http://schemas.xceed.com/wpf/xaml/datagrid"
      xmlns:local="clr-namespace:Xceed.Wpf.Documentation"
      xmlns:scm="clr-namespace:System.ComponentModel;assembly=WindowsBase">
  <Grid.Resources>

   <local:PersonObservableCollection x:Key="personData">
     
<local:Person FirstName="Jenny"
                   
LastName="Beland"
                   
Occupation="Writer"/>
     
<local:Person FirstName="Francois"
                   
LastName="Carignan"
                   
Occupation="Developer"/>
     
<local:Person FirstName="Pascal"
                   
LastName="Bourque"
                   
Occupation="Developer"/>
     
<local:Person FirstName="Michel"
                   
LastName="Fortin"
                   
Occupation="Developer"/>
     
<local:Person FirstName="Marc"
                   
LastName="Laroche"
                   
Occupation="Developer"/>
     
<local:Person FirstName="Pierre-Luc"
                   
LastName="Ledoux"
                   
Occupation="Developer"/>
     
<local:Person FirstName="Mathieu"
                   
LastName="Drimonakos"
                   
Occupation="TechnicalSupport"/>
     
<local:Person FirstName="Catherine"
                   
LastName="Sauzede"
                   
Occupation="Infograph"/>
   
</local:PersonObservableCollection>

   
<xcdg:DataGridCollectionViewSource x:Key="cvs_person"
                                      
ItemType="{x:Type local:Person}"
                                      
Source="{StaticResource personData}">

      <xcdg:DataGridCollectionViewSource.GroupDescriptions>
        <xcdg:DataGridGroupDescription PropertyName="Occupation"/>
      </xcdg:DataGridCollectionViewSource.GroupDescriptions>

      <xcdg:DataGridCollectionViewSource.SortDescriptions>
        <scm:SortDescription PropertyName="Occupation"
                              Direction="Ascending"/>
      </xcdg:DataGridCollectionViewSource.SortDescriptions>
    </xcdg:DataGridCollectionViewSource>
  </Grid.Resources>

 <xcdg:DataGridControl x:Name="PersonGrid"
                       
ItemsSource="{Binding Source={StaticResource cvs_person}}"/>

</Grid>

ShowExample 6: Binding to a LINQ table

The following example demonstrates how to bind a grid to a LINQ table and submit any modifications made to the data items using the SubmitChanges method. 

This example assumes that a new LINQ to SQL Classes item named Northwind.dbml has been added to the project and that it contains the Orders, Customers, and Shippers tables. The Northwind.designer.cs that is created at the same time represents the NorthwindDataContext and should automatically contain all the relevant members. It also assumes that a property named LinqDataContext that returns a new instance of the NorthwindDataContext exists in the App.xaml.cs code-behind file.

For more information on LINQ, refer to The LINQ Project Web site.

XAML Copy Code

<Grid xmlns:xcdg="http://schemas.xceed.com/wpf/xaml/datagrid "
      xmlns:local="clr-namespace:Xceed.Wpf.Documentation">
  <Grid.Resources>

    <xcdg:DataGridCollectionViewSource x:Key="cvs_orders"
                                       
Source="{Binding Source={x:Static Application.Current},
                                                        
Path=LinqDataContext.Orders}"/>

    <DataTemplate DataType="{x:Type local:Shipper}">
      <TextBlock Text="{Binding CompanyName}"/>
    </DataTemplate>

    <DataTemplate DataType="{x:Type local:Customer}">
      <TextBlock Text="{Binding CompanyName}"/>
    </DataTemplate>

    <DataTemplate DataType="{x:Type local:Employee}">
      <StackPanel Orientation="Horizontal">
        <TextBlock Text="{Binding FirstName}"/>
        <TextBlock Text=" " />
        <TextBlock Text="{Binding LastName}"/>
      </StackPanel>
    </DataTemplate>

    <xcdg:CellEditor x:Key="employeeEditor">
      <xcdg:CellEditor.EditTemplate>
        <DataTemplate>
          <ComboBox ItemsSource="{Binding Source={x:Static Application.Current}, 
                                          Path=LinqDataContext.Employees}"
                    SelectedItem="{xcdg:CellEditorBinding}"/>
        </DataTemplate>
      </xcdg:CellEditor.EditTemplate>
    </xcdg:CellEditor>

    <xcdg:CellEditor x:Key="customerEditor">
      <xcdg:CellEditor.EditTemplate>
        <DataTemplate>
          <ComboBox ItemsSource="{Binding Source={x:Static Application.Current},
                                          Path=LinqDataContext.Customers}"
                    SelectedItem="{xcdg:CellEditorBinding}"/>
        </DataTemplate>
      </xcdg:CellEditor.EditTemplate>
    </xcdg:CellEditor>

    <xcdg:CellEditor x:Key="shipperEditor">
      <xcdg:CellEditor.EditTemplate>
        <DataTemplate>
          <ComboBox ItemsSource="{Binding Source={x:Static Application.Current}, Path=LinqDataContext.Shippers}"
                    SelectedItem="{xcdg:CellEditorBinding}"/>
        </DataTemplate>
      </xcdg:CellEditor.EditTemplate>
    </xcdg:CellEditor>
  </Grid.Resources>

  <DockPanel>

    <Button Content="Save Modifications"
            
Click="SaveModifications"
            
DockPanel.Dock="Top" />
    
<xcdg:DataGridControl x:Name="OrdersGrid"
                          
ItemsSource="{Binding Source={StaticResource cvs_orders}}">

      <xcdg:DataGridControl.Columns>
        <xcdg:Column FieldName="OrderID"
                     Visible="False"/>
        <xcdg:Column FieldName="EmployeeID"
                     Visible="False"/>
        <xcdg:Column FieldName="Employee"
                     CellEditor="{StaticResource employeeEditor}"/>
        <xcdg:Column FieldName="CustomerID"
                     Visible="False"/>
        <xcdg:Column FieldName="Customer"
                     CellEditor="{StaticResource customerEditor}"
                     Title="Company Name"/>
        <xcdg:Column FieldName="ShipVia"
                     Visible="False"/>
        <xcdg:Column FieldName="Shipper"
                     CellEditor="{StaticResource shipperEditor}"/>
      </xcdg:DataGridControl.Columns>
      <xcdg:DataGridControl.View>
        <xcdg:TableView>
          <xcdg:TableView.FixedFooters>
            <DataTemplate>
              <xcdg:InsertionRow/>
            </DataTemplate>
          </xcdg:TableView.FixedFooters>
        </xcdg:TableView>
      </xcdg:DataGridControl.View>
    </xcdg:DataGridControl>
  </DockPanel>
</Grid>

VB.NET Copy Code
Private Sub SaveModifications( sender As Object, e As RoutedEventArgs )
   App.LinqDataContext.SubmitChanges()
End Sub
C# Copy Code
private void SaveModifications( object sender, RoutedEventArgs e )
{     
 App.LinqDataContext.SubmitChanges();
}

ShowExample 7: Binding to a LINQ query (SQL)

The following example demonstrates how to bind a grid to an SQL LINQ query and submit any modifications made to the data items using the SubmitChanges method. 

Although existing data items can be modified and the changes committed, it is not possible to insert new data items.

This example assumes that a new LINQ to SQL Classes item named Northwind.dbml has been added to the project and that it contains the Orders, Customers, and Shippers tables. The Northwind.designer.cs that is created at the same time represents the NorthwindDataContext and should automatically contain all the relevant members. It also assumes that a property named OrdersQuery that returns a new new query based on the value selected in the combo box.

The Window1 class implements INotifyPropertyChanged so that the DataGridCollectionViewSource can be notified when the query changes in order to refresh its content.

For more information on LINQ, refer to The LINQ Project Web site.

XAML Copy Code

<Grid xmlns:xcdg="http://schemas.xceed.com/wpf/xaml/datagrid"
      xmlns:local="clr-namespace:Xceed.Wpf.Documentation">
  <Grid.Resources>

    <xcdg:DataGridCollectionViewSource x:Key="cvs_orders"
                                      
Source="{Binding RelativeSource={RelativeSource AncestorType={x:Type Window}},
                                                       
Path=OrdersQuery}">

      <xcdg:DataGridCollectionViewSource.GroupDescriptions>
        <xcdg:DataGridGroupDescription PropertyName="Shipper"/>
      </xcdg:DataGridCollectionViewSource.GroupDescriptions>
    </xcdg:DataGridCollectionViewSource>

    <DataTemplate DataType="{x:Type local:Shipper}">
      <TextBlock Text="{Binding CompanyName}"/>
    </DataTemplate>

    <DataTemplate DataType="{x:Type local:Customer}">
      <TextBlock Text="{Binding CompanyName}"/>
    </DataTemplate>

    <DataTemplate DataType="{x:Type local:Employee}">
      <StackPanel Orientation="Horizontal">
        <TextBlock Text="{Binding FirstName}"/>
        <TextBlock Text=" " />
        <TextBlock Text="{Binding LastName}"/>
      </StackPanel>
    </DataTemplate>        
  </Grid.Resources>

  <DockPanel>
    <StackPanel Orientation="Horizontal"
                DockPanel.Dock="Top">

      <Button Content="Save Modifications"
              
Click="SaveModifications"/>
      
<ComboBox x:Name="ShipperCombo"
                
ItemsSource="{Binding Source={x:Static Application.Current}, Path=LinqDataContext.Shippers}"
                
SelectionChanged="ShipperSelectionChanged"/>

    </StackPanel>

    <xcdg:DataGridControl x:Name="OrdersGrid"
                          
ItemsSource="{Binding Source={StaticResource cvs_orders}}">

      <xcdg:DataGridControl.Columns>
        <xcdg:Column FieldName="Shipper"
                     VisiblePosition="0"/>
        <xcdg:Column FieldName="OrderID"
                     Visible="False"/>
        <xcdg:Column FieldName="EmployeeID"
                     Visible="False"/>
        <xcdg:Column FieldName="CustomerID"
                     Visible="False"/>
        <xcdg:Column FieldName="Customer"
                     Title="Company Name"/>
        <xcdg:Column FieldName="ShipVia"
                     Visible="False"/>
      </xcdg:DataGridControl.Columns>
    </xcdg:DataGridControl>
  </DockPanel>
</Grid>

VB.NET Copy Code
Namespace Xceed.Wpf.Documentation

Public Partial Class Window1
    Inherits Window
    Implements INotifyPropertyChanged
    Public Sub New()
      InitializeComponent()
    End Sub

    Private m_query As IEnumerable = Nothing
    Public Property OrdersQuery() As IEnumerable
      Get
        If m_query Is Nothing Then
          m_query = From orders In App.LinqDataContext.Orders _
                    Select orders
        End If

        Return m_query
      End Get
      Set
        m_query = Value
        Me.OnPropertyChanged(New PropertyChangedEventArgs("OrdersQuery"))
      End Set
    End Property

    Private Sub ShipperSelectionChanged(ByVal sender As Object, ByVal e As SelectionChangedEventArgs)
      Me.OrdersQuey = From orders In App.LinqDataContext.Orders _
                 Where orders.Shipper.CompanyName = CTYpe( Me.ShipperCombo.SelectedValue, Shipper).CompanyName _
                 Select orders
    End Sub

    Private Sub SaveModifications(ByVal sender As Object, ByVal e As RoutedEventArgs)
      App.LinqDataContext.SubmitChanges()
    End Sub

    Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged

    Private Sub OnPropertyChanged(ByVal e As PropertyChangedEventArgs)
      If Me.PropertyChangedEvent Is Nothing Then
        Return
      End If

      RaiseEvent PropertyChanged(Me, e)
    End Sub
  End Class
End Namespace
C# Copy Code

namespace Xceed.Wpf.Documentation
{
 
public partial class Window1 : Window, INotifyPropertyChanged
 {
   
public Window1()
   {
     InitializeComponent();     
   }

   
private IEnumerable m_query = null;
   
public IEnumerable OrdersQuery
   {
     get
     {
       
if( m_query == null )
       {
         m_query = from orders
in App.LinqDataContext.Orders
                   select orders;
       }
       
return m_query;
     }
     set
     {
       m_query = value;
       
this.OnPropertyChanged( new PropertyChangedEventArgs( "OrdersQuery" ) );
     }
   }

   
private void ShipperSelectionChanged( object sender, SelectionChangedEventArgs e )
   {
     
this.OrdersQuery = from orders in App.LinqDataContext.Orders
                 where orders.Shipper.CompanyName == ( ( Shipper )
this.ShipperCombo.SelectedValue ).CompanyName
                 select orders;
   }

   
private void SaveModifications( object sender, RoutedEventArgs e )
   {     
     App.LinqDataContext.SubmitChanges();
   }

   
public event PropertyChangedEventHandler PropertyChanged;
   
private void OnPropertyChanged( PropertyChangedEventArgs e )
   {
     
if( this.PropertyChanged == null )
       
return;
     
this.PropertyChanged( this, e );
   }
 }
}

ShowExample 8: Binding to a LINQ query (XML)

The following example demonstrates how to bind a grid to an XML query on an XDocument that loads the XML version of the Orders table of the Northwind database.

The content of the resulting grid will not be editable.
XAML Copy Code

<Grid xmlns:xcdg="http://schemas.xceed.com/wpf/xaml/datagrid">
  <Grid.Resources>

    <xcdg:DataGridCollectionViewSource x:Key="cvs_orders"
                    
Source="{Binding RelativeSource={RelativeSource AncestorType={x:Type Window}},
                                     
Path=XmlData}"/>

  </Grid.Resources>

 

  <xcdg:DataGridControl x:Name="OrdersGrid"
                       
ItemsSource="{Binding Source={StaticResource cvs_orders}}"/>

</Grid>

The following code provides the implementation for the XmlData property, which returns the query result.

VB.NET Copy Code
Public ReadOnly Property XmlData() As IEnumerable
  Get
    Dim document As XDocument = App.NorthwindDocument

    Dim data = From order In document.Element("dataroot").Descendants("Orders") _
               Select New With {.ShipCountry = order.Element("ShipCountry").Value, _
                                .ShipCity = order.Element("ShipCity").Value, _
                                .ShipAddress = order.Element("ShipAddress").Value, _
                                .ShipName = order.Element("ShipName").Value, _
                                .Freight = order.Element("Freight").Value}
    Return data.ToList()
  End Get
End Property
C# Copy Code

 

public IEnumerable XmlData
{
 get
 {
   XDocument document = App.NorthwindDocument;

   var data = from order
in document.Element( "dataroot" ).Descendants( "Orders" )
              select
new
              {
                
ShipCountry = order.Element( "ShipCountry" ).Value,
                ShipCity = order.Element(
"ShipCity" ).Value,
                ShipAddress = order.Element(
"ShipAddress" ).Value,
                ShipName = order.Element(
"ShipName" ).Value,
                ShipVia = order.Element(
"ShipVia" ).Value,
                Freight = order.Element(
"Freight" ).Value
              };
   
return data.ToList();
 }
}

ShowExample 9: Providing groupable and sortable XML data

The following example demonstrates how to bind a grid to an XML data source whose values can be grouped and sorted. In order to support grouping and sorting of XML data, the following classes were created:

  • XmlPropertyDescriptor: Derives from the PropertyDescriptor class and overrides the GetValue method in which the value of the appropriate node is retrieved and its value returned after its type has been changed to the type specified by the override of the PropertyType property.
  • XmlDataGridItemProperty: Derives from the DataGridItemProperty class and sets its PropertyDescriptor property to use an XmlPropertyDescriptor.

For the purposes of this example, data will be retrieved from an XML file that contains the data exported from the Orders table of the Northwind database.

Implementation of the XmlPropertyDescriptor class:

VB.NET Copy Code

Imports System
Imports System.Collections.Generic
Imports System.Linq
Imports System.Text
Imports System.ComponentModel
Imports System.Xml
Imports System.Windows

Namespace Xceed.Wpf.Documentation

  Public Class XmlPropertyDescriptor
               Inherits PropertyDescriptor

    Public Sub New( ByVal itemProperty As XmlDataGridItemProperty )
      MyBase.New( "None", Nothing )


      If itemProperty Is Nothing Then
        Throw New ArgumentNullException( "itemProperty" )
      End If
 

      m_itemProperty = itemProperty
    End Sub

    Public Overrides ReadOnly Property DisplayName As String
      Get
        Return m_itemProperty.Name  
      End Get
    End Property

    Public Overrides Function CanResetValue( ByVal component As Object ) As Boolean
      Return False
    End Function

    Public Overrides ReadOnly Property ComponentType As Type
      Get
        Return GetType( XmlElement );
      End Get

    End Property

    Public Override Function GetValue( ByVal component As Object ) As Object
      Dim node As XmlElement = TryCase( component, XmlElement )

      If node Is Nothing Then
        Return Nothing
      End If

      Dim retval As Object = Nothing
      Dim childNode As XmlNode = node.SelectSingleNode( m_itemProperty.Name )

      If Not childNode Is Nothing Then
        retval = Convert.ChangeType( childNode.InnterText, Me.PropertyType )
      End If

      Return retval
    End Function

    Public Overrides ReadOnly Property PropertyType As Type
      Get
        Return m_itemProperty.DataType
      End Get
    End Property

    Public Overrides ReadOnly Property IsReadOnly As Boolean
      Get
        Return False
      End Get
    End Property

    Public Overrides Sub ResetValue( ByVal component As Object )
    End Sub

    Public Overrides Sub SetValue( ByVal component As Object, ByVal value As Object )
      Dim node As XmlElement = TryCast( component, XmlElement )

      If Node Is Nothing Then
        Return
      End If

      node.SelectSingleNode( m_itemProperty.Name ).InnerText = value.ToString()
    End Sub

    Public Overrides Function ShouldSerializeValue( ByVal component As Object ) As Boolean
      Return False
    End Function

    Private m_itemProperty As XmlDataGridItemProperty
  End Class
End Namespace

C# Copy Code

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.Xml;
using System.Windows;

namespace Xceed.Wpf.Documentation
{

 public class XmlPropertyDescriptor : PropertyDescriptor

 {
    public XmlPropertyDescriptor( XmlDataGridItemProperty itemProperty )
      : base( "None", null )
    {
      if( itemProperty == null )
        throw new ArgumentNullException( "itemProperty" );

      m_itemProperty = itemProperty;
    }

    public override string DisplayName
    {
      get
      {
        return m_itemProperty.Name;
      }
    }

    public override bool CanResetValue( object component )
    {
      return false;
    }

    public override Type ComponentType
    {
      get
      {
        return typeof( XmlElement );
      }
    }

    public override object GetValue( object component )
    {
      XmlElement node = component
as XmlElement;

      
if( node == null )
        
return null;

      
object retval = null;
      XmlNode childNode = node.SelectSingleNode( m_itemProperty.Name );

      
if( childNode != null )
      {
        retval = Convert.ChangeType( childNode.InnerText,
this.PropertyType );
      }

      
return retval;
    }

    
public override Type PropertyType
    {
      get
      {
        
return m_itemProperty.DataType;
      }
    }

    public override bool IsReadOnly
    {
      get
      {
        return false;
      }
    }

    public override void ResetValue( object component )
    {
    }

    public override void SetValue( object component, object value )
    {
      XmlElement node = component as XmlElement;

      if( node == null )
        return;

      node.SelectSingleNode( m_itemProperty.Name ).InnerText = value.ToString();
    }

    public override bool ShouldSerializeValue( object component )
    {
      return false;
    }

    private XmlDataGridItemProperty m_itemProperty;
  }
}

Implementation of the XmlDataGridItemProperty class:

VB.NET Copy Code

Imports System
Imports System.Collections.Generic
Imports System.Linq
Imports sing System.Text
Imports Xceed.Wpf.DataGrid
Imports System.Xml

Namespace Xceed.Wpf.Documentation

  Public Class XmlDataGridItemProperty
               Inherits DataGridItemProperty
    Public Sub New()
      MyBase.New()
      Me.PropertyDescriptor = New XmlPropertyDescriptor( Me )
    End Sub
  End Class

End Namespace

C# Copy Code

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Xceed.Wpf.DataGrid;
using System.Xml;

namespace Xceed.Wpf.Documentation
{

 public class XmlDataGridItemProperty: DataGridItemProperty
 {
   
public XmlDataGridItemProperty()               
     :
base()
   {     
     
this.PropertyDescriptor = new XmlPropertyDescriptor( this );     
   }
 }

}

XAML Copy Code

<Grid xmlns:xcdg="http://schemas.xceed.com/wpf/xaml/datagrid">
  <Grid.Resources>

   <XmlDataProvider x:Key="xmlData"
                    Source="Data\Northwind.xml"
                    XPath="dataroot/Orders" />
 
   <xcdg:DataGridCollectionViewSource x:Key="cvs_xml"
                                      Source="{Binding Source={StaticResource xmlData}}">

     <xcdg:DataGridCollectionViewSource.ItemProperties>
        
<local:XmlDataGridItemProperty Name="OrderID"
                                       
DataType="{x:Type s:Int32}" />
        
<local:XmlDataGridItemProperty Name="ShipCountry"
                                       
DataType="{x:Type s:String}"
                                       
Title="Ship Country" />
        
<local:XmlDataGridItemProperty Name="ShipCity"
                                       
DataType="{x:Type s:String}"
                                       
Title="Ship City" />
        
<local:XmlDataGridItemProperty Name="Freight"
                                       
DataType="{x:Type s:Double}" />
        
<local:XmlDataGridItemProperty Name="OrderDate"
                                       
DataType="{x:Type s:DateTime}" />
     
</xcdg:DataGridCollectionViewSource.ItemProperties>

   </xcdg:DataGridCollectionViewSource>
  </Grid.Resources>
 
  <xcdg:DataGridControl x:Name="XmlGrid"
                      ItemsSource="{Binding Source={StaticResource cvs_xml}}"/>
</Grid>

ShowExample 10: Binding to a master/detail data table

The following example demonstrates how to bind a grid to a DataTable that contains DataRelations that will be displayed as child and grandchild detail data.

The code below demonstrates how to create a connection to the Access version of the Northwind database and create a property named "Employees" that retrieves its values from the Employees data table and to which a child and grandchild detail are added.

VB.NET Copy Code

Shared Sub New()

  Dim dataSet As New DataSet()
  Dim mdbfile As String = "Data\Northwind.mdb"
  Dim connString As String = String.Format("Provider=Microsoft.Jet.OLEDB.4.0; Data Source={0}", mdbfile)
  Dim conn As New OleDbConnection(connString)
  Dim adapter As New OleDbDataAdapter()
  m_adapter = New OleDbDataAdapter()
  m_adapter.SelectCommand = New OleDbCommand( "SELECT * FROM Employees;", conn )
  m_adapter.Fill( dataSet, "Employees" )
  m_employees = dataSet.Tables( "Employees" )

  m_adapter = New OleDbDataAdapter()
  m_adapter.SelectCommand = New OleDbCommand( "SELECT * FROM Orders;", conn )
  m_adapter.Fill( dataSet, "Orders" )
  m_orders = dataSet.Tables( "Orders" )
 
  m_adapter = New OleDbDataAdapter()
  m_adapter.SelectCommand = New OleDbCommand( "SELECT * FROM [Order Details];", conn )
  m_adapter.Fill( dataSet, "Order Details" )
  m_orderDetails = dataSet.Tables( "Order Details" )

  m_employees.ChildRelations.Add( New DataRelation( "Employee_Orders", m_employees.Columns( "EmployeeID" ), m_orders.Columns( "EmployeeID" ) ) )
  m_orders.ChildRelations.Add( New DataRelation( "Order_OrderDetails", m_orders.Columns( "OrderID" ), m_orderDetails.Columns( "OrderID" ) ) )

End Sub

Public Shared ReadOnly Property Employees As DataTable
  Get
    Return m_employees
   End Get
End Property

Private Shared m_employees As DataTable
Private Shared m_orders As DataTable
Private Shared m_orderDetails As DataTable
Private Shared m_adapter As OleDbDataAdapter = Nothing

C# Copy Code

static App()
{

 DataSet dataSet = new DataSet();
 
string mdbFile = @"Data\Northwind.mdb";
 
string connString = String.Format( "Provider=Microsoft.Jet.OLEDB.4.0; Data Source={0}", mdbFile );
 OleDbConnection conn =
new OleDbConnection( connString );
 m_adapter =
new OleDbDataAdapter();
 m_adapter.SelectCommand =
new OleDbCommand( "SELECT * FROM Employees;", conn );
 m_adapter.Fill( dataSet,
"Employees" );
 m_employees = dataSet.Tables
[ "Employees" ];    

  m_adapter = new OleDbDataAdapter();
  m_adapter.SelectCommand = new OleDbCommand( "SELECT * FROM Orders;", conn );
  m_adapter.Fill( dataSet, "Orders" );
  m_orders = dataSet.Tables[ "Orders" ];
 
  m_adapter = new OleDbDataAdapter();
  m_adapter.SelectCommand = new OleDbCommand( "SELECT * FROM [Order Details];", conn );
  m_adapter.Fill( dataSet, "Order Details" );
  m_orderDetails = dataSet.Tables[ "Order Details" ];

 m_employees.ChildRelations.Add( new DataRelation( "Employee_Orders", m_employees.Columns[ "EmployeeID" ], m_orders.Columns[ "EmployeeID" ] ) );
 m_orders.ChildRelations.Add(
new DataRelation( "Order_OrderDetails", m_orders.Columns[ "OrderID" ], m_orderDetails.Columns[ "OrderID" ] ) );  

}

public static DataTable Employees
{
 get
 {
   
return m_employees;
  }
}

private static DataTable m_employees;
private static DataTable m_orders;
private static DataTable m_orderDetails;
private static OleDbDataAdapter m_adapter = null;

The following code demonstrates how to bind the grid to the Employees property and provide a detail configuration for both detail relations to change their title and the item-container style of the first child detail.

XAML Copy Code

<Grid xmlns:xcdg="http://schemas.xceed.com/wpf/xaml/datagrid"
      xmlns:local="clr-namespace:Xceed.Wpf.Documentation">

 <Grid.Resources>
    
<xcdg:DataGridCollectionViewSource x:Key="cvs_employees"
                                       
Source="{Binding Source={x:Static Application.Current},
                                                        
Path=Employees}"/>   

     <xcdg:IndexToOddConverter x:Key="rowIndexConverter" />
  
     <Style x:Key="alternatingDataRowStyle" TargetType="{x:Type xcdg:DataRow}">
        <Style.Triggers>
           <DataTrigger Binding="{Binding RelativeSource={RelativeSource Self},
                                  Path=(xcdg:DataGridVirtualizingPanel.ItemIndex),
                                  Converter={StaticResource rowIndexConverter}}"
                        Value="True">
              <Setter Property="Background" Value="AliceBlue"/>                   
           </DataTrigger>
        </Style.Triggers>
     </Style>
  </Grid.Resources>

 <xcdg:DataGridControl x:Name="EmployeesGrid"
                       
ItemsSource="{Binding Source={StaticResource cvs_employees}}"
                       
AutoCreateDetailConfigurations="True">  
    
<xcdg:DataGridControl.Columns>
       
<xcdg:Column FieldName="Photo"
                    
Visible="False" />
    
</xcdg:DataGridControl.Columns>
    
<xcdg:DataGridControl.DetailConfigurations>
       
<xcdg:DetailConfiguration RelationName="Employee_Orders"
                                 
Title="Employee Orders"
                                 
ItemContainerStyle="{StaticResource alternatingDataRowStyle}">
          
<xcdg:DetailConfiguration.Columns>
             
<xcdg:Column FieldName="EmployeeID"
                          
Visible="False" />
          
</xcdg:DetailConfiguration.Columns>
          
<xcdg:DetailConfiguration.DetailConfigurations>
             
<xcdg:DetailConfiguration RelationName="Order_OrderDetails"
                                       
Title="Order Details"/>                   
          
</xcdg:DetailConfiguration.DetailConfigurations>
      
</xcdg:DetailConfiguration>
    
</xcdg:DataGridControl.DetailConfigurations>       
 
</xcdg:DataGridControl>

</Grid>