tags:

views:

193

answers:

1

I have my own TreeView control which is completely OwnerDraw'n:

  myTreeView.DrawMode = TreeViewDrawMode.OwnerDrawAll;

What I try to achieve is to draw the opened/closed glyph according to the current explorer theme. Especially on Vista and Win7 boxes I'd like to see the new glyphes (black triangles) instead of the plus/minus signs. I know, for a non-OwnerDraw'n TreeView this can be achieved as follows which works perfectly:

  myTreeView.HandleCreated += delegate(object sender, EventArgs args)
  {
     MyNativeMethods.SetWindowTheme(myTreeView.Handle, "explorer", null);
  };

I thought a VisualStyleRenderer let me paint the glyphs theme-aware:

  VisualStyleRenderer r = new VisualStyleRenderer(VisualStyleElement.TreeView.Glyph.Opened);
  r.DrawBackground(e.Graphics, e.Bounds);

The code above unfortunately draws the minus sign in all cases. It looks like the VisualStyleRenderer does not honour the theme setting.

Can someone shed some light on this? Thanks!

+2  A: 

Hi,

I guess its a good thing I stumbled across this post, I wanted to know the same thing when I started updating the Owner-Drawn TreeView control used by some of my projects, after some uxtheme hacking last week I found the states used by explorer and later posted them here for others: http://www.codeproject.com/KB/list/ObjectListView.aspx?msg=3492581#xx3492581xx

Here are the undocumented styles set by Windows when the SetWindowTheme API is used, There are a few other Part and State IDs not listed here but they dont seem useful, I have ommited error checking and VisualStyleRenderer.IsElementDefined() for brevity.

These class names, states and part IDs can also be used by the OpenThemeData/OpenThemeDataEx and DrawThemeBackground API's if you require their usage in native code.

Explorer TreeView Styles:

(These are used by the Glyph +/- expando icons)

VisualStyleRenderer OpenedRenderer = new VisualStyleRenderer("Explorer::TreeView", 2, 2);
VisualStyleRenderer ClosedRenderer = new VisualStyleRenderer("Explorer::TreeView", 2, 1); 

(These two are used when the mouse is positioned over the above two Glyph's)

VisualStyleRenderer HoverOpenedRenderer = new VisualStyleRenderer("Explorer::TreeView", 4, 2);
VisualStyleRenderer HoverClosedRenderer = new VisualStyleRenderer("Explorer::TreeView", 4, 1); 

(Hovering state over TreeView item)

VisualStyleRenderer ItemHoverRenderer = new VisualStyleRenderer("Explorer::TreeView", 1, 2); 

(Selected state TreeView item)

VisualStyleRenderer ItemSelectedRenderer = new VisualStyleRenderer("Explorer::TreeView", 1, 3);

(Selected but when control has lost focus (when this.HideSelecton = False))

VisualStyleRenderer LostFocusSelectedRenderer = new VisualStyleRenderer("Explorer::TreeView", 1, 5); 

(there is also another SelectedTreeView state thats a little darker than the default one (1-3) used for showing what item is currently selected when all items are currently selected??)

VisualStyleRenderer Selectedx2Renderer = new VisualStyleRenderer("Explorer::TreeView", 1, 6); 

Explorer ListView Styles:

(Hovering state over ListView item)

VisualStyleRenderer ItemHoverRenderer = new VisualStyleRenderer("Explorer::ListView", 1, 2); 

(Selected state TreeView item)

VisualStyleRenderer ItemSelectedRenderer = new VisualStyleRenderer("Explorer::ListView", 1, 3);

(Selected but when control has lost focus (when this.HideSelecton = False))

VisualStyleRenderer LostFocusSelectedRenderer = new VisualStyleRenderer("Explorer::ListView", 1, 5); 

(again there is also another Selected state thats a little darker than the default one (1-3) used for showing what item is currently selected when all items are currently selected??)

VisualStyleRenderer Selectedx2Renderer = new VisualStyleRenderer("Explorer::ListView", 1, 6); 

Example: (Taken from ObjectListView)

protected virtual void DrawExpansionGlyphStyled(Graphics g, Rectangle r, bool isExpanded)
{
VisualStyleElement glowelement = VisualStyleElement.CreateElement("Explorer::TreeView", 2, 1);

if (isExpanded)
glowelement = VisualStyleElement.CreateElement("Explorer::TreeView", 2, 2);

VisualStyleRenderer renderer = new VisualStyleRenderer(glowelement);
renderer.DrawBackground(g, r);
} 

Just make sure you cache the creation of the VisualStyleRenderer with a property so your not reading the uxtheme.dll 100's of times a second when your control is getting painted ;)

private static VisualStyleRenderer closedRenderer;
public static VisualStyleRenderer ClosedRenderer
{
   get
   {
       if (closedRenderer == null)
          closedRenderer = new VisualStyleRenderer("Explorer::TreeView", 2, 1);

       return closedRenderer;
   }    
}

above example using cached VisualStyleRenderer:

protected virtual void DrawExpansionGlyphStyled(Graphics g, Rectangle r, bool isExpanded)
{

if (isExpanded)
   OpenedRenderer.DrawBackground(g, r);
else
   ClosedRenderer.DrawBackground(g, r);
} 

Enjoy. dmex

dmex
Awesome, that does the trick! Many thanks.
Yves