.NET Forum / Windows Forms / WinForm General / January 2008
Error in Treeview with Checkboxes and Vista
|
|
Thread rating:  |
Dieter Pelz - 31 Oct 2007 11:40 GMT Hallo,
there is an error in the TreeView control when checkboxes are enabled. When the checkbox is double clicked the node is visibly not checked, but the Checked property is still true;
I'm using Visual Studio 2005. Windows Vista und Vista 64 has this error. Windows XP works fine.
Is there any workaround for this Error? An example project is available.
Thanks, Dieter Pelz
Linda Liu[MSFT] - 01 Nov 2007 08:25 GMT Hi Dieter,
I performed a test based on your description and did reproduce the problem on my side.
This problem is caused by the Vista visual styles. If you disable the visual styles for the application, the problem doesn't exist.
FYI, to disable the visual styles for a WinForm application, if you're using C#, open the Program.cs file and comment out the line of code 'Application.EnableVisualStyles();' in the static Main method; if you're using VB.NET, right click the project in the Solution Explorer and choose Properties, in the Project Designer, switch to Application tab and clear the checkbox before the option 'Enable XP visual styles'.
So, the easiest workaround of this problem is to disable the Vista visual styles for the application.
A more complicated workaround is to draw the TreeView by ourselves so that we can ensure the displayed check state of the treenode is always correct. To do this, we need to set the DrawMode of the TreeView to OwnerDrawAll and handle the DrawNode event of the TreeView. In addition, we need to add two bmp files to the application. One bmp file represents the plus sign used by the TreeView and the other represents the minus sign.
The following is a sample to do this:
public partial class Form1 : Form { public Form1() { InitializeComponent(); this.treeView1.DrawMode = TreeViewDrawMode.OwnerDrawAll; this.treeView1.DrawNode += new DrawTreeNodeEventHandler(treeView1_DrawNode); }
void treeView1_DrawNode(object sender, DrawTreeNodeEventArgs e) { int left = e.Bounds.X; int top = e.Bounds.Y; int height = e.Bounds.Height;
int nodeleft = e.Node.Bounds.X; int nodetop = e.Node.Bounds.Y; int nodeheight = e.Node.Bounds.Height; int nodewidth = e.Node.Bounds.Width;
int linelength =10; int checkboxwidth = 13; int checknodespace = 2; using (Pen p = new Pen(Color.Gray)) { p.DashStyle = System.Drawing.Drawing2D.DashStyle.Dot; int lineleft = nodeleft-checknodespace-checkboxwidth-linelength; //draw horizontal dot line e.Graphics.DrawLine(p, lineleft, top + height / 2, lineleft + linelength, top + height / 2); // draw the up half vertical dot line if (e.Node.PrevNode != null || e.Node.Parent != null) { e.Graphics.DrawLine(p, lineleft, top, lineleft, top + height / 2); } // draw the down half vertical dot line if (e.Node.NextNode != null) { e.Graphics.DrawLine(p, lineleft, top + height / 2, lineleft, e.Node.NextNode.Bounds.Top); } // draw plus/minus image if (e.Node.Nodes.Count > 0) { if (!e.Node.IsExpanded) { e.Graphics.DrawImage(Properties.Resources.plus, lineleft - Properties.Resources.plus.Width / 2, top + (height - Properties.Resources.plus.Height) / 2); } else { e.Graphics.DrawImage(Properties.Resources.minus, lineleft - Properties.Resources.minus.Width / 2, top + (height - Properties.Resources.minus.Height) / 2); } } // draw the vertical dot line for the parent nodes if necessary TreeNode parentNode = e.Node.Parent; int parentNodeLeftDistance = checknodespace + checkboxwidth + linelength; while (parentNode != null) { if (parentNode.NextNode != null) { e.Graphics.DrawLine(p, parentNode.Bounds.X - parentNodeLeftDistance, top, parentNode.Bounds.X - parentNodeLeftDistance, top + height); } parentNode = parentNode.Parent; } } // draw checkbox if (e.Node.Checked) { ControlPaint.DrawCheckBox(e.Graphics, new Rectangle(nodeleft - checkboxwidth - checknodespace, top + (height - checkboxwidth) / 2, checkboxwidth, checkboxwidth), ButtonState.Checked); } else { ControlPaint.DrawCheckBox(e.Graphics, new Rectangle(nodeleft - checkboxwidth - checknodespace, top + (height - checkboxwidth) / 2, checkboxwidth, checkboxwidth), ButtonState.Normal); } // erase the previous node text using (Brush b = new SolidBrush(this.treeView1.BackColor)) { e.Graphics.DrawString(e.Node.Text, this.treeView1.Font, b, nodeleft, nodetop); } // draw node text and highlight rectangle if (e.Node.IsSelected) { ControlPaint.DrawFocusRectangle(e.Graphics, e.Node.Bounds); e.Graphics.FillRectangle(Brushes.LightSkyBlue, new Rectangle(nodeleft + 1, nodetop + 1, nodewidth - 2, nodeheight - 2)); using (Brush b = new SolidBrush(Color.White)) { e.Graphics.DrawString(e.Node.Text, this.treeView1.Font, b, nodeleft, nodetop); } } else { using (Brush b = new SolidBrush(this.treeView1.ForeColor)) { e.Graphics.DrawString(e.Node.Text, this.treeView1.Font, b, nodeleft, nodetop); } } } }
Hope this helps. If you have any question, please feel free to let me know.
Sincerely, Linda Liu Microsoft Online Community Support
================================================== Get notification to my posts through email? Please refer to http://msdn.microsoft.com/subscriptions/managednewsgroups/default.aspx#notif ications. Note: The MSDN Managed Newsgroup support offering is for non-urgent issues where an initial response from the community or a Microsoft Support Engineer within 1 business day is acceptable. Please note that each follow up response may take approximately 2 business days as the support professional working with you may need further investigation to reach the most efficient resolution. The offering is not appropriate for situations that require urgent, real-time or phone-based interactions or complex project analysis and dump analysis issues. Issues of this nature are best handled working with a dedicated Microsoft Support Engineer by contacting Microsoft Customer Support Services (CSS) at http://msdn.microsoft.com/subscriptions/support/default.aspx. ================================================== This posting is provided "AS IS" with no warranties, and confers no rights.
Brendon Bezuidenhout - 01 Nov 2007 09:08 GMT Linda,
Do you possibly know how to "fix" the Vista msstyles and XP VisualStyles incompatibility possibly? For example below in the code snippet... It's possible now to handle both XP visual styles and pre XP styles... But with the advent of Vista things are now not as backward compatible as it were? I understand that it is possible using the Win32 API to possibly make the code below look as it does in Vista; but there has to be an easier way through VS to do this rather than the SDK? (I'm using VS2005 and 2008 Beta2).
Thanks, Brendon
<code> public class ComboTreeButton : Button { #region Fields
private ButtonState buttonState; private ComboBoxState comboBoxState;
#endregion
protected override void OnPaint(PaintEventArgs e) { base.OnPaint(e); if (!ComboBoxRenderer.IsSupported) { ControlPaint.DrawComboButton(e.Graphics, this.ClientRectangle, buttonState ); } else { ComboBoxRenderer.DrawDropDownButton(e.Graphics, this.ClientRectangle, comboBoxState); } } } </code>
> Hi Dieter, > [quoted text clipped - 171 lines] > This posting is provided "AS IS" with no warranties, and confers no > rights. Linda Liu[MSFT] - 02 Nov 2007 11:19 GMT Hi Brendon,
> Do you possibly know how to "fix" the Vista msstyles and XP VisualStyles incompatibility possibly?
Sorry that I don't understand your question. You sample code works fine on my Vista machine.
Could you please explain more about your question?
Sincerely, Linda Liu Microsoft Online Community Support
Brendon Bezuidenhout - 02 Nov 2007 19:18 GMT Linda,
Put that code in a class and build the application - then add the control created onto a form and put a combo box onto the same form... Now UNDER VISTA run the application and look at the form... What do you notice different? While the button is rendered correctly yes... It is not the visual style of Vista... When I've done OwnerDrawn controls under XP to ensure conformity in the UI I've used that block for example to ensure that dependant on the user system and theme selected the controls look and feel the same... Vista to XP and before this is not the way now...
Brendon
> Hi Brendon, > [quoted text clipped - 9 lines] > Linda Liu > Microsoft Online Community Support Linda Liu[MSFT] - 05 Nov 2007 09:00 GMT Hi Brendon,
In fact, the Vista visual style of a ComboBox drop down button has three appearances. Initially, the drop down button only shows a black triangle sign. If you hover the mouse over the drop down button, the drop down button appears activated. If you click on it, it appears pressed.
You can mimic the above appearances by handling the related events of the ComboBox and pass ComboBoxState.Hot or ComboBoxState.Pressed to the ComboBoxRenderer.DrawDropDownButton method.
Sincerely, Linda Liu Microsoft Online Community Support
Brendon Bezuidenhout - 05 Nov 2007 19:26 GMT Linda,
Please see my blog on this topic to see a screenshot of what I mean :) - I fully understand the ComboBox model and its rendering on Windows XP and pre XP days... my concern is the Aero and Vista days...
http://fileunderb.spaces.live.com/blog/cns!30E7F96B7150E7A7!273.entry
Brendon
> Hi Brendon, > [quoted text clipped - 10 lines] > Linda Liu > Microsoft Online Community Support Linda Liu[MSFT] - 07 Nov 2007 10:46 GMT Hi Dieter,
How about your problem now?
If you have any question, please feel free to let me know.
Thank you for using our MSDN Managed Newsgroup Support Service!
Sincerely, Linda Liu Microsoft Online Community Support
Dieter Pelz - 13 Nov 2007 09:34 GMT Hallo,
sorry for answering so late.
Will this error in the framework on Vista be fixed? Because it seemed for me that the state of the W32 TreeView Item and the .Net TreeView Item are not in sync! I used Reflector to look inside the problem and it seemed to be that the TreeItem will cache the state, but the state of the TreeViewItem in W32 is not the same.
Disabling Visual Styles ist not the right solution for me because it is a dialog inside a library that is used from an C++/CLI application.
Sincerely, Dieter Pelz
> Hi Dieter, > [quoted text clipped - 7 lines] > Linda Liu > Microsoft Online Community Support Linda Liu[MSFT] - 15 Nov 2007 09:39 GMT Hi Dieter,
Thank you for your reply!
The problem you entered has been reproduced, but our evaluation determined that it does not meet the criteria to be addressed in this release. This evaluation is carefully done and considers many aspects including fix cost, breaking changes, globalization, performance, etc.
Additionally, as part of planning and analysis of future versions this bug will be considered again for possible inclusion.
> Disabling Visual Styles ist not the right solution for me because it is a dialog inside a library that is used from an C++/CLI application.
How about the other solution of drawing the TreeView by ourselves that I provided in my first reply?
If you have any question, please feel free to let me know.
Sincerely, Linda Liu Microsoft Online Community Support
Dieter Pelz - 15 Nov 2007 13:33 GMT Hallo,
> Hi Dieter, > [quoted text clipped - 5 lines] > cost, > breaking changes, globalization, performance, etc. But this meens a WinForm App with an TreeView with Checkboxes is not usable under Vista. I think checkboxes will normally be used to select functions that will run on the nodes. In our app the checkbox will delete and change main configuration entries in a database. When an node is visibly not check but the state in Framework says it ist checked the functions will run. This makes TreeView with Checkboxes in every WinForm application not usable.
This brings me to another question: Does this means error in the .Net Framework will not be fixed because of the costs? The error will not affect breaking changes and globalization aspects. Performance could be affected because an TreeViewItem State must be asked when a mouse button is pressed.
> Additionally, as part of planning and analysis of future versions this bug > will be considered again for possible inclusion. [quoted text clipped - 4 lines] > How about the other solution of drawing the TreeView by ourselves that I > provided in my first reply? ImageLists are not attended and the look is not the same as in Vista. What must be change to get the same look as in Vista? What about Visual Styles? What about the property HideSelection?
I could send you an image from a test app and an test Project.
I adopted your code in a new class TreeViewVista inherited from TreeView. On the left side I used the new class TreeViewVista. On the right side I used the original class TreeView. Under every control there are labels. They will be filled with the state of the first related TreeNode.
Here is the Code of my TreeViewVista class: Where will I get the original bitmaps for plus and minus? What must be added to get the same look as the original TreeView?
File: TreeViewErrorVista.cs
using System; using System.Collections.Generic; using System.Text; using System.Windows.Forms; using System.Drawing;
namespace TreeViewErrorVista { public class TreeViewVista : TreeView { public TreeViewVista() { if (Environment.OSVersion.Version.Major >= 6) { DrawMode = TreeViewDrawMode.OwnerDrawAll; DrawNode += new DrawTreeNodeEventHandler(treeView1_DrawNode); } }
private void treeView1_DrawNode(object sender, DrawTreeNodeEventArgs e) { int left = e.Bounds.X; int top = e.Bounds.Y; int height = e.Bounds.Height;
int nodeleft = e.Node.Bounds.X; int nodetop = e.Node.Bounds.Y; int nodeheight = e.Node.Bounds.Height; int nodewidth = e.Node.Bounds.Width;
int linelength =10; int checkboxwidth = 13; int checknodespace = 2; using (Pen p = new Pen(Color.Gray)) { p.DashStyle = System.Drawing.Drawing2D.DashStyle.Dot; int lineleft = nodeleft-checknodespace-checkboxwidth-linelength; //draw horizontal dot line e.Graphics.DrawLine(p, lineleft, top + height / 2, lineleft + linelength, top + height / 2); // draw the up half vertical dot line if (e.Node.PrevNode != null || e.Node.Parent != null) { e.Graphics.DrawLine(p, lineleft, top, lineleft, top + height / 2); } // draw the down half vertical dot line if (e.Node.NextNode != null) { e.Graphics.DrawLine(p, lineleft, top + height / 2, lineleft, e.Node.NextNode.Bounds.Top); } // draw plus/minus image if (e.Node.Nodes.Count > 0) { if (!e.Node.IsExpanded) { e.Graphics.DrawImage(Properties.Resources.plus, lineleft - Properties.Resources.plus.Width / 2, top + (height - Properties.Resources.plus.Height) / 2); } else { e.Graphics.DrawImage(Properties.Resources.minus, lineleft - Properties.Resources.minus.Width / 2, top + (height - Properties.Resources.minus.Height) / 2); } } // draw the vertical dot line for the parent nodes if necessary TreeNode parentNode = e.Node.Parent; int parentNodeLeftDistance = checknodespace + checkboxwidth + linelength; while (parentNode != null) { if (parentNode.NextNode != null) { e.Graphics.DrawLine(p, parentNode.Bounds.X - parentNodeLeftDistance, top, parentNode.Bounds.X - parentNodeLeftDistance, top + height); } parentNode = parentNode.Parent; } } // draw checkbox if (e.Node.Checked) { ControlPaint.DrawCheckBox(e.Graphics, new Rectangle(nodeleft - checkboxwidth - checknodespace, top + (height - checkboxwidth) / 2, checkboxwidth, checkboxwidth), ButtonState.Checked); } else { ControlPaint.DrawCheckBox(e.Graphics, new Rectangle(nodeleft - checkboxwidth - checknodespace, top + (height - checkboxwidth) / 2, checkboxwidth, checkboxwidth), ButtonState.Normal); } // erase the previous node text using (Brush b = new SolidBrush(BackColor)) { e.Graphics.DrawString(e.Node.Text,Font, b, nodeleft, nodetop); } // draw node text and highlight rectangle if (e.Node.IsSelected) { ControlPaint.DrawFocusRectangle(e.Graphics, e.Node.Bounds);
e.Graphics.FillRectangle(Brushes.LightSkyBlue, new Rectangle(nodeleft + 1, nodetop + 1, nodewidth - 2, nodeheight - 2)); using (Brush b = new SolidBrush(Color.White)) { e.Graphics.DrawString(e.Node.Text, Font, b, nodeleft, nodetop); } } else { using (Brush b = new SolidBrush(ForeColor)) { e.Graphics.DrawString(e.Node.Text, Font, b, nodeleft, nodetop); } } }
} }
File: form1.cs using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms;
namespace TreeViewErrorVista { public partial class Form1 : Form { public Form1() { InitializeComponent(); }
private void timer1_Tick(object sender, EventArgs e) { if (treeViewVista1.Nodes[0].Checked) { lbtreeViewVista1.Text = "Checked"; } else { lbtreeViewVista1.Text = "Not checked"; }
if (treeView1.Nodes[0].Checked) { lbtreeView1.Text = "Checked"; } else { lbtreeView1.Text = "Not checked"; }
if (treeViewVista2.Nodes[0].Checked) { lbtreeViewVista2.Text = "Checked"; } else { lbtreeViewVista2.Text = "Not checked"; }
if (treeView2.Nodes[0].Checked) { lbtreeView2.Text = "Checked"; } else { lbtreeView2.Text = "Not checked"; }
}
private void Form1_Load(object sender, EventArgs e) {
foreach (TreeView tv in new TreeView[] { treeView1, treeView2, treeViewVista1, treeViewVista2 }) { TreeNode myNode = new TreeNode("TestNode", 0, 0); tv.Nodes.Add(myNode); myNode.Nodes.Add("SubNode2"); myNode.Nodes.Add("SubNode3"); tv.Nodes.Add(new TreeNode("TestNode2", 0, 0)); tv.Nodes.Add(new TreeNode("TestNode3", 0, 0)); } }
} }
> If you have any question, please feel free to let me know. > > Sincerely, > Linda Liu > Microsoft Online Community Support Sincerely. Dieter Pelz
Linda Liu[MSFT] - 16 Nov 2007 11:12 GMT Hi Dieter,
Thank you for feedback!
I understand your concern and I will forward your concern to our product team.
As for the workaround of custom drawing the TreeView by ourselves, I must say that it may be difficult to make the custom drawn TreeView look exactly the same as the standard TreeView, because the TreeView has so many properties that would influence the appearance and behavior of it. But we can do our best to make the custom drawn TreeView look more like a standard TreeView.
The following is the modified code of the custom drawn TreeView:
using System; using System.Windows.Forms; using System.Drawing; using System.Windows.Forms.VisualStyles;
public class TreeViewVista : TreeView { public TreeViewVista() { if (Environment.OSVersion.Version.Major >= 6) { DrawMode = TreeViewDrawMode.OwnerDrawAll; DrawNode += new DrawTreeNodeEventHandler(treeView1_DrawNode); } } int linelength = 0; private void treeView1_DrawNode(object sender, DrawTreeNodeEventArgs e) { int left = e.Bounds.X; int top = e.Bounds.Y; int height = e.Bounds.Height; int nodeleft = e.Node.Bounds.X; int nodetop = e.Node.Bounds.Y; int nodeheight = e.Node.Bounds.Height; int nodewidth = e.Node.Bounds.Width; int checkboxwidth = 13; int checknodespace = 2; if (e.Node.Level == 0 && e.Node.Index == 0) { linelength = nodeleft - checknodespace - checkboxwidth - left; if (this.ImageList != null) { linelength -= this.ImageList.ImageSize.Width; } linelength = linelength / 2; } int lineleft = nodeleft - checknodespace - checkboxwidth - linelength; if (this.ImageList != null) { lineleft -= this.ImageList.ImageSize.Width; }
using (Pen p = new Pen(Color.Gray)) { p.DashStyle = System.Drawing.Drawing2D.DashStyle.Dot;
//draw horizontal dot line e.Graphics.DrawLine(p, lineleft, top + height / 2, lineleft + linelength, top + height / 2); // draw the up half vertical dot line if (e.Node.PrevNode != null || e.Node.Parent != null) { e.Graphics.DrawLine(p, lineleft, top, lineleft, top + height / 2); } // draw the down half vertical dot line if (e.Node.NextNode != null) { e.Graphics.DrawLine(p, lineleft, top + height / 2, lineleft, e.Node.NextNode.Bounds.Top); } // draw plus/minus image if (e.Node.Nodes.Count > 0) { if (!e.Node.IsExpanded) { e.Graphics.DrawImage(Properties.Resources.plus, lineleft - Properties.Resources.plus.Width / 2, top + (height - Properties.Resources.plus.Height) / 2); } else { e.Graphics.DrawImage(Properties.Resources.minus, lineleft - Properties.Resources.minus.Width / 2, top + (height - Properties.Resources.minus.Height) / 2); } } // draw the vertical dot line for the parent nodes if necessary TreeNode parentNode = e.Node.Parent; int parentNodeLeftDistance = checknodespace + checkboxwidth + linelength; if (this.ImageList != null) { parentNodeLeftDistance += this.ImageList.ImageSize.Width; } while (parentNode != null) { if (parentNode.NextNode != null) { e.Graphics.DrawLine(p, parentNode.Bounds.X - parentNodeLeftDistance, top, parentNode.Bounds.X - parentNodeLeftDistance, top + height); } parentNode = parentNode.Parent; } } // draw checkbox if (e.Node.Checked) { CheckBoxRenderer.DrawCheckBox(e.Graphics, new Point(lineleft + linelength, top + (height - checkboxwidth) / 2), CheckBoxState.CheckedNormal); } else { CheckBoxRenderer.DrawCheckBox(e.Graphics, new Point(lineleft + linelength, top + (height - checkboxwidth) / 2), CheckBoxState.UncheckedNormal); }
// draw image if any if (this.ImageList != null && e.Node.ImageIndex >= 0) { e.Graphics.DrawImage(this.ImageList.Images[e.Node.ImageIndex], new Rectangle(lineleft + linelength + checkboxwidth, top - (this.ImageList.ImageSize.Height - height) / 2, this.ImageList.ImageSize.Width, this.ImageList.ImageSize.Height)); } // erase the previous node text and highlight background using (Brush b = new SolidBrush(BackColor)) { e.Graphics.DrawString(e.Node.Text, Font, b, nodeleft, nodetop + (nodeheight - this.Font.Height) / 2); e.Graphics.FillRectangle(b, new Rectangle(nodeleft + 1, nodetop + 1, nodewidth - 2, nodeheight - 2)); } // draw node text if (this.Focused && e.Node.IsSelected) { // draw highlight background e.Graphics.FillRectangle(SystemBrushes.Highlight, new Rectangle(nodeleft + 1, nodetop + 1, nodewidth - 2, nodeheight - 2)); } else if (!this.Focused && !this.HideSelection && e.Node.IsSelected) { // draw gray background e.Graphics.FillRectangle(SystemBrushes.ControlLight, new Rectangle(nodeleft + 1, nodetop + 1, nodewidth - 2, nodeheight - 2)); } // draw highlight rectangle if (e.Node.IsSelected && this.Focused) { using (Brush b = new SolidBrush(Color.White)) { e.Graphics.DrawString(e.Node.Text, Font, b, nodeleft, nodetop + (nodeheight - this.Font.Height) / 2); } } else { using (Brush b = new SolidBrush(ForeColor)) { e.Graphics.DrawString(e.Node.Text, Font, b, nodeleft, nodetop + (nodeheight - this.Font.Height) / 2); } } } } Please try the above code in your project to see if there's any problem in it and let me know the result.
Sincerely, Linda Liu Microsoft Online Community Support
Linda Liu[MSFT] - 21 Nov 2007 11:09 GMT Hi Dieter,
I have forwarded your concern to our product team.
How about the modified sample I gave you in my previous reply? Is there any problem?
If you have any question, please feel free to let me know.
Sincerely, Linda Liu Microsoft Online Community Support
Dieter Pelz - 26 Nov 2007 11:40 GMT Hallo Linda,
thanks for your sample.
I changed the recognition of the ImageList entry and now is looks like nearly the same.
How could I recognize if Visual Styles are enable to switch on the OwnerDraw function only with visual styles?
I recognized a 1 Pixel difference in horizontal axis between the OwnerDraw function an the real function. This could be a dependency on the bitmaps for plus and minus. What size must they have?
Thanks, Dieter Pelz
using System; using System.Collections.Generic; using System.Text; using System.Windows.Forms; using System.Windows.Forms.VisualStyles; using System.Drawing;
namespace TreeViewErrorVista { public class TreeViewVista : TreeView { public TreeViewVista() { if (Environment.OSVersion.Version.Major >= 6) { DrawMode = TreeViewDrawMode.OwnerDrawAll; DrawNode += new DrawTreeNodeEventHandler(treeView1_DrawNode); } }
int linelength = 0; private void treeView1_DrawNode(object sender, DrawTreeNodeEventArgs e) { int left = e.Bounds.X; int top = e.Bounds.Y; int height = e.Bounds.Height; int nodeleft = e.Node.Bounds.X; int nodetop = e.Node.Bounds.Y; int nodeheight = e.Node.Bounds.Height; int nodewidth = e.Node.Bounds.Width; int checkboxwidth = 13; int checknodespace = 2; if (e.Node.Level == 0 && e.Node.Index == 0) { linelength = nodeleft - checknodespace - checkboxwidth - left; if (this.ImageList != null) { linelength -= this.ImageList.ImageSize.Width; } linelength = linelength / 2; }
int lineleft = nodeleft - checknodespace - checkboxwidth - linelength; if (this.ImageList != null) { lineleft -= this.ImageList.ImageSize.Width; }
using (Pen p = new Pen(Color.Gray)) { p.DashStyle = System.Drawing.Drawing2D.DashStyle.Dot;
//draw horizontal dot line e.Graphics.DrawLine(p, lineleft, top + height / 2, lineleft + linelength, top + height / 2); // draw the up half vertical dot line if (e.Node.PrevNode != null || e.Node.Parent != null) { e.Graphics.DrawLine(p, lineleft, top, lineleft, top + height / 2); } // draw the down half vertical dot line if (e.Node.NextNode != null) { e.Graphics.DrawLine(p, lineleft, top + height / 2, lineleft, e.Node.NextNode.Bounds.Top); } // draw plus/minus image if (e.Node.Nodes.Count > 0) { if (!e.Node.IsExpanded) { e.Graphics.DrawImage(Properties.Resources.plus, lineleft - Properties.Resources.plus.Width / 2, top + (height - Properties.Resources.plus.Height) / 2); } else { e.Graphics.DrawImage(Properties.Resources.minus, lineleft - Properties.Resources.minus.Width / 2, top + (height - Properties.Resources.minus.Height) / 2); } } // draw the vertical dot line for the parent nodes if necessary TreeNode parentNode = e.Node.Parent; int parentNodeLeftDistance = checknodespace + checkboxwidth + linelength; if (this.ImageList != null) { parentNodeLeftDistance += this.ImageList.ImageSize.Width; } while (parentNode != null) { if (parentNode.NextNode != null) { e.Graphics.DrawLine(p, parentNode.Bounds.X - parentNodeLeftDistance, top, parentNode.Bounds.X - parentNodeLeftDistance, top + height); } parentNode = parentNode.Parent; } } // draw checkbox if (e.Node.Checked) { CheckBoxRenderer.DrawCheckBox(e.Graphics, new Point(lineleft + linelength, top + (height - checkboxwidth) / 2), CheckBoxState.CheckedNormal); } else { CheckBoxRenderer.DrawCheckBox(e.Graphics, new Point(lineleft + linelength, top + (height - checkboxwidth) / 2), CheckBoxState.UncheckedNormal); }
// draw image if any // if (this.ImageList != null && e.Node.ImageIndex >= 0) if (this.ImageList != null) { int imageIndex = e.Node.ImageIndex; if (e.Node.ImageIndex < 0) imageIndex = 0;
e.Graphics.DrawImage(this.ImageList.Images[imageIndex], new Rectangle(lineleft + linelength + checkboxwidth, top - (this.ImageList.ImageSize.Height - height) / 2, this.ImageList.ImageSize.Width, this.ImageList.ImageSize.Height)); } // erase the previous node text and highlight background using (Brush b = new SolidBrush(BackColor)) { e.Graphics.DrawString(e.Node.Text, Font, b, nodeleft, nodetop + (nodeheight - this.Font.Height) / 2); e.Graphics.FillRectangle(b, new Rectangle(nodeleft + 1, nodetop + 1, nodewidth - 2, nodeheight - 2)); } // draw node text if (this.Focused && e.Node.IsSelected) { // draw highlight background e.Graphics.FillRectangle(SystemBrushes.Highlight, new Rectangle(nodeleft + 1, nodetop + 1, nodewidth - 2, nodeheight - 2)); } else if (!this.Focused && !this.HideSelection && e.Node.IsSelected) { // draw gray background e.Graphics.FillRectangle(SystemBrushes.ControlLight, new Rectangle(nodeleft + 1, nodetop + 1, nodewidth - 2, nodeheight - 2)); } // draw highlight rectangle if (e.Node.IsSelected && this.Focused) { using (Brush b = new SolidBrush(Color.White)) { e.Graphics.DrawString(e.Node.Text, Font, b, nodeleft, nodetop + (nodeheight - this.Font.Height) / 2); } } else { using (Brush b = new SolidBrush(ForeColor)) { e.Graphics.DrawString(e.Node.Text, Font, b, nodeleft, nodetop + (nodeheight - this.Font.Height) / 2); } }
} }
}
> Hi Dieter, > [quoted text clipped - 9 lines] > Linda Liu > Microsoft Online Community Support Linda Liu[MSFT] - 27 Nov 2007 03:23 GMT Hi Dieter,
Thank you for your feedback!
> How could I recognize if Visual Styles are enable to switch on the OwnerDraw function only with visual styles?
You can use the Application.RenderWithVisualStyles property to recognize if Visual Styles are enabled.
> I recognized a 1 Pixel difference in horizontal axis between the OwnerDraw function an the real function. This could be a dependency on the bitmaps for plus and minus. What size must they have?
Do you mean the size of the bitmaps for the plus and minus? In my sample project, I set both the width and height of the two bitmaps to 9.
I made a small modification in the custom draw TreeView to ensure that the TreeView control is custom drawn only when the CheckBox property is true and the OS version is Vista and Visual Styles is enabled.
In addition, I implemented the ISupportInitialize interface in the derived TreeView class so as to set DrawMode property to OwnerDrawAll when the above condition is met at run time.
FYI, I use the Control.DesignMode property to recognize whether a control is at design time. However, it's too early to use this property in the constructor because the DesignMode property relies on the Site property(the Site property is set by the designer, if the Site property is not null, the DesignMode property returns true; otherwise, the DesignMode returns false) and the key point is that the control has not finished the construction in the constructor so the Site property has not been set and the DesignMode always returns false.
In the other hand, if a control implements the ISupportInitialize interface, the ISupportInitialize.BeginEdit and ISupportInitialize.EndEdit methods will be serialized in the InitializeComponent method of a form when we drag&drop this control onto a form.
Note that both the ISupportInitialize.BeginEdit and the ISupportInitialize.EndEdit method are serialized after the control is created, so we can use the DesignMode property to recognize if the control is at design time within either the ISupportInitialize.BeginEdit method or the ISupportInitialize.EndEdit method.
I will send my modified sample project to your email address. If there's any question in the sample project, please feel free to let me know.
Sincerely, Linda Liu Microsoft Online Community Support
Nice Mr. G - 16 Dec 2007 15:30 GMT > Hi Dieter, ...
> I will send my modified sample project to your email address. If there's > any question in the sample project, please feel free to let me know. > > Sincerely, > Linda Liu > Microsoft Online Community Support Any chance you can send me the modified sample Linda? Or, could you please post the current code.
Thanks much
Brendon Bezuidenhout - 01 Jan 2008 18:59 GMT Evening Linda,
Any chance you could send me a copy of the project you sent to Dieter?
Many thanks, Brendon Bezuidenhout
> Hi Dieter, > [quoted text clipped - 52 lines] > Linda Liu > Microsoft Online Community Support
Free MagazinesGet these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...
|
|
|