Tuesday, March 31, 2009

Working with WPF DataGrid - Part 6

Filtering data in a datagrid can be achieved by attaching the data source of the datagrid with a ListCollectionView object and then set the Filter property with a private method that has the logic to filter the data in the ListCollectionView object based on the object passed.

In this sample I will show how to filter data in the Grid based on Employees FirstName

I have added the event handler for the window loaded event to set the ItemsSource property of the Grid as

private void OnWindowLoaded(object sender, RoutedEventArgs e)

{

ListCollectionView dgcv = new ListCollectionView(new List<UIEmployee>(_employeeDataGrid.ItemsSource as ObservableEmployee));

dgcv.Filter = SearchFilter;

_employeeDataGrid.ItemsSource = dgcv;

}

The search filter method is implemented as

private bool SearchFilter(object sender)

{

if (_searchTextBox == null)

return true;

string search = _searchTextBox.Text;

UIEmployee item = (UIEmployee)sender;

if (!string.IsNullOrEmpty(search))

{

if (item.FirstName.ToLower().Contains(search.ToLower()))

return true;

return false;

}

return true;

}

For entering the search text for searching, we need to add a text box and an event handler to the TextChanged event of the textbox as

<TextBox Name="_searchTextBox" TextChanged="OnSearchChanged" Width="150" Margin="8 0 0 0" Height="25">TextBox>

The event handler code is given as

private void OnSearchChanged(object sender, TextChangedEventArgs e)

{

((ListCollectionView)_employeeDataGrid.ItemsSource).Refresh();

}

Output

The next part of the series I'll show how to display data with Master- Detail relationship on the WPF DataGrid.

Saturday, March 28, 2009

Working with WPF DataGrid - Part 5

The DataGrid supports sorting by default on all bound and stock columns. You can set the CanUserSortColumns="False" if you want to disable sorting. For sorting template columns you need to set the SortMemberPath property of the columns to the property name of the business object that the column is bound to.

In my example I have enable sorting on the columns like

<WPF:DataGridTextColumn Binding="{Binding Path=LastName}" Header="LastName" Width="100" />

<WPF:DataGridTemplateColumn Header="Occupation" SortMemberPath="Occupation">

<WPF:DataGridTemplateColumn.CellEditingTemplate>

<DataTemplate>

<ComboBox SelectedItem="{Binding Path=Occupation, Mode=TwoWay}" ItemsSource="{Binding Source={StaticResource _occupationFactory}}" IsEditable="True" IsReadOnly="True" />

DataTemplate>

WPF:DataGridTemplateColumn.CellEditingTemplate>

<WPF:DataGridTemplateColumn.CellTemplate>

<DataTemplate>

<TextBlock Text="{Binding Path=Occupation}" />

DataTemplate>

WPF:DataGridTemplateColumn.CellTemplate>

WPF:DataGridTemplateColumn>

You can also have a look into Vincent’s blog where he explains the concept of tri-state sorting on WPF DataGrid. The next part of the series we’ll see how to filter data on DataGrid.

Thursday, March 26, 2009

Working with WPF DataGrid - Part 4

The ObservableCollection has a CollectionChanged event that can be used to trace changes to the collection binded to the DataGrid. We will be using the CollectionChanged event and the ItemEndEdit event of the ObservableCollection class to support CRUD operations on the sample.

To add handlers for the CollectionChanged and ItemEndEdit event for the EmployeeCollection used in our sample, I have modified the EmployeeDataProvider class GetEmployees method as

public ObservableEmployee GetEmployees()

{

ObservableEmployee employeeCollection = new ObservableEmployee(EmployeeFactory.GetEmployees());

employeeCollection.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler((x, y) =>

{

if (y.Action == NotifyCollectionChangedAction.Remove)

{

foreach (object item in y.OldItems)

EmployeeFactory.Remove(Translator.ViewToBusiness(item as UIEmployee));

}

});

employeeCollection.ItemEndEdit += new UIEmployee.ItemEndEditEventHandler((x) => EmployeeFactory.Update(Translator.ViewToBusiness(x as UIEmployee)));

return employeeCollection;

}

The DataGrid is able to perform an atomic commit of the row which is currently being edited; this is made possible if the bound items implement the IEditableObject interface which exposes BeginEdit, EndEdit, and CancelEdit methods. Typically, an object implementing this interface would return to its state at the point when the BeginEdit method was called as a response to the CancelEdit method being invoked. However, in this instance, we are not really concerned about being able to cancel edits; all we really need to know is when the user has finished editing a row. This is indicted when the DataGrid invokes EndEdit on our bound item. In order to notify the EmployeeDataProvider that EndEdit has been invoked on one of the objects in the collection; the UIEmployee implements the IEditableObject as given below.

public class UIEmployee : INotifyPropertyChanged, IEditableObject

{

//Previous code goes here

public delegate void ItemEndEditEventHandler(IEditableObject sender);

public event ItemEndEditEventHandler ItemEndEdit;

#region IEditableObject Members

public void BeginEdit() { }

public void CancelEdit() { }

public void EndEdit()

{

if (ItemEndEdit != null)

ItemEndEdit(this);

}

#endregion

}

The event is handled for all the items in the collection as

public class ObservableEmployee : ObservableCollection<UIEmployee>

{

//Previous code goes here

protected override void InsertItem(int index, UIEmployee item)

{

base.InsertItem(index, item);

item.ItemEndEdit += new UIEmployee.ItemEndEditEventHandler((x) =>

{

if (ItemEndEdit != null)

ItemEndEdit(x);

});

}

}

That completes the code for the CRUD operations on the DataGrid. The next part we’ll see how to implement sorting on the datagrid.