Providing, Inserting, and Removing Data
The following page provides a list of examples that demonstrate how to provide data to a grid.
All examples in this topic assume that the grid is bound to the Orders table of the Northwind database, unless stated otherwise.
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.cs file.
- XAML
- C#
- VB.NET
<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>
public partial class App : Application
{
public DataSet Data
{
get; set;
}
public DataTable Orders
{
get; set;
}
protected override void OnStartup( StartupEventArgs e )
{
// Set the licence key
Xceed.Wpf.DataGrid.Licenser.LicenseKey = "Enter your license key here";
Data = Xceed.Wpf.DataGrid.Samples.SampleData.DataProvider.GetNorthwindDataSet();
Orders = Data.Tables[ "Orders" ];
base.OnStartup( e );
}
}
Public Partial Class App
Inherits Application
Public Property Data As DataSet
Public Property Orders As DataTable
Protected Overrides Sub OnStartup(ByVal e As StartupEventArgs)
' Set the licence key
Xceed.Wpf.DataGrid.Licenser.LicenseKey = "Enter your license key here"
Data = Xceed.Wpf.DataGrid.Samples.SampleData.DataProvider.GetNorthwindDataSet()
Orders = Data.Tables("Orders")
MyBase.OnStartup(e)
End Sub
End Class
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
- C#
- VB.NET
<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>
string[] data = new string[ 7 ];
data[ 0 ] = "Sunday";
data[ 1 ] = "Monday";
data[ 2 ] = "Tuesday";
data[ 3 ] = "Wednesday";
data[ 4 ] = "Thursday";
data[ 5 ] = "Friday";
data[ 6 ] = "Saturday";
dataGridControl.ItemsSource = data;
Dim data() As New String( 6 )
data( 0 ) = "Sunday"
data( 1 ) = "Monday"
data( 2 ) = "Tuesday"
data( 3 ) = "Wednesday"
data( 4 ) = "Thursday"
data( 5 ) = "Friday"
data( 6 ) = "Saturday"
dataGridControl.ItemsSource = data
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
<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>
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
- C#
- VB.NET
<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}"
AutoCreateItemProperties="False">
<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>
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 );
}
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
Providing unbound data
The following example demonstrates how to add Person data to a custom ObservableCollection of Person objects.
- XAML
- C#
- VB.NET
<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>
ObservableCollection<Person> people = new ObservableCollection<Person>();
people.Add( new Person( "Jenny", "Beland" ) );
people.Add( new Person( "Francois", "Carignan" ) );
people.Add( new Person( "Jacques", "Bourque" ) );
people.Add( new Person( "Pascal", "Bourque" ) );
people.Add( new Person( "Marc", "Laroche" ) );
people.Add( new Person( "Pierre-Luc", "Ledoux" ) );
people.Add( new Person( "Catherine", "Sauzede" ) );
people.Add( new Person( "Christian", "Nadeau" ) );
DataGridCollectionView collectionView = new DataGridCollectionView( people, typeof( Person ) );
dataGridControl.ItemsSource = collectionView;
Dim people As New ObservableCollection( Of Person )()
people.Add( New Person( "Jenny", "Beland" ) )
people.Add( New Person( "Francois", "Carignan" ) )
people.Add( New Person( "Jacques", "Bourque" ) )
people.Add( New Person( "Pascal", "Bourque" ) )
people.Add( New Person( "Marc", "Laroche" ) )
people.Add( New Person( "Pierre-Luc", "Ledoux" ) )
people.Add( New Person( "Catherine", "Sauzede" ) )
people.Add( New Person( "Christian", "Nadeau" ) )
Dim collectionView As New DataGridCollectionView( people, GetType( Person ) )
dataGridControl.ItemsSource = collectionView
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
- C#
- VB.NET
<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>
private void SaveModifications( object sender, RoutedEventArgs e )
{
App.LinqDataContext.SubmitChanges();
}
Private Sub SaveModifications( sender As Object, e As RoutedEventArgs )
App.LinqDataContext.SubmitChanges()
End Sub
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
- C#
- VB.NET
<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>
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 );
}
}
}
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
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
- C#
- VB.NET
<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>
public IEnumerable XmlData
{
get
{
XDocument document = App.NorthwindDocument;
IEnumerable 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;
}
}
Public ReadOnly Property XmlData() As IEnumerable
Get
Dim document As XDocument = App.NorthwindDocument
Dim data As IEnumerable = 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
End Get
End Property
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.
- XAML
- C#
- VB.NET
<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>
static App()
{
DataSet dataSet = new DataSet();
string mdbFile = @"Data\Northwind.mdb";
string connString = String.Format( "Provider=Microsoft.ACE.OLEDB.12.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;
Shared Sub New()
Dim dataSet As New DataSet()
Dim mdbfile As String = "Data\Northwind.mdb"
Dim connString As String = String.Format("Provider=Microsoft.ACE.OLEDB.12.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
Defining detail descriptions
The following example demonstrates how to explicitly define detail descriptions for the DataRelations found in the DataTable to which the grid is bound and how to calculate statistical functions for a detail description whose results will be displayed in the StatRows contained in the footer sections of the details to which the description's corresponding detail configuration will be applied.
- XAML
<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>
Manually handling the insertion process
The following example demonstrates how to manually handle the insertion process of a new item into a collection.
- XAML
- C#
- VB.NET
<Grid xmlns:xcdg="http://schemas.xceed.com/wpf/xaml/datagrid"
xmlns:local="clr-namespace:Xceed.Wpf.Documentation">
<Grid.Resources>
<xcdg:DataGridCollectionViewSource x:Key="cvs_persons"
Source="{Binding Source={x:Static Application.Current},
Path=PersonList}"
CreatingNewItem="CollectionView_CreatingNewItem"
CommittingNewItem="CollectionView_CommittingNewItem"
CancelingNewItem="CollectionView_CancelingNewItem"/>
</Grid.Resources>
<xcdg:DataGridControl x:Name="PersonsGrid"
ItemsSource="{Binding Source={StaticResource cvs_persons}}">
<xcdg:DataGridControl.View>
<xcdg:TableView>
<xcdg:TableView.FixedHeaders>
<DataTemplate>
<xcdg:InsertionRow/>
</DataTemplate>
</xcdg:TableView.FixedHeaders>
</xcdg:TableView>
</xcdg:DataGridControl.View>
</xcdg:DataGridControl>
</Grid>
private void CollectionView_CreatingNewItem( object sender, DataGridCreatingNewItemEventArgs e )
{
e.NewItem = new Person( Person.AutoIncrementID, string.Empty, string.Empty, -1 );
e.Handled = true;
}
private void CollectionView_CommittingNewItem( object sender, DataGridCommittingNewItemEventArgs e )
{
List<Person> source = e.CollectionView.SourceCollection as List<Person>;
source.Add( ( Person )e.Item );
Person.AutoIncrementID = Person.AutoIncrementID + 1;
// the new item is always added at the end of the list.
e.Index = source.Count - 1;
e.NewCount = source.Count;
e.Handled = true;
}
private void CollectionView_CancelingNewItem( object sender, DataGridItemHandledEventArgs e )
{
// Manually handling the insertion of new items requires that the CreatingNewItem,
// CommitingNewItem, and CancelingNewItem events must all be handled even if nothing
// is done in the event.
e.Handled = true;
}
Private Sub CollectionView_CreatingNewItem( ByVal sender As Object, _
ByVal e As DataGridCreatingNewItemEventArgs )
e.NewItem = New Person( Person.AutoIncrementID, String.Empty, String.Empty, -1 )
e.Handled = True
End Sub
Private Sub CollectionView_CommittingNewItem( ByVal sender As Object, _
ByVal e As DataGridCommittingNewItemEventArgs )
Dim source As List( Of Person ) = CType( e.CollectionView.SourceCollection, List( Of Person ) )
source.Add( CType( e.Item, Person ) )
Person.AutoIncrementID = Person.AutoIncrementID + 1
' the new item is always added at the end of the list.
e.Index = source.Count - 1
e.NewCount = source.Count
e.Handled = True
End Sub
Private Sub CollectionView_CancelingNewItem( ByVal sender As Object, _
ByVal e As DataGridItemHandledEventArgs )
' Manually handling the insertion of new items requires that the CreatingNewItem,
' CommitingNewItem, and CancelingNewItem events must all be handled even if nothing
' is done in the event.
e.Handled = True
End Sub
Deleting selected items
The following example demonstrates how to delete the selected items and handle the DeletingSelectedItemError and DeletingSelectedItems events.
- XAML
- C#
- VB.NET
<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}}"
IsDeleteCommandEnabled="True"
DeletingSelectedItemError="OrdersGrid_DeletingSelectedItemError"
DeletingSelectedItems="OrdersGrid_DeletingSelectedItems"/>
</Grid>
private void OrdersGrid_DeletingSelectedItemError( object sender, DeletingSelectedItemErrorRoutedEventArgs e )
{
MessageBoxResult result = System.Windows.MessageBox.Show( "The following error occurred while attempting to delete an item: " +
e.Exception.Message + " Do you want to attempt to continue?", "Error", MessageBoxButton.YesNoCancel );
// If "No", the item would be skipped. Since "Skip" is the default action,
// there is no need to verify it.
if( result == MessageBoxResult.Yes )
{
if( this.OrdersGrid.IsBeingEdited )
{
try
{
this.OrdersGrid.CancelEdit();
e.Action = DeletingSelectedItemErrorAction.Retry;
}
catch
{
e.Action = DeletingSelectedItemErrorAction.Skip;
}
}
}
if( result == MessageBoxResult.Cancel )
{
e.Action = DeletingSelectedItemErrorAction.Abort;
}
}
private void OrdersGrid_DeletingSelectedItems( object sender, CancelRoutedEventArgs e )
{
MessageBoxResult result = System.Windows.MessageBox.Show( "Are you certain you want to delete the selected rows?", "Confirm Delete", MessageBoxButton.YesNo );
if( result == MessageBoxResult.No )
{
e.Cancel = true;
}
}
Private Sub OrdersGrid_DeletingSelectedItemError( ByVal sender As Object, ByVal e As DeletingSelectedItemErrorRoutedEventArgs )
Dim result As MessageBoxResult = System.Windows.MessageBox.Show( "The following error occurred while attempting to delete an item: " & _
e.Exception.Message & " Do you want to attempt to continue?", "Error", MessageBoxButton.YesNoCancel )
' If "No", the item would be skipped. Since "Skip" is the default action,
' there is no need to verify it.
If result = MessageBoxResult.Yes Then
If Me.OrdersGrid.IsBeingEdited Then
Try
Me.OrdersGrid.CancelEdit()
e.Action = DeletingSelectedItemErrorAction.Retry
Catch
e.Action = DeletingSelectedItemErrorAction.Skip
End Try
End If
End If
If result = MessageBoxResult.Cancel Then
e.Action = DeletingSelectedItemErrorAction.Abort
End If
End Sub
Private Sub OrdersGrid_DeletingSelectedItems( ByVal sender As Object, ByVal e As CancelRoutedEventArgs )
Dim result As MessageBoxResult = System.Windows.MessageBox.Show( "Are you certain you want to delete the selected rows?", _
"Confirm Delete", MessageBoxButton.YesNo )
If result = MessageBoxResult.No Then
e.Cancel = True
End If
End Sub
Binding to an IQueryable source
The following example demonstrates how to bind to a data source that implements IQueryable (LINQ DataContext) and allow items to be edited, deleted, inserted, and refreshed.
- XAML
- C#
- VB.NET
<Grid xmlns:xcdg="http://schemas.xceed.com/wpf/xaml/datagrid">
<Grid.Resources>
<xcdg:DataGridVirtualizingQueryableCollectionViewSource x:Key="cvs_queryableSource"
QueryableSource="{Binding Path=QueryableSource}"
CommitMode="EditCommitted"
CreatingNewItem="DataGridVirtualizingQueryableCollectionViewSource_CreatingNewItem"
CommittingNewItem="DataGridVirtualizingQueryableCollectionViewSource_CommittingNewItem"
CancelingNewItem="DataGridVirtualizingQueryableCollectionViewSource_CancelingNewItem"
CommitItems="DataGridVirtualizingQueryableCollectionViewSource_CommitItems"
RemovingItem="DataGridVirtualizingQueryableCollectionViewSource_RemovingItem" />
</Grid.Resources>
<xcdg:DataGridControl ItemsSource="{Binding Source={StaticResource cvs_queryableSource}}"
ItemScrollingBehavior="Deferred"
MaxGroupLevels="2"
MaxSortLevels="2"
IsDeleteCommandEnabled="True"
IsRefreshCommandEnabled="True">
<xcdg:DataGridControl.Resources>
<Style TargetType="{x:Type xcdg:Row}"
x:Key="RowHeightStyle">
<Setter Property="Height"
Value="27" />
</Style>
<Style TargetType="{x:Type xcdg:DataRow}"
BasedOn="{StaticResource RowHeightStyle}" />
<Style TargetType="{x:Type xcdg:InsertionRow}"
BasedOn="{StaticResource RowHeightStyle}" />
</xcdg:DataGridControl.Resources>
<xcdg:DataGridControl.View>
<xcdg:TableView>
<xcdg:TableView.FixedHeaders>
<DataTemplate>
<xcdg:InsertionRow />
</DataTemplate>
</xcdg:TableView.FixedHeaders>
</xcdg:TableView>
</xcdg:DataGridControl.View>
<xcdg:DataGridControl.Columns>
<xcdg:Column FieldName="ProductID"
AllowSort="False"
AllowGroup="False" />
</xcdg:DataGridControl.Columns>
</xcdg:DataGridControl>
</Grid>
public partial class Window1 : Window
{
public Window1()
{
this.DataContext = this;
InitializeComponent();
}
// QUERYABLE SOURCE
public IQueryable QueryableSource
{
get
{
if( m_queryable == null )
{
m_northwind = new NorthwindDataContext();
m_queryable = m_northwind.Products;
}
return m_queryable;
}
}
private NorthwindDataContext m_northwind;
private IQueryable m_queryable;
// QUERYABLE INSERTION SUPPORT
private void DataGridVirtualizingQueryableCollectionViewSource_CreatingNewItem( object sender, DataGridCreatingNewItemEventArgs e )
{
Product productToInsert = new Product();
e.NewItem = productToInsert;
m_northwind.Products.InsertOnSubmit( productToInsert );
e.Handled = true;
}
private void DataGridVirtualizingQueryableCollectionViewSource_CommittingNewItem( object sender, DataGridCommittingNewItemEventArgs e )
{
try
{
m_northwind.SubmitChanges();
}
catch
{
e.Cancel = true;
}
e.Handled = true;
}
private void DataGridVirtualizingQueryableCollectionViewSource_CancelingNewItem( object sender, DataGridItemHandledEventArgs e )
{
m_northwind.GetChangeSet().Inserts.Clear();
e.Handled = true;
}
// QUERYABLE EDIT SUPPORT
private void DataGridVirtualizingQueryableCollectionViewSource_CommitItems( object sender, CommitItemsEventArgs e )
{
try
{
m_northwind.SubmitChanges();
}
catch
{
m_northwind.GetChangeSet().Updates.Clear();
}
finally
{
e.AsyncCommitInfo.EndCommit();
}
}
// QUERYABLE DELETE SUPPORT
private void DataGridVirtualizingQueryableCollectionViewSource_RemovingItem( object sender, DataGridRemovingItemEventArgs e )
{
try
{
m_northwind.Products.DeleteOnSubmit( e.Item as Product );
m_northwind.SubmitChanges();
}
catch
{
m_northwind.GetChangeSet().Deletes.Clear();
e.Cancel = true;
}
e.Handled = true;
}
}
Public Partial Class Window1
Inherits Window
Public Sub New
Me.DataContext = Me
InitializeComponent()
End Sub
' QUERYABLE SOURCE
Public ReadOnly Property QueryableSource As IQueryable
Get
If m_queryable Is Nothing Then
m_northwind = New NorthwindDataContext()
m_queryable = m_northwind.Products
End If
Return m_queryable
End Get
End Property
Private m_northwind As NorthwindDataContext
Private m_queryable As IQueryable
' QUERYABLE INSERTION SUPPORT
Private Sub DataGridVirtualizingQueryableCollectionViewSource_CreatingNewItem( sender As Object, e As DataGridCreatingNewItemEventArgs )
Dim productToInsert As New Product()
e.NewItem = productToInsert
m_northwind.Products.InsertOnSubmit( productToInsert )
e.Handled = True
End Sub
Private Sub DataGridVirtualizingQueryableCollectionViewSource_CommittingNewItem( sender As Object, e As DataGridCommittingNewItemEventArgs )
Try
m_northwind.SubmitChanges()
Catch e As Exception
e.Cancel = True
End try
e.Handled = True
End Sub
Private Sub DataGridVirtualizingQueryableCollectionViewSource_CancelingNewItem( sender As Object, e As DataGridItemHandledEventArgs )
m_northwind.GetChangeSet().Inserts.Clear()
e.Handled = True
End Sub
' QUERYABLE EDIT SUPPORT
Private Sub DataGridVirtualizingQueryableCollectionViewSource_CommitItems( sender As Object, e As CommitItemsEventArgs )
Try
m_northwind.SubmitChanges()
Catch e As Exception
m_northwind.GetChangeSet().Updates.Clear()
Finally
e.AsyncCommitInfo.EndCommit()
End Try
End Sub
' QUERYABLE DELETE SUPPORT
Private Sub DataGridVirtualizingQueryableCollectionViewSource_RemovingItem( sender As Object, e as DataGridRemovingItemEventArgs )
Try
m_northwind.Products.DeleteOnSubmit( TryCast( e.Item, Product ) )
m_northwind.SubmitChanges()
Catch e As Exception
m_northwind.GetChangeSet().Deletes.Clear()
e.Cancel = True
End Try
e.Handled = True
End Sub
End Class