This article is about creating a
ListView which has extended capabilities such as having its data filtered and exported to Excel, while supporting the MVVM pattern and having the
ListView.ItemsSource type not standing in the way, while also having the ability to determine how each type can be filtered.
I was given an assignment at work of creating an application which presents some data. The data had to be filtered, in a way that resembles Windows file filtering. Being a hug MVVM supporter, I wanted my code to be clean, decoupled, as well as generic, so it could be used in other cases as well.
Using the code
ListView is required to handle all data types, I wanted the decision on how the filtering and exporting is done to be made by the
ViewModel. Thus, I can have a list of student details being filtered by the students' private name, and a list of cars being filtered only by the manufacturer. To handle this task, I created an interface which the
ViewModels must implement:
public interface IEnhancedListObject
bool Filter(string strFilter);
void WriteHeaderIntoExcelSheet(Worksheet worksheet, ref int nRow, ref int nColumn);
void WriteDataIntoExcelSheet(Worksheet worksheet, ref int nRow, ref int nColumn);
The interface holds three methods:
Filter: Decides if the element passes the given string.
WriteHeaderIntoExcelSheet: Writes the columns of the exported data.
WriteDataIntoExcelSheet: Writes the actual data into the Excel sheet.
Since I wanted my code to be as robust as possible, I tried to avoid having any code written in the Xaml.cs files. I used the attached properties for that matter.
public class ListViewFilterExtension
public static readonly DependencyProperty FilterSourceProperty =
public static TextBox GetFilterSource(DependencyObject d)
public static void SetFilterSource(DependencyObject d, TextBox value)
private static void OnTextBoxSet(DependencyObject d,
ListView listView = d as ListView;
TextBox textBox = e.NewValue as TextBox;
if ((listView != null) && (textBox != null))
textBox.TextChanged += delegate(object sender,
ICollectionView view =
view.Filter = null;
view.Filter = delegate(object obj)
IEnhancedListObject filterableObject = obj as IEnhancedListObject;
if (filterableObject == null) return false;
string textFilter = ((TextBox)sender).Text;
if (textFilter.Trim().Length == 0) return true;
The filtering assumes the filter string would be taken from a
TextBox. The attached property is given a
TextBox as a parameter, and registers itself as a listener to the
TextChanged event. The delegate it registers goes through the elements in the
ListView.ItemSource, assuming they are implementing the
IEnhancedListObject interface, and runs the filter operation on them.
Export to Excel:
public class ListViewExcelExporterExtension
public static readonly DependencyProperty ExcelExporterProperty =
public static ListView GetExcelExporter(DependencyObject d)
public static void SetExcelExporter(DependencyObject d, ListView value)
private static void OnExcelExportRequest(DependencyObject d,
System.Windows.Controls.Button button = d as System.Windows.Controls.Button;
ListView listView = e.NewValue as ListView;
if ((button != null) && (listView != null))
button.Click += delegate(object sender, RoutedEventArgs er)
Microsoft.Office.Interop.Excel.Application application =
application.Visible = true;
CultureInfo currentCulture = Thread.CurrentThread.CurrentCulture;
Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US");
Workbook workbook = application.Workbooks.Add(Missing.Value);
Worksheet worksheet = workbook.ActiveSheet as Worksheet;
if (worksheet != null)
worksheet._DisplayRightToLeft = 0;
if (listView.Items.Count > 0)
IEnhancedListObject vm = listView.Items as IEnhancedListObject;
int nRow = 1;
int nColumn = 1;
if (vm != null)
vm.WriteHeaderIntoExcelSheet(worksheet, ref nRow, ref nColumn);
foreach (var item in listView.Items)
vm = item as IEnhancedListObject;
vm.WriteDataIntoExcelSheet(worksheet, ref nRow, ref nColumn);
Thread.CurrentThread.CurrentCulture = currentCulture;
The exporting attached property assumes it would be used by a
Button. It gets a
ListView as its parameter. It registeres itself to the
Button.Click operation. Upon click, it goes through the
ListView.ItemsSource, assuming they are implementing the
IEnhancedListObject interface, and uses the interface to add the data into the Excel sheet.
In the example, I'm presenting a list of the 500 companies in the S & P index, which I've taken from Wikipedia.
- June 29, 2010: Initial version.