How to: Create a ListView with Editable Cells
This example shows how to create a ListView control in a GridView view mode that has editable cells.
Example
To edit the cells of a GridViewColumn in a GridView, define a custom control to use as the CellTemplate of the column.
The following example shows a custom control that is named EditBox, which implements two dependency properties, Value and IsEditing. The Value property stores the value of a cell. The IsEditing property specifies whether the cell is currently editable.
Public Class EditBox
Inherits Control
...
Public Shared ReadOnly ValueProperty As DependencyProperty = DependencyProperty.Register("Value", GetType(Object), GetType(EditBox), New FrameworkPropertyMetadata(Nothing))
...
Public Shared IsEditingProperty As DependencyProperty = DependencyProperty.Register("IsEditing", GetType(Boolean), GetType(EditBox), New FrameworkPropertyMetadata(False))
...
End Class
public class EditBox : Control
{
...
public static readonly DependencyProperty ValueProperty =
DependencyProperty.Register(
"Value",
typeof(object),
typeof(EditBox),
new FrameworkPropertyMetadata(null));
...
public static DependencyProperty IsEditingProperty =
DependencyProperty.Register(
"IsEditing",
typeof(bool),
typeof(EditBox),
new FrameworkPropertyMetadata(false));
...
}
The following example creates a Style for the EditBox control.
<Style x:Key="{x:Type l:EditBox}" TargetType="{x:Type l:EditBox}" >
<Setter Property="HorizontalAlignment" Value="Left" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type l:EditBox}">
<TextBlock x:Name="PART_TextBlockPart"
Text="{Binding Path=Value,RelativeSource =
{RelativeSource TemplatedParent}}">
</TextBlock>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
To create a TextBox control to edit a cell, implement an Adorner. The following example shows the constructor for the EditBoxAdorner.
Friend NotInheritable Class EditBoxAdorner
Inherits Adorner
...
Public Sub New(ByVal adornedElement As UIElement, ByVal adorningElement As UIElement)
MyBase.New(adornedElement)
_textBox = TryCast(adorningElement, TextBox)
Debug.Assert(_textBox IsNot Nothing, "No TextBox!")
_visualChildren = New VisualCollection(Me)
BuildTextBox()
End Sub
...
End Class
internal sealed class EditBoxAdorner : Adorner
{
...
public EditBoxAdorner(UIElement adornedElement,
UIElement adorningElement): base(adornedElement)
{
_textBox = adorningElement as TextBox;
Debug.Assert(_textBox != null, "No TextBox!");
_visualChildren = new VisualCollection(this);
BuildTextBox();
}
...
}
To control when the EditBox is editable, use events like MouseUp, MouseLeave, or MouseEnter. The following example shows how the first MouseUp event that is received by an EditBox selects the EditBox, and the second MouseUp event puts the EditBox in editing mode.
Public Class EditBox
Inherits Control
...
Protected Overrides Sub OnMouseUp(ByVal e As MouseButtonEventArgs)
MyBase.OnMouseUp(e)
If e.ChangedButton = MouseButton.Right OrElse e.ChangedButton = MouseButton.Middle Then
Return
End If
If Not IsEditing Then
If (Not e.Handled) AndAlso (_canBeEdit OrElse _isMouseWithinScope) Then
IsEditing = True
End If
'If the first MouseUp event selects the parent ListViewItem,
'then the second MouseUp event puts the EditBox in editing
'mode
If IsParentSelected Then
_isMouseWithinScope = True
End If
End If
End Sub
...
End Class
public class EditBox : Control
{
...
protected override void OnMouseUp(MouseButtonEventArgs e)
{
base.OnMouseUp(e);
if (e.ChangedButton == MouseButton.Right ||
e.ChangedButton == MouseButton.Middle)
return;
if (!IsEditing)
{
if (!e.Handled && (_canBeEdit || _isMouseWithinScope))
{
IsEditing = true;
}
//If the first MouseUp event selects the parent ListViewItem,
//then the second MouseUp event puts the EditBox in editing
//mode
if (IsParentSelected)
_isMouseWithinScope = true;
}
}
...
}
The following example shows how you use the MouseEnter and MouseLeave events to determine if a cell is eligible for editing.
Public Class EditBox
Inherits Control
...
Protected Overrides Sub OnMouseEnter(ByVal e As MouseEventArgs)
MyBase.OnMouseEnter(e)
If (Not IsEditing) AndAlso IsParentSelected Then
_canBeEdit = True
End If
End Sub
...
Protected Overrides Sub OnMouseLeave(ByVal e As MouseEventArgs)
MyBase.OnMouseLeave(e)
_isMouseWithinScope = False
_canBeEdit = False
End Sub
...
End Class
public class EditBox : Control
{
...
protected override void OnMouseEnter(MouseEventArgs e)
{
base.OnMouseEnter(e);
if (!IsEditing && IsParentSelected)
{
_canBeEdit = true;
}
}
...
protected override void OnMouseLeave(MouseEventArgs e)
{
base.OnMouseLeave(e);
_isMouseWithinScope = false;
_canBeEdit = false;
}
...
}
To define a GridViewColumn that permits editing, set the CellTemplate property to an EditBox control. The following example specifies the CellTemplate property of a GridViewColumn as an EditBox control.
<GridViewColumn Header="ID" Width="50" >
<GridViewColumn.CellTemplate>
<DataTemplate>
<l:EditBox Height="25" Value="{Binding Path=EmployeeNumber}" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>