Introduction
WPF ListView
and DataGrid
controls are very powerful but rather mysterious to program in VB.NET (VS 2010 Beta 1) without using XAML. This article shows how to embed various controls into cells of ListView
and DataGrid
. The sample program demonstrates how to embed TextBlock
, TextBox
, FlowDocument
, and RichTextBox
. The data source for the demonstration program is a LINQ query that obtains process information (process name, id, etc.). The grids are built using either the LINQ query either directly or indirectly via DataTable
s. Data binding, control factories, IValueConverter
and INotifyPropertyChange
are used to build the sample program. The demonstration program presents a matrix of options which are used to generate grids of various data sources and data types.
Background
While working on a project which required displaying rich text in a grid, I became very frustrated by the lack of information about the WPF DataGrid
control. I wanted to build the control in code (VB.NET, no XAML). There were few examples. Hence I decided to create a mega sample program that demonstrates many combinations of LINQ queries, controls and data binding.
Using the Code
The attached program uses three different ways to capture a LINQ query. The query uses GetProcess
to obtain information about the currently running processes.
- Captures a query result to an anonymous type.
- Captures a query result as an instance of a class (
ProcessInfo
).
- Uses the above to create a collection class (
ProcessInfoCollection
) which uses INotifyPropertyChange
to enable dynamic binding.
The user can select any or all of the above LINQ query methods to create a binding. The binding can be used to directly feed ListView
or DataGrid
controls or indirectly by creating DataTable
s from the query and then binding the DataTable
s. The program allows the user to create DataTable
s of nine data types.
- Source data type. The
DataTable
columns inherit their type from the data source.
- All columns are
String
types.
- All columns are
TextBlock
controls. TextBlock
s have some rich text ability. Since TextBlock
s can't be created using FrameworkElementFactory
(they lack a InlinesProperty
), the program contains BindableTextBlock
class to allow FrameworkElementFactory
to work.
- All columns are
BindableTextBlock
s.
- All columns are
TextBox
es. TextBox
lacks rich text ability.
- All columns are a
string
representation of FlowDocument
.
- All columns are
FlowDocument
controls.
- All columns are
RichTextBox
controls. Since RichTextBox
es can't be created using FrameworkElementFactory
(they lack a DocumentProperty
), the program contains BindableRichTextBox
class to allow FrameworkElementFactory
to work.
- All columns are
BindableRichTextBox
.
The user can select the data type of the columns of the ListView
or DataGrid
control. Essentially the same choices as above. This means that any of the above data types may have to be converted into any of the others (e.g. TextBlock
into RichTextBox
). All these combinations are handled by the Convert
method of the IValueConverter
interface.
To demonstrate how to style individual cells, the user can select text styling according to the contents of the cell (using regular expressions). For example, all process names beginning with the letter b have their process names bolded, names beginning with i are italicized, letters beginning with r have a red foreground, and processes with a u are underlined. Otherwise, all cells are given black foreground and light gray backgrounds in the FrameworkElementFactory
code.
The Refresh button will cause new data to appear in the grids but only for the INotify
class when fed directly into the ListView
or DataGrid
(not via a DataTable
).
The final option allows the user to generate windows of ListView
s and/or DataGrid
s. Be careful, it's easy to get carried away with options thus generating dozens of windows which will deplete your computer of CPU and memory.
To build the project, just create a new VS 2010 WPF Application project and paste/copy Window1.xaml.vb and Window1.xaml. There are no references to add.
Points of Interest
The key to the program's magic is the Convert
method of IValueConverter
interface. The method contains the goodness to convert from many types (datatypes and controls) to other types. Other challenges were dynamic binding (INotifyPropertyChange
) as implemented in the ProcessInfoCollection
class, column binding, and supporting the three types of LINQ results.
History
- 24-Sept-2009: Version 0.1