Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

VisualStyleRenderer and themes (WinForms)

Tags:

.net

winforms

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!

like image 770
Yves Avatar asked Jun 10 '10 13:06

Yves


1 Answers

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

like image 191
dmex Avatar answered Sep 26 '22 23:09

dmex