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 Grouping, Sorting, 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
Click 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.
Example 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> |
Example 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> |
Example 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> |
Example 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
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 ); } |
Example 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> |
Example 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(); } |
Example 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 ); } } } |
Example 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(); } } |
Example 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> |
Example 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> |