VisualStyleRenderer и темы (WinForms)

У меня есть собственный элемент управления TreeView, который полностью принадлежит OwnerDraw'n:

  myTreeView.DrawMode = TreeViewDrawMode.OwnerDrawAll;

То, что я пытаюсь достичь, - это нарисовать открытый/закрытый глиф в соответствии с текущей темой исследователя. Особенно в Vista и Win7 я бы хотел видеть новые глифы (черные треугольники) вместо знаков плюс/минус. Я знаю, что для не-OwnerDraw'n TreeView это может быть достигнуто следующим образом, которое отлично работает:

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

Я думал, что VisualStyleRenderer позволяет мне рисовать значки с символикой:

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

Приведенный выше код, к сожалению, рисует знак минус во всех случаях. Похоже, что VisualStyleRenderer не соблюдает настройки темы.

Может кто-то пролить свет на это? Спасибо!

Ответы

Ответ 1

Я думаю, что это хорошая вещь, на которую я наткнулся на этот пост, мне хотелось узнать то же самое, когда я начал обновлять элемент управления Tree-Tree TreeView, используемый некоторыми из моих проектов, после некоторого взлома uxtheme на прошлой неделе я нашел используемые состояния by explorer и позже разместил их здесь для других: http://www.codeproject.com/KB/list/ObjectListView.aspx?msg=3492581#xx3492581xx

Ниже приведены стили недокументированные, установленные Windows при использовании API SetWindowTheme. Есть несколько других идентификаторов деталей и состояний, которые не перечислены здесь, но они не кажутся полезными, у меня есть проверка ошибок и VisualStyleRenderer.IsElementDefined() для краткости.

Эти имена классов, состояния и идентификаторы частей также могут использоваться API OpenThemeData/OpenThemeDataEx и DrawThemeBackground, если вам требуется их использование в собственном коде.

Стили Explorer TreeView:

(Они используются значками Glyph +/- expando)

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

(Эти два используются, когда мышь расположена над двумя вышеуказанными символами)

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

(зависание состояния над элементом TreeView)

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

(элемент выбранного дерева TreeView)

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

(Выбрано, но когда управление потеряло фокус (когда это .HideSelecton = False))

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

(есть также другое состояние SelectedTreeView, которое немного темнее, чем значение по умолчанию (1-3), используемое для отображения того, какой элемент выбран в данный момент, когда все элементы выбраны в данный момент?)

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

Стили списка ListView Explorer:

(зависание состояния над элементом ListView)

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

(элемент выбранного дерева TreeView)

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

(Выбрано, но когда управление потеряло фокус (когда это .HideSelecton = False))

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

(опять же есть еще одно выбранное состояние, которое немного темнее, чем значение по умолчанию (1-3), используемое для отображения того, какой элемент выбран в данный момент, когда все элементы выбраны в данный момент?)

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

Пример: (взято из 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);
} 

Просто убедитесь, что кэширует создание VisualStyleRenderer с таким свойством, чтобы вы не читали uxtheme.dll 100 раз в секунду, когда ваш элемент управления рисуется;)

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

       return closedRenderer;
   }    
}

пример с использованием кэшированного VisualStyleRenderer:

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

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

Enjoy. dmex