asp:Feature
LANGUAGES: C#
ASP.NET VERSIONS: 3.5
Columns & Rows:
Part I
Silverlight 2.0 DataGrid Properties
By Bilal Haidar
There is a need in every database-driven
application to display data to end-users in the form of rows and columns that
mimic the Excel sheets with which most end-users are familiar. Fortunately for
us, Silverlight provides a rich and robust DataGrid control.
The Silverlight team at Microsoft issued the first
release of the DataGrid in October 2008. This release had so many issues the
team was forced to release an updated version in December 2008. This is the
most up-to-date release, and includes more than 30 bug fixes. To read more
about that latest release, visit the Silverlight 2 DataGrid December 2008
Release blog post by Scott Morrison, the project manager of the Silverlight
DataGrid (blogs.msdn.com/scmorris/archive/2008/12/19/silverlight-2-datagrid-december-2008-release.aspx).
Working with the Silverlight 2.0 DataGrid is not
difficult; however, having a series of articles dissecting its details can be
beneficial, so this is exactly what I intend to do in this series.
Introduction
This article is the first in a series that will
tackle most of the features of the Silverlight 2.0 DataGrid. There are several
sections to discuss and explain regarding the Silverlight 2.0 DataGrid,
including an overview of the DataGrid properties, auto-generating columns,
defining columns in XAML, defining columns at runtime, implementing
master/detail features, paging and sorting, and editing/deleting/adding rows
using the DataGrid.
Through the course of this article, you ll get an
overview of the majority of the DataGrid properties that play an important role
in configuring the DataGrid, like setting the column width and row color, and
alternating colors, among other things.
References to Silverlight 2.0
This article assumes you have a fair knowledge of
using Silverlight 2.0 especially data-binding features and is not intended as
an introduction to Silverlight 2.0. If you feel you need more information on
Silverlight 2.0, I recommend you check the official website at www.silverlight.net, where you ll find
dozens of articles and videos to get you started. Another major resource for
learning Silverlight 2.0 is www.silverlightshow.net;
it focuses on delivering rich and comprehensive tutorials on Silverlight.
Additionally, you can download the Microsoft Silverlight
2.0 SDK documentation, which covers all the features of Silverlight (www.microsoft.com/Downloads/details.aspx?familyid=BCE7684A-507B-4FC6-BC99-6933CD690CAB&displaylang=en).
The Silverlight DataGrid
To start, let s create a new Visual Studio 2008
Silverlight application. The Silverlight Application template has been integrated
into Visual Studio 2008. When creating the new application, make sure to select
the Add a new ASP.NET Web project to the solution to host Silverlight option,
as shown in Figure 1.
Figure 1: Silverlight configuration screen
Selecting this option will create for you an
ASP.NET Web project that hosts the Silverlight application; this also provides
more flexibility for you as a developer to make use of all the ASP.NET features
to which you are already accustomed.
Before we start with the details of adding the
DataGrid and exploring its properties, the final product will be something
similar to what is shown in Figure 2.
Figure 2: DataGrid properties view
As you can see in this demonstration, the DataGrid
is on top, with the major properties to be discussed shown as separate
rectangles, each with a title representing the property title and the body
representing the different values that the property can accept.
Adding a DataGrid to a User Control
To add a DataGrid to a Silverlight User Control,
all you need to do is drag the DataGrid control from the Silverlight XAML
Controls toolbox that is only available for Silverlight applications. You can
only drag controls on to the XAML part of the User Control because the Design
View is still read-only for Silverlight applications. The dragged DataGrid
control is shown in Figure 3.
<!-- DataGrid -->
<data:DataGrid x:Name="dgEmployees"
Width="500" />
Figure 3: Silverlight DataGrid control
Adding the DataGrid as shown in Figure 3 adds to
the User Control header the XAML namespace shown in Figure 4.
xmlns:data="clr-namespace:System.Windows.Controls;
assembly=System.Windows.Controls.Data"
Figure 4: DataGrid XAML namespace
This is to say that the DataGrid control is located
in the System.Windows.Controls namespace that is part of the
System.Windows.Controls.Data assembly. This is required, because the DataGrid
is only available as part of the Silverlight 2.0 Software Development Kit
(SDK).
Adding a DataGrid this way without configuring any
properties yields default values for some of the major properties (see Figure
5).
| Property
Name |
Default Value |
| AutoGenerateColumns |
TRUE |
| CanUserReorderColumns |
TRUE |
| CanUserResizeColumns |
TRUE |
| CanUserSortColumns |
TRUE |
| MaxColumnWidth |
double.PositiveInfinity |
| MinColumnWidth |
20 |
| RowDetailsVisiblityMode |
DataGridRowDetailsVisibilityMode.VisibleWhenSelected |
| RowHeight |
2 |
| SelectionMode |
DataGridSelectionMode.Extended |
| HorizontalGridLinesThinkness |
1 |
| ColumnHeaderHeight |
4 |
| RowHeaderWidth |
4 |
|
|
Figure 5: Major DataGrid properties
Now that you know how to add a DataGrid, let s
start building each property s UI and explain how to use it, as well as its
effect on the DataGrid.
DataGrid Properties
In this section, the major DataGrid properties will
be listed together with a detailed explanation of the UI used to present the
property and the code-behind that puts the properties selected values into
effect by applying them to the DataGrid.
The GridLinesVisibility Property
This property controls the display of the
horizontal or vertical grid lines separating the inner cells of the DataGrid.
It is of type DataGridLinesVisibility enumeration.
The XAML UI in Figure 6 shows a StackPanel control
holding a TextBlock control as a title, together with a ListBox control listing
all the available values the GridLinesVisibility property accepts.
<StackPanel >
<Border >
<TextBlock Text="GridLinesVisibility"
/>
</Border>
<ListBox
x:Name="lstboxGridLinesVisibility"
SelectionChanged="lstboxGridLinesVisibility_SelectionChanged"
>
<TextBlock
Text="All" />
<TextBlock
Text="Horizontal" />
<TextBlock
Text="None" />
<TextBlock
Text="Vertical" />
</ListBox>
</StackPanel>
Figure 6: XAML UI of the GridLinesVisibility
property
Acceptable
Value(s). The GridLinesVisibility property is a Dependency property and can
take any of the following values:
- Horizontal: Only horizontal grid lines are
displayed.
- Vertical: Only vertical grid lines are
displayed.
- None: The DataGrid is displayed without any grid
lines.
Each of the above values is displayed as a
TextBlock control inside the ListBox control.
Code-behind.
The ListBox control listing the acceptable values of the
GridLinesVisibility property defines an event handler for the SelectionChanged
event (see Figure 7).
The event handler in Figure 7 starts by getting a
reference to the TextBlock control representing the value selected in the
ListBox control. After that, the GridLinesVisibility property is set on the
DataGrid by casting the value in to a DataGridGridLinesVisibility enumeration.
Based on the item selected, the DataGrid will behave accordingly.
private void lstboxGridLinesVisibility_SelectionChanged(
object sender,
SelectionChangedEventArgs e)
{
TextBlock option =
e.AddedItems[0] as
TextBlock;
if
(option.Text.Equals(""))
return;
this.dgEmployees.GridLinesVisibility = (DataGridGridLinesVisibility)
Enum.Parse(typeof(DataGridGridLinesVisibility), option.Text, true);
}
Figure 7: Define an event handler for the
SelectionChanged event of the GridLinesVisibility property
The HeadersVisibility Property
This property controls the display of column and
row headers on the DataGrid control. You are likely familiar with the column
headers; however, the row header is a new feature added to a DataGrid that
shows an empty cell beside each row, and hence acts as a header for every row
displayed in the DataGrid. This property is of type HeadersVisibility
enumeration.
The XAML UI in Figure 8 shows a StackPanel control
holding a TextBlock control as a title, together with a ListBox control listing
all the available values the HeadersVisibility property accepts.
<StackPanel >
<Border >
<TextBlock
Text="HeadersVisiblity" />
</Border>
<ListBox
x:Name="lstboxHeadersVisiblity"
SelectionChanged="lstboxHeadersVisiblity_SelectionChanged">
<TextBlock Text="All"
/>
<TextBlock
Text="Column" />
<TextBlock
Text="None" />
<TextBlock
Text="Row" />
</ListBox>
</StackPanel>
Figure 8: XAML UI of the HeadersVisibility
property
Acceptable
Value(s). The HeadersVisibility property is a Dependency property and can
take any of the following values:
Column: Only column headers are displayed.
Row: Only row headers are displayed.
All: Both column and row headers are displayed.
None: Both column and row headers are not
displayed.
Each of the above values is displayed as a
TextBlock control inside the ListBox control.
Code-behind.
The ListBox control listing the acceptable values of the HeadersVisibility
property defines an event handler for the SelectionChanged event (see Figure
9).
private void lstboxHeadersVisibility_SelectionChanged(
object sender,
SelectionChangedEventArgs e)
{
TextBlock option =
e.AddedItems[0] as
TextBlock;
if
(option.Text.Equals(""))
return;
this.dgEmployees.HeadersVisibility = (DataGridHeadersVisibility)
Enum.Parse(typeof(DataGridHeadersVisibility), option.Text, true);
}
Figure 9: Define an event handler for the
SelectionChanged event of the HeadersVisibility property
The event handler in Figure 9 starts by getting a
reference to the TextBlock control representing the value selected in the
ListBox control. After that, the HeadersVisibility property is set on the
DataGrid by casting the value in to a DataGridHeadersVisibility enumeration.
Based on the item selected, the DataGrid will behave accordingly.
The RowBackground Property
This property decides on the Brush that is used to
paint the background color of rows in a DataGrid. It is of type Brush.
The XAML UI in Figure 10 shows a StackPanel control
holding a TextBlock control as a title, together with a ListBox control listing
some color names that will be used to change the row background colors for the
DataGrid rows.
<StackPanel>
<Border >
<TextBlock
Text="RowBackground" />
</Border>
<ListBox x:Name="lstboxRowBackground"
SelectionChanged="lstboxRowBackground_SelectionChanged">
<TextBlock
Text="Red" />
<TextBlock
Text="Beige" />
<TextBlock
Text="Blue" />
<TextBlock
Text="Remove Color" />
</ListBox>
</StackPanel>
Figure 10: XAML UI of the RowBackground
property
Acceptable
Value(s). The RowBackground property is a Dependency property and can take
only values of type Brush.
Code-behind.
The ListBox control listing some color names defines an event handler for the
SelectionChanged event (see Figure 11).
private void lstboxRowBackground_SelectionChanged(
object sender,
SelectionChangedEventArgs e)
{
TextBlock option =
e.AddedItems[0] as TextBlock;
if
(option.Text.Equals(""))
return;
this.dgEmployees.RowBackground
=
(Brush)this.Resources[option.Text];
}
Figure 11: Define an event handler for the
SelectionChanged event of the RowBackground property
The event handler in Figure 11 starts by getting a
reference to the TextBlock control representing the color value selected in the
ListBox control. Then the RowBackground property is set on the DataGrid by
casting in to a Brush object a resource object that was already defined in the
XAML. Based on the color selected, the DataGrid s row backgrounds will change
accordingly.
The trick here is to define a set of color brushes
in the XAML part of the User Control and place them as part of the User
Control s resources:
<!-- Colors -->
<SolidColorBrush x:Key="Red" Color="Red"
Opacity=".8" />
<SolidColorBrush x:Key="Beige"
Color="Beige"
Opacity=".8"
/>
A separate SolidColorBrush is defined for every
color intended to be added. Once the colors are added as User Control
resources, they can be accessed in the code-behind by accessing the ResourceDictionary
using an indexer; in this case, the key name that was used to define the color
Brush in XAML. Once a resource item is retrieved, it is cast to its proper type
(in this case, Brush type).
The FrozenColumnCount Property
This property controls the number of columns the
user will not be able to scroll horizontally. In other words, the value of this
property determines the columns that will be frozen, and on which the
horizontal scrollbar will not act.
The XAML UI in Figure 12 shows a StackPanel control
holding a TextBlock control as a title, together with a ListBox control listing
some integer values that will be used to control the FrozenColumnCount property
of the DataGrid.
<StackPanel >
<Border >
<TextBlock
Text="FrozenColumnCount" />
</Border>
<ListBox
x:Name="lstboxFrozenColumnCount"
SelectionChanged="lstboxFrozenColumnCount_SelectionChanged">
<TextBlock
Text="1" />
<TextBlock
Text="2" />
<TextBlock
Text="None" />
</ListBox>
</StackPanel>
Figure 12: XAML UI of the FrozenColumnCount
property
Acceptable
Value(s).The FrozenColumnCount property is a Dependency property and can
take only integer values. Specifying an integer value represents the number of
columns to freeze while scrolling with the horizontal scrollbars. To freeze the
first column, set the value to 1 . To freeze the second column, set the value
to 2 , thus freezing the first two columns at once.
Code-behind.
The ListBox control listing some color names defines an event handler for
the SelectionChanged event (see Figure 13).
private void lstboxFrozenColumnCount_SelectionChanged(
object sender,
SelectionChangedEventArgs e)
{
TextBlock option =
e.AddedItems[0] as TextBlock;
if
(option.Text.Equals(""))
return;
this.dgEmployees.FrozenColumnCount =
option.Text.Equals("None") ? 0 : Int32.Parse(option.Text);
}
Figure 13: Define an event handler for the
SelectionChanged event of the FrozenColumnCount property
The event handler in Figure 13 starts by getting a
reference to the TextBlock control representing the integer value selected in
the ListBox control. If the selected value was None , which is a special value
added to represent 0 columns frozen, the DataGrid is configured with a value
of 0 on the FrozenColumnCount, else the exact number selected in the ListBox
control is cast to an integer and assigned on the FrozenColumnCount property.
The SelectionMode Property
This property controls the selection of a single or
multiple rows in a DataGrid. In general, the DataGrid has two main selection
modes; either a single selection, which means only one row, can be selected at
once, or extended selection mode, which allows the selection of multiple rows.
This property is of type DataGridSelectionMode enumeration.
The XAML UI in Figure 14 shows a StackPanel control
holding a TextBlock control as a title, together with two RadioButton controls
for each of the possible values that the SelectionMode property accepts.
<StackPanel>
<Border>
<TextBlock
Text="SelectionMode" />
</Border>
<Border>
<Grid
Height="Auto" Width="Auto">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="75" />
<ColumnDefinition Width="75" />
</Grid.ColumnDefinitions>
<RadioButton
x:Name="rbtnSingle"
Content="Single" Checked="rbtnSingle_Checked"
GroupName="grSelectionMode"
/>
<RadioButton
x:Name="rbtnExtended"
Content="Extended" Checked="rbtnSingle_Checked"
GroupName="grSelectionMode" />
</Grid>
</Border>
</StackPanel>
Figure 14: XAML UI of the SelectionMode
Property
Acceptable
Value(s). The SelectionMode property is a Dependency property and can take
either of the following values:
Single: A single row can be selected at a time.
Extended: Multiple rows can be selected at once.
Each of the above values is displayed as a
RadioButton control.
Code-behind. The
above two RadioButton controls define the same event handler for the Checked
event. Checking either of these two controls triggers the Checked event. To
force only one of the RadioButtons to be checked at a time, you must add the
GroupName to both RadioButtons and make sure they have the same group name, and
thus only one RadioButton in a single group can be checked at a time. The
RadioButtons Checked event handler is defined in Figure 15.
private void rbtnSingle_Checked(object sender, RoutedEventArgs e)
{
if
(this.rbtnSingle.IsChecked.Value)
this.dgEmployees.SelectionMode = DataGridSelectionMode.Single;
if
(this.rbtnExtended.IsChecked.Value)
this.dgEmployees.SelectionMode = DataGridSelectionMode.Extended;
}
Figure 15: The RadioButtons Checked event
handler
Based on what the user has selected, the
corresponding SelectionMode value is set on the DataGrid.
The CanUserReorderColumns Property
This property is of type Boolean; it allows or
prevents the user from selecting a column, then dragging and changing its order
among the other columns displayed in the DataGrid. When the property is set to
true , the user is allowed to drag a column and change its position on the DataGrid,
thus reordering the columns displayed.
The XAML UI in Figure 16 shows a StackPanel control
holding a TextBlock control as a title, together with two RadioButton controls,
one for the true value and one for the false value that the CanUserReorderColumns
property accepts.
<StackPanel>
<Border>
<TextBlock
Text="CanUserReorderColumns" />
</Border>
<Border >
<Grid
Height="Auto" Width="Auto">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="60" />
<ColumnDefinition Width="60" />
</Grid.ColumnDefinitions>
<RadioButton
x:Name="rbtnCanUserReorderColumns"
Content="True"
Checked="rbtnCanUserReorderColumns_Checked"
GroupName="grCanUserReorderColumns" />
<RadioButton
x:Name="rbtnCannotUserReorderColumns"
Content="False"Checked="rbtnCanUserReorderColumns_Checked"
GroupName="grCanUserReorderColumns" />
</Grid>
</Border>
</StackPanel>
Figure 16: XAML UI of the
CanUserReorderColumns property
Acceptable
Value(s). The CanUserReorderColumns property is a Dependency property and
can take either a true or false value:
True: User is allowed to rearrange the DataGrid
columns.
False: Column rearrangement is not allowed in
the DataGrid.
Each of the above values is displayed as a
RadioButton control.
Code-behind.
The above two RadioButton controls define the same event handler for the
Checked event. Checking either of these two controls triggers the Checked
event. To force only one of the RadioButtons to be checked at a time, you must
add the GroupName to both RadioButtons and make sure they have the same group
name so only one RadioButton in a single group can be checked at a time. The
RadioButtons Checked event handler is defined in Figure 17.
private void rbtnCanUserReorderColumns_Checked(
object sender,
RoutedEventArgs e)
{
if
(this.rbtnCanUserReorderColumns.IsChecked.Value)
this.dgEmployees.CanUserReorderColumns = true;
if
(this.rbtnCannotUserReorderColumns.IsChecked.Value)
this.dgEmployees.CanUserReorderColumns = false;
}
Figure 17: The RadioButtons Checked event
handler
Based on what the user has selected, the
corresponding CanUserReorderColumns value is set on the DataGrid, thus allowing
or preventing a user from reordering the DataGrid columns.
There are additional major properties that can be
manipulated on the DataGrid control. The code download accompanying this
article explores additional important properties; take some time to explore how
they are implemented. I also suggest you visit bhaidar.net/SilverlightDataGrid/GridProperties.aspx
to browse a live sample and play around with all the major DataGrid properties.
Conclusion
This article is the first in a series covering the
Silverlight 2.0 DataGrid control. This installment provides an overview of the
DataGrid properties and how they can be used to configure the behavior of the
DataGrid.
Source code accompanying this article is available for download.
Bilal Haidar (bhaidar@gmail.com) is a Microsoft MVP in
ASP.NET. He is an MCP, MCTS, MCPD, MCT, and Telerik MVP. He is a lead software
developer at CCC, a multinational construction company based in Athens, Greece.