Sign In
CarlosAg Blog
Translate This Page
Translate this page
Powered by
Microsoft® Translator
Options
Email Blog Author
RSS for posts
Atom
RSS for comments
OK
Search
Advanced search options...
Search In:
Everything
Blogs
Forums
People
Groups
Places
Pages
Date range:
All Time
Last Year
Last 6 Months
Last 3 Months
Last Month
Last Week
Last Two Days
Tags
.NET
ARR
ASP.NET
IIS
IIS Manager
IIS News Item
Microsoft.Web.Administration
Personal
SEO
URL Rewrite
WinForms
Most Viewed
The evil WinForms Splitter
Posted
over 7 years ago
by
CarlosAg
1
Comments
Archive
Archives
December 2011
(1)
August 2011
(3)
January 2011
(1)
November 2010
(1)
October 2010
(1)
May 2010
(2)
April 2010
(3)
March 2010
(1)
February 2010
(2)
November 2009
(9)
October 2009
(1)
September 2009
(1)
July 2009
(1)
June 2009
(6)
February 2009
(1)
November 2008
(2)
October 2008
(1)
September 2008
(4)
August 2008
(3)
July 2008
(5)
June 2008
(4)
May 2008
(3)
April 2008
(4)
March 2008
(6)
February 2008
(1)
January 2008
(2)
December 2007
(1)
November 2007
(2)
October 2007
(1)
September 2007
(2)
June 2007
(1)
May 2007
(1)
March 2007
(2)
February 2007
(1)
August 2006
(1)
June 2006
(1)
May 2006
(1)
April 2006
(2)
November 2005
(1)
September 2005
(1)
August 2005
(1)
July 2005
(1)
November, 2005
MSDN Blogs
>
CarlosAg Blog
>
November, 2005
Posts
Subscribe via RSS
Sort by:
Most Recent
|
Most Views
|
Most Comments
Excerpt View
|
Full Post View
CarlosAg Blog
The evil WinForms Splitter
Posted
over 7 years ago
by
CarlosAg
1
Comments
Beware of SplitPosition.
Today I spent quite some time debugging an issue in the new product I am working on.
Well, to summarize what I was seeing in our UI is that for some reason certain information that I was expecting to be there when a TreeNode was expanded, it just wasn’t there. It was completely surprising to me, since in that particular code path, we do not start multiple threads or use Application.DoEvents nor anything like that, basically all we do is a simple assignment in the TreeView after select event, something like:
private
void
OnTreeViewAfterSelect(
object
sender,
TreeViewEventArgs
e) {
_myObject =
DoSomeProcessing()
;
}
However, for some reason in another event handler of our TreeView,
_myObject
was not set.
How can this be?
Well, after quite some interesting time with VS 2005 (which rocks!), the problem was due to an interesting raise condition caused by (believe it or not) a WinForms Splitter. What was happening is that DoSomeProcessing changed some properties, that caused the UI to perform a layout and inside that code, we set the SplitterPosition property of the Splitter. Well, surprise-surprise,
Splitter calls Application.DoEvents in its property setter!!!.
What
DoEvents
does is basically lets Windows pop the next message from the windows message pump and process it, so the next event was actually fired, and _myObject ended up not being set.
To illustrate the problem with a simple sample, try this code:
(
Just copy the code and paste it into notepad.
Save it as TestApp.cs and compile it using “csc.exe /target:winexe TestApp.cs”
)
using
System
;
using
System.Drawing
;
using
System.Threading
;
using
System.Windows.Forms
;
namespace
TestApp {
public class
Form1 : Form {
private
TreeView _treeView
;
private
Label _label
;
private
Splitter _splitter
;
private
Button _someButton
;
[STAThread]
static void
Main() {
Application.Run(
new
Form1())
;
}
public
Form1() {
InitializeComponent()
;
// Just add some nodes...
TreeNode node
=
_treeView.Nodes.Add(
"Node 1"
)
;
node.Nodes.Add(
"Node 1.1"
)
;
node.Nodes.Add(
"Node 1.2"
)
;
_treeView.Nodes.Add(
"Node 2"
)
;
}
private void
InitializeComponent() {
_treeView
= new
TreeView()
;
_splitter
= new
Splitter()
;
_label
= new
Label()
;
_someButton
= new
Button()
;
SuspendLayout()
;
// treeView1
_treeView.Dock
=
DockStyle.Left
;
_treeView.Location
= new
Point(
5
,
28
)
;
_treeView.TabIndex
=
1
;
_treeView.AfterSelect +
= new
TreeViewEventHandler(OnTreeViewAfterSelect)
;
_treeView.BeforeSelect +
= new
TreeViewCancelEventHandler(OnTreeViewBeforeSelect)
;
// splitter
_splitter.Location
= new
Point(
126
,
28
)
;
_splitter.TabIndex
=
1
;
_splitter.TabStop
= false;
// label1
_label.BackColor
=
SystemColors.Window
;
_label.BorderStyle
=
BorderStyle.Fixed3D
;
_label.Dock
=
DockStyle.Fill
;
_label.Location
= new
Point(
129
,
28
)
;
_label.TabIndex
=
2
;
// button1
_someButton.Dock
=
DockStyle.Top
;
_someButton.Location
= new
Point(
5
,
5
)
;
_someButton.TabIndex
=
0
;
// Form
ClientSize
= new
Size(
500
,
400
)
;
Controls.Add(_label)
;
Controls.Add(_splitter)
;
Controls.Add(_treeView)
;
Controls.Add(_someButton)
;
ResumeLayout(
false
)
;
}
private void
OnTreeViewAfterSelect(
object
sender, TreeViewEventArgs e) {
_label.Text
=
"Node selected:"
+ e.Node.Text
;
}
private void
OnTreeViewBeforeSelect(
object
sender, TreeViewCancelEventArgs e) {
// Just sleep 500ms to simulate some work
Thread.Sleep(
500
)
;
// Now update the SplitPosition
_splitter.SplitPosition
=
100
;
// simulate 500ms of more work ...
Thread.Sleep(
500
)
;
}
}
}
Colorized by:
CarlosAg.CodeColorizer
Run it and select the TreeView, notice how ugly everything works.
Basically every time you select a different node you will get an ugly flickering, getting to see how selection jumps from the newly selected node to the last selected node, and then back to the new selected node.
Well, luckily in Visual Studio 2005, there is a new class called SplitContainer that simplifies everything.
It even adds new features, such as letting you set a MaxSize for both the left panel and the right panel, and many more features. Best of all, there is no Application.DoEvents in their code, so you can have code that behaves deterministically.
Bottom line, you do want to use SplitContainer if at all possible.
Page 1 of 1 (1 items)