Files
componentowl-astro/public/documentation/better-listview/data/chapter-embedded-controls.html

720 lines
26 KiB
HTML
Raw Permalink Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:xlink="http://www.w3.org/1999/xlink">
<head>
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
<title>Embedded Controls</title>
<link href="style.css" rel="stylesheet" type="text/css">
<link href="prettify.css" type="text/css" rel="stylesheet">
<script type="text/javascript" src="prettify.js"></script><script type="text/javascript" src="lang-vb.js"></script><link href="../resources/main.css" media="screen" rel="stylesheet" type="text/css">
</head>
<body onload="prettyPrint()"><div class="placing">
<br><table class="navigation"><tr>
<td class="navigation-previous"><a href="chapter-drag-drop.html"><strong>
« Drag and Drop</strong></a></td>
<td class="navigation-index"><a href="../../../quick-start-guide/better-listview/index.html"><strong>Index</strong></a></td>
<td class="navigation-next"><a href="chapter-empty-text.html"><strong>Empty Text »
</strong></a></td>
</tr></table>
<br><h1>Embedded Controls</h1>
<div class="banner">
<a href="../../../blog/page/6/index.html"><img src="../resources/overview.gif" alt="Better ListView" class="ss"></a>
<div class="inside">
<div class="text">Better ListView: Ultimate .NET ListView replacement control for WinForms (C#, VB.NET)</div>
<span class="dbtn-c dbtn-hilight"><span class="dbtn-w"><a href="../../../betterlistview.exe" class="dbtn">Download</a></span></span>
<span class="dbtn-c"><span class="dbtn-w"><a href="../../../blog/page/6/index.html" class="dbtn">More Info</a></span></span>
</div>
</div>
<p>Embedded editing controls can be thought of as an extension to label
edit functionality (see <strong><em><a href="chapter-label-edit.html">Label
Editing</a></em></strong> for more information).</p>
<p>Every item and sub-item has a <strong><em>cell</em></strong> area on which
an editing control can be placed. In the simplest case
(<span class="code">LabelEdit</span> set to <span class="code">true</span>), the editing control is
basically a <span class="code">System.Windows.Forms.TextBox</span> control. It is
actually an instance of <span class="code">BetterListViewTextBoxEmbeddedControl</span>,
which is a <span class="code">TextBox</span> wrapper implementing
<span class="code">IBetterListViewEmbeddedControl</span> interface. Any control can be
used as embedded control in Bettter ListView if implements one of these
interfaces:</p>
<ul>
<li>
<p><span class="code">IBetterListViewEmbeddedControl </span></p>
</li>
<li>
<p><span class="code">IBetterListViewEmbeddedControlExtended</span></p>
</li>
</ul>
<p>The custom embedded control is shown on the image below. When user
clicks on sub-item text (an abbreviation of tea grading), an editing control
appears on the top-left corner of the cell area. The control contains
buttons for accepting and cancelling changes:</p>
<p class="images"><img src="embedded-control.png"></p>
<h2>Implementing IBetterListViewEmbeddedControl</h2>
<p>This interface contains prescription for minimum amount of
functionality required by an embedded control:</p>
<ul>
<li>
<p>Get label text for currently edited data.</p>
</li>
<li>
<p>Data accepting and cancelling events (e.g. if the control has an
OK button).</p>
</li>
<li>
<p>Set control size given the cell area and positioning
data.</p>
</li>
<li>
<p>Move data from sub-item to the control.</p>
</li>
<li>
<p>Move data from the control to the sub-item.</p>
</li>
</ul>
<p>Let's make a sample control. We will make a
<span class="code">TextBox</span>-based embedded control for editing words in
lower-case. First, we inherit <span class="code">TextBox</span> and implement
<span class="code">IBetterListViewEmbeddedControl</span> interface:</p>
<p><strong>C#</strong></p>
<pre class="prettyprint"><code class="lang-cs">/// &lt;summary&gt;
/// Represents a custom control embeddable in Better ListView.
/// &lt;/summary&gt;
public class TextBoxEmbeddedControl : TextBox, IBetterListViewEmbeddedControl</code></pre>
<p><strong>Visual Basic</strong></p>
<pre class="prettyprint"><code class="lang-vb">''' &lt;summary&gt;
''' Represents a custom control embeddable in Better ListView.
''' &lt;/summary&gt;
Public Class TextBoxEmbeddedControl
Inherits TextBox
Implements IBetterListViewEmbeddedControl</code></pre>
<p>Then we implement the <span class="code">LabelText</span> property:</p>
<p><strong>C#</strong></p>
<pre class="prettyprint"><code class="lang-cs">/// &lt;summary&gt;
/// current (edited) label text
/// &lt;/summary&gt;
public string LabelText
{
get
{
return Text.ToLower();
}
}</code></pre>
<p><strong>Visual Basic</strong></p>
<pre class="prettyprint"><code class="lang-vb">''' &lt;summary&gt;
''' current (edited) label text
''' &lt;/summary&gt;
Public ReadOnly Property LabelText() As String
Get
Return Text.ToLower()
End Get
End Property</code></pre>
<p>As you can see, the text of the <span class="code">TextBox</span> is converted to
lower case since we want item/sub-item labels to be only in lower
case.</p>
<p>Next, we implement <span class="code">RequestAccept</span> and
<span class="code">RequestCancel</span> events:</p>
<p><strong>C#</strong></p>
<pre class="prettyprint"><code class="lang-cs">/// &lt;summary&gt;
/// request accepting updated data in BetterListView
/// &lt;/summary&gt;
public event EventHandler RequestAccept;
/// &lt;summary&gt;
/// request cancelling editing
/// &lt;/summary&gt;
public event EventHandler RequestCancel;</code></pre>
<p><strong>Visual Basic</strong></p>
<pre class="prettyprint"><code class="lang-vb">''' &lt;summary&gt;
''' request accepting updated data in BetterListView
''' &lt;/summary&gt;
Public Event RequestAccept As EventHandler Implements IBetterListViewEmbeddedControl.RequestAccept
''' &lt;summary&gt;
''' request cancelling editing
''' &lt;/summary&gt;
Public Event RequestCancel As EventHandler Implements IBetterListViewEmbeddedControl.RequestCancel</code></pre>
<p>Next, we implement <span class="code">GetData</span> and <span class="code">SetData</span>
methods:</p>
<p><strong>C#</strong></p>
<pre class="prettyprint"><code class="lang-cs">/// &lt;summary&gt;
/// get data from the specified sub-item in control
/// &lt;/summary&gt;
/// &lt;param name = "subItem"&gt;sub-item whose data are being edited&lt;/param&gt;
public void GetData(BetterListViewSubItem subItem)
{
Text = subItem.Text;
}
/// &lt;summary&gt;
/// set data from control to the specified sub-item
/// &lt;/summary&gt;
/// &lt;param name = "subItem"&gt;sub-item whose data are being edited&lt;/param&gt;
public void SetData(BetterListViewSubItem subItem)
{
subItem.Text = LabelText;
}</code></pre>
<p><strong>Visual Basic</strong></p>
<pre class="prettyprint"><code class="lang-vb">''' &lt;summary&gt;
''' get data from the specified sub-item in control
''' &lt;/summary&gt;
''' &lt;param name = "subItem"&gt;sub-item whose data are being edited&lt;/param&gt;
Public Sub GetData(ByVal subItem As BetterListViewSubItem) Implements IBetterListViewEmbeddedControl.GetData
Text = subItem.Text
End Sub
''' &lt;summary&gt;
''' set data from control to the specified sub-item
''' &lt;/summary&gt;
''' &lt;param name = "subItem"&gt;sub-item whose data are being edited&lt;/param&gt;
Public Sub SetData(ByVal subItem As BetterListViewSubItem) Implements IBetterListViewEmbeddedControl.SetData
subItem.Text = LabelText
End Sub</code></pre>
<p>These method are trivial since we need not to do any data
conversions (the only conversion here is lowering the case of edited text
in the <span class="code">LabelText</span> getter).</p>
<p>The last method contained in the interface is <span class="code">SetSize</span>
method, which needs not to be implemented (the body can be kept empty).
You implement this method only if you need to adjust control's size when
label edit starts.</p>
<p>The constructor should be implemented like this:</p>
<p><strong>C#</strong></p>
<pre class="prettyprint"><code class="lang-cs">/// &lt;summary&gt;
/// Initializes a new instance of the &lt;see cref = "TextBoxEmbeddedControl" /&gt; class.
/// &lt;/summary&gt;
public TextBoxEmbeddedControl()
{
AcceptsReturn = true;
CausesValidation = false;
}</code></pre>
<p><strong>Visual Basic</strong></p>
<pre class="prettyprint"><code class="lang-vb">''' &lt;summary&gt;
''' Initializes a new instance of the &lt;see cref = "TextBoxEmbeddedControl" /&gt; class.
''' &lt;/summary&gt;
Public Sub New()
AcceptsReturn = True
CausesValidation = False
End Sub</code></pre>
<p>The <span class="code">AcceptsReturn</span> property is set to <span class="code">true</span>
because we will handle the <strong><em>ENTER</em></strong> key (and raise
<span class="code">RequestAccept</span> event appropriately).</p>
<p>The <span class="code">CausesValidation</span> property is set to
<span class="code">false</span> because it is a good practice in this situation.</p>
<p>Both input and output data are validated in the
<span class="code">IBetterListViewEmbeddedControl</span> implementation and validation
of some third-party controls can prevent whole form with the control from
closing.</p>
<p>The last thing we implement is handling of the
<strong><em>ENTER</em></strong> key for accepting the data and the
<strong><em>ESCAPE</em></strong> key for cancelling:</p>
<p><strong>C#</strong></p>
<pre class="prettyprint"><code class="lang-cs">protected override void OnKeyDown(KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter &amp;&amp;
RequestAccept != null)
{
RequestAccept(this, EventArgs.Empty);
e.Handled = true;
return;
}
if (e.KeyCode == Keys.Escape &amp;&amp;
RequestCancel != null)
{
RequestCancel(this, EventArgs.Empty);
e.Handled = true;
return;
}
base.OnKeyDown(e);
}</code></pre>
<p><strong>Visual Basic</strong></p>
<pre class="prettyprint"><code class="lang-vb">Protected Overrides Sub OnKeyDown(e As KeyEventArgs)
If e.KeyCode = Keys.Enter AndAlso RequestAccept IsNot Nothing Then
RequestAccept(Me, EventArgs.Empty)
e.Handled = True
Return
End If
If e.KeyCode = Keys.Escape AndAlso RequestCancel IsNot Nothing Then
RequestCancel(Me, EventArgs.Empty)
e.Handled = True
Return
End If
MyBase.OnKeyDown(e)
End Sub</code></pre>
<br><hr>
<p class="note">It is a common good practice to implement interfaces explicitly.
The sample implementation is implicit for the sake of better
readability. Embedded controls implemented in BetterListView.dll are
implemented implicitly (and marked virtual) to allow for being inherited
(e.g. <span class="code">MyCustomControl : BetterListViewEmbeddedControl</span>) and
you may possibly want to override any part of the interface
implementation.</p>
<hr>
<br><h2>Implementing IBetterListViewEmbeddedControlExtended</h2>
<p>The extended interface has currently only one method called
<span class="code">RequestEndEdit</span>. This method can be called by the Better
ListView, when it asks the control whether it is ready to end editing. The
control can return a boolean value (<span class="code">true</span> - continue
<span class="code">EndEdit</span>, <span class="code">false</span> - refuse to end editing). There
are many situations when the label editing is terminated (e.g. scrolling
the control, selecting items...) and terminating the label edit is not
always wanted (this is a case of
<span class="code">System.Windows.Forms.DateTimePicker</span> control, which sometimes
behaves as being transparent for mouse clicks and thus being closed
because of click-through on the Better ListView client area - the
<span class="code">RequestEndEdit</span> method fixes such possible behavior of third
party controls).</p>
<h2>Sample Source Code</h2>
<p>Form with Better ListView containing some columns and items:</p>
<p><strong>C#</strong></p>
<pre class="prettyprint"><code class="lang-cs">/// &lt;summary&gt;
/// Shows embedding of custom controls into Better ListView.
/// &lt;/summary&gt;
internal sealed partial class EmbeddedControlSampleForm : Form
{
/// &lt;summary&gt;
/// Initializes a new instance of the &lt;see cref = "EmbeddedControlSampleForm" /&gt; class.
/// &lt;/summary&gt;
public EmbeddedControlSampleForm()
{
InitializeComponent();
this.listView.BeginUpdate();
this.listView.Columns.AddRange(new[]
{
new BetterListViewColumnHeader("Document name", 160),
new BetterListViewColumnHeader("Access", 128)
});
this.listView.Items.AddRange(
new[]
{
new BetterListViewItem(new[] { "hydro-report.pdf", "read" }),
new BetterListViewItem(new[] { "magnetic_resonance.docx", "read write" }),
new BetterListViewItem(new[] { "billing forms (2011).zip", "read" })
});
this.listView.LabelEditActivation = (BetterListViewLabelEditActivation.Keyboard | BetterListViewLabelEditActivation.SingleClick);
this.listView.LabelEditModeSubItems = BetterListViewLabelEditMode.CustomControl;
this.listView.EndUpdate();
this.listView.RequestEmbeddedControl += ListViewRequestEmbeddedControl;
}
private IBetterListViewEmbeddedControl ListViewRequestEmbeddedControl(object sender, BetterListViewRequestEmbeddedControlEventArgs eventArgs)
{
if (eventArgs.SubItem.Index == 1)
{
return (new DocumentAccessConrol());
}
return null;
}
}</code></pre>
<p><strong>Visual Basic</strong></p>
<pre class="prettyprint"><code class="lang-vb">''' &lt;summary&gt;
''' Shows embedding of custom controls into Better ListView.
''' &lt;/summary&gt;
Partial Friend NotInheritable Class EmbeddedControlSampleForm
''' &lt;summary&gt;
''' Initializes a new instance of the &lt;see cref = "EmbeddedControlSampleForm" /&gt; class.
''' &lt;/summary&gt;
Public Sub New()
InitializeComponent()
ListView.BeginUpdate()
ListView.Columns.AddRange(
New BetterListViewColumnHeader() { _
New BetterListViewColumnHeader("Document name", 160),
New BetterListViewColumnHeader("Access", 128)
})
ListView.Items.AddRange(
New BetterListViewItem() { _
New BetterListViewItem(New String() {"hydro-report.pdf", "read"}),
New BetterListViewItem(New String() {"magnetic_resonance.docx", "read write"}),
New BetterListViewItem(New String() {"billing forms (2011).zip", "read"})
})
ListView.LabelEditActivation =
(BetterListViewLabelEditActivation.Keyboard Or BetterListViewLabelEditActivation.SingleClick)
ListView.LabelEditModeSubItems = BetterListViewLabelEditMode.CustomControl
ListView.EndUpdate()
AddHandler ListView.RequestEmbeddedControl, AddressOf ListViewRequestEmbeddedControl
End Sub
Private Function ListViewRequestEmbeddedControl(ByVal sender As Object,
ByVal eventArgs As BetterListViewRequestEmbeddedControlEventArgs) _
As IBetterListViewEmbeddedControl
If eventArgs.SubItem.Index = 1 Then
Return (New DocumentAccessConrol())
End If
Return Nothing
End Function
End Class</code></pre>
<p><span class="code">DocumentAccessControl</span> class used as complex embedded
control (see <span class="code">EmbeddedControlSampleForm</span> sample in the provided
C# and Visual Basic samples for full source code):</p>
<p><strong>C#</strong></p>
<pre class="prettyprint"><code class="lang-cs">/// &lt;summary&gt;
/// Represents a custom control embeddable in Better ListView.
/// &lt;/summary&gt;
[ToolboxItem(false)]
internal sealed partial class DocumentAccessConrol : UserControl, IBetterListViewEmbeddedControl
{
private const string StringRead = "read";
private const string StringWrite = "write";
/// &lt;summary&gt;
/// current (edited) label text
/// &lt;/summary&gt;
public string LabelText
{
get
{
// convert control's state to label
if (this.checkBoxRead.Checked &amp;&amp;
this.checkBoxWrite.Checked)
{
return String.Format("{0} {1}", StringRead, StringWrite);
}
if (this.checkBoxRead.Checked)
{
return StringRead;
}
if (this.checkBoxWrite.Checked)
{
return StringWrite;
}
return String.Empty;
}
}
/// &lt;summary&gt;
/// request accepting updated data in BetterListView
/// &lt;/summary&gt;
public event EventHandler RequestAccept;
/// &lt;summary&gt;
/// request cancelling editing
/// &lt;/summary&gt;
public event EventHandler RequestCancel;
/// &lt;summary&gt;
/// Initializes a new instance of the &lt;see cref = "DocumentAccessConrol" /&gt; class.
/// &lt;/summary&gt;
public DocumentAccessConrol()
{
InitializeComponent();
//NOTE: disabling validation prevents form close cancellation
CausesValidation = false;
foreach (Control control in Controls)
{
control.LostFocus += ControlOnLostFocus;
}
}
/// &lt;summary&gt;
/// get data from the specified sub-item in control
/// &lt;/summary&gt;
/// &lt;param name = "subItem"&gt;sub-item whose data are being edited&lt;/param&gt;
public void GetData(BetterListViewSubItem subItem)
{
// convert label to control's state
this.checkBoxRead.Checked = subItem.Text.Contains(StringRead);
this.checkBoxWrite.Checked = subItem.Text.Contains(StringWrite);
}
/// &lt;summary&gt;
/// set data from control to the specified sub-item
/// &lt;/summary&gt;
/// &lt;param name = "subItem"&gt;sub-item whose data are being edited&lt;/param&gt;
public void SetData(BetterListViewSubItem subItem)
{
subItem.Text = LabelText;
}
/// &lt;summary&gt;
/// set control size
/// &lt;/summary&gt;
/// &lt;param name = "subItem"&gt;sub-item whose data are being edited&lt;/param&gt;
/// &lt;param name = "placement"&gt;placement of the embedded control within sub-item&lt;/param&gt;
public void SetSize(BetterListViewSubItem subItem, BetterListViewEmbeddedControlPlacement placement)
{
// keep size of the control unchanged
}
private void ControlOnLostFocus(object sender, EventArgs eventArgs)
{
//
// NOTE: this code is needed just for hiding embedded control with sub-controls when user changes active form while label editing
//
bool anyFocused = Focused;
if (anyFocused == false)
{
foreach (Control control in Controls)
{
if (control.Focused)
{
anyFocused = true;
break;
}
}
}
if (anyFocused == false)
{
RequestAccept(this, eventArgs);
}
}
private void ButtonOKClick(object sender, EventArgs e)
{
RequestAccept(this, e);
}
private void ButtonCancelClick(object sender, EventArgs e)
{
RequestCancel(this, e);
}
}</code></pre>
<p><strong>Visual Basic</strong></p>
<pre class="prettyprint"><code class="lang-vb">''' &lt;summary&gt;
''' Represents a custom control embeddable in Better ListView.
''' &lt;/summary&gt;
&lt;ToolboxItem(False)&gt;
Partial Friend NotInheritable Class DocumentAccessConrol
Inherits UserControl
Implements IBetterListViewEmbeddedControl
Private Const StringRead As String = "read"
Private Const StringWrite As String = "write"
''' &lt;summary&gt;
''' current (edited) label text
''' &lt;/summary&gt;
Public ReadOnly Property LabelText() As String Implements IBetterListViewEmbeddedControl.LabelText
Get
' convert control's state to label
If CheckBoxRead.Checked AndAlso CheckBoxWrite.Checked Then
Return [String].Format("{0} {1}", StringRead, StringWrite)
End If
If CheckBoxRead.Checked Then
Return StringRead
End If
If CheckBoxWrite.Checked Then
Return StringWrite
End If
Return [String].Empty
End Get
End Property
''' &lt;summary&gt;
''' request accepting updated data in BetterListView
''' &lt;/summary&gt;
Public Event RequestAccept As EventHandler Implements IBetterListViewEmbeddedControl.RequestAccept
''' &lt;summary&gt;
''' request cancelling editing
''' &lt;/summary&gt;
Public Event RequestCancel As EventHandler Implements IBetterListViewEmbeddedControl.RequestCancel
''' &lt;summary&gt;
''' Initializes a new instance of the &lt;see cref = "DocumentAccessConrol" /&gt; class.
''' &lt;/summary&gt;
Public Sub New()
InitializeComponent()
'NOTE: disabling validation prevents form close cancellation
CausesValidation = False
For Each control As Control In Controls
AddHandler control.LostFocus, AddressOf ControlOnLostFocus
Next
End Sub
''' &lt;summary&gt;
''' get data from the specified sub-item in control
''' &lt;/summary&gt;
''' &lt;param name = "subItem"&gt;sub-item whose data are being edited&lt;/param&gt;
Public Sub GetData(ByVal subItem As BetterListViewSubItem) Implements IBetterListViewEmbeddedControl.GetData
' convert label to control's state
CheckBoxRead.Checked = subItem.Text.Contains(StringRead)
CheckBoxWrite.Checked = subItem.Text.Contains(StringWrite)
End Sub
''' &lt;summary&gt;
''' set data from control to the specified sub-item
''' &lt;/summary&gt;
''' &lt;param name = "subItem"&gt;sub-item whose data are being edited&lt;/param&gt;
Public Sub SetData(ByVal subItem As BetterListViewSubItem) Implements IBetterListViewEmbeddedControl.SetData
subItem.Text = LabelText
End Sub
''' &lt;summary&gt;
''' set control size
''' &lt;/summary&gt;
''' &lt;param name = "subItem"&gt;sub-item whose data are being edited&lt;/param&gt;
''' &lt;param name = "placement"&gt;placement of the embedded control within sub-item&lt;/param&gt;
Public Sub SetSize(ByVal subItem As BetterListViewSubItem,
ByVal placement As BetterListViewEmbeddedControlPlacement) _
Implements IBetterListViewEmbeddedControl.SetSize
' keep size of the control unchanged
End Sub
Private Sub ControlOnLostFocus(ByVal sender As Object, ByVal eventArgs As EventArgs)
'
' NOTE: this code is needed just for hiding embedded control with sub-controls when user changes active form while label editing
'
Dim anyFocused As Boolean = Focused
If anyFocused = False Then
For Each control As Control In Controls
If control.Focused Then
anyFocused = True
Exit For
End If
Next
End If
If anyFocused = False Then
RaiseEvent RequestAccept(Me, eventArgs)
End If
End Sub
Private Sub ButtonOKClick(ByVal sender As Object, ByVal e As EventArgs) Handles ButtonOK.Click
RaiseEvent RequestAccept(Me, e)
End Sub
Private Sub ButtonCancelClick(ByVal sender As Object, ByVal e As EventArgs) Handles ButtonCancel.Click
RaiseEvent RequestCancel(Me, e)
End Sub
End Class</code></pre>
<br><div class="banner">
<a href="../../../blog/page/6/index.html"><img src="../resources/overview.gif" alt="Better ListView" class="ss"></a>
<div class="inside">
<div class="text">Better ListView: Ultimate .NET ListView replacement control for WinForms (C#, VB.NET)</div>
<span class="dbtn-c dbtn-hilight"><span class="dbtn-w"><a href="../../../betterlistview.exe" class="dbtn">Download</a></span></span>
<span class="dbtn-c"><span class="dbtn-w"><a href="../../../blog/page/6/index.html" class="dbtn">More Info</a></span></span>
</div>
</div>
<table class="navigation"><tr>
<td class="navigation-previous"><a href="chapter-drag-drop.html"><strong>
« Drag and Drop</strong></a></td>
<td class="navigation-index"><a href="../../../quick-start-guide/better-listview/index.html"><strong>Index</strong></a></td>
<td class="navigation-next"><a href="chapter-empty-text.html"><strong>Empty Text »
</strong></a></td>
</tr></table>
<br><table class="footer"><tr>
<td class="footer-title">Better ListView Documentation
</td>
<td class="footer-copyright">
Copyright © 2010-2012  <a href="../../../index.html" target="_blank">ComponentOwl.com</a>
</td>
</tr></table>
</div></body>
</html>