2012-04-11 2 views
10

Я создал новое приложение Windows Forms (C#) с одной простой формой, содержащей ListView. Тогда я изменил View Property к деталям и увеличение размера шрифта, используемого в этом ListView и вот результат:Тема Windows, влияющая на заголовок ListView

Вот как это выглядит на Windows XP с Windows Classic тему:
enter image description here

и вот результат с темой Windows XP:
enter image description here

я могу предотвратить появление моего приложения будут затронуты Visual Styles либо путем удаления Application.EnableVisualStyles() вызова или путем изменения Application.VisualStyleState: enter image description here
Несмотря на то, что это изменение приводит к тому, что ListView имеет желаемый внешний вид, он также влияет на внешний вид других элементов управления. Я бы хотел, чтобы мой ListView был единственным элементом управления, на который не влияют визуальные стили.

Я также обнаружил, аналогичные вопросы, которые пытаются справиться с ней:
Can you turn off visual styles/theming for just a single windows control?
How do I disable visual styles for just one control, and not its children?

К сожалению, ни одно из указанных решений не работает. Похоже, что заголовок будет состоять из некоторых элементов управления, на которые влияют визуальные стили, даже если визуальные стили для управления ListView отключены.

Любое решение C#, которое препятствовало бы визуальным стилям влиять на внешний вид заголовка ListView, было бы оценено.

ответ

2

После изнурительных исследований, я нашел его. Дело в том, что, когда вы звоните

SetWindowTheme(this.Handle, "", ""); 

в пользовательских ListView классе, он предотвращает визуальные стили от влияния на внешнем вид в элементе управления ListView, но не ListView управления заголовком (SysHeader32 окна), которое является дочерним окном ListView. Поэтому при вызове функции SetWindowTheme, мы должны обеспечить ручку окна заголовка вместо ручки ListView:

[DllImportAttribute("uxtheme.dll")] 
private static extern int SetWindowTheme(IntPtr hWnd, string appname, string idlist); 

[DllImport("user32")] 
[return: MarshalAs(UnmanagedType.Bool)] 
private static extern bool EnumChildWindows(IntPtr window, EnumWindowProc callback, IntPtr i); 

// Callback method to be used when enumerating windows: 
private static bool EnumWindow(IntPtr handle, IntPtr pointer) 
{ 
    GCHandle gch = GCHandle.FromIntPtr(pointer); 
    List<IntPtr> list = gch.Target as List<IntPtr>; 
    if (list == null) 
     throw new InvalidCastException("GCHandle Target could not be cast as List<IntPtr>"); 
    list.Add(handle); 
    return true; 
} 

// delegate for the EnumChildWindows method: 
private delegate bool EnumWindowProc(IntPtr hWnd, IntPtr parameter); 

// get first child: 
private static void DisableVisualStylesForFirstChild(IntPtr parent) 
{ 
    List<IntPtr> children = new List<IntPtr>(); 
    GCHandle listHandle = GCHandle.Alloc(children); 
    try 
    { 
     EnumWindowProc childProc = new EnumWindowProc(EnumWindow); 
     EnumChildWindows(parent, childProc, GCHandle.ToIntPtr(listHandle)); 
     if (children.Count > 0) 
      SetWindowTheme(children[0], "", ""); 
    } 
    finally 
    { 
     if (listHandle.IsAllocated) 
      listHandle.Free(); 
    } 
} 

protected override void OnHandleCreated(EventArgs e) 
{ 
    DisableVisualStylesForFirstChild(this.Handle); 
    base.OnHandleCreated(e); 
} 
+0

Поскольку это основано на решении, предложенном Камилом Лачем, я награждаю его ответ щедростью, которую я предлагал. – LihO

2

Как отключить визуальные стили?

с этим кодом можно отключить стиль для одного элемента управления (просто использовать ListViewConstrol вместо ListView):

using System; 
using System.Windows.Forms; 
using System.Runtime.InteropServices; 

public class ListViewControl : ListView { 
    [DllImportAttribute("uxtheme.dll")] 
    private static extern int SetWindowTheme(IntPtr hWnd, string appname, string idlist); 

    protected override void OnHandleCreated(EventArgs e) { 
    SetWindowTheme(this.Handle, "", ""); 
    base.OnHandleCreated(e); 
    } 
} 
+0

+1 за указание на то, что визуальные стили вызывают эти изменения, хотя это решение не работа на всех. – LihO

+0

Я узнал, почему SetWindowTheme не работал раньше. Он работает сейчас, проверьте мой ответ;) – LihO

+0

Поздравляю Камиля за баунти :) – ABH

3

Похоже, это known bug, для которого не существует простого решения. Согласно ответу нет:

После этого многих исследований этого вопроса, мы находим, что это ОС Windows ошибки, которую управление заголовком ComCtl6.0 забывает применять информация о шрифте чертежу ОКРУГ КОЛУМБИЯ.

Однако вы могли бы нарисовать колонтитул самостоятельно. См. this article on MSDN, чтобы узнать, как это сделать, а также посмотреть на listView1_DrawColumnHeader.

+0

+1 для рисования его самостоятельно –

+0

Рисование это само по себе не поможет, так как вы можете изменить только контент который рисуется, а не размер заголовка. – LihO

0

Как Botz3000 упомянул в своем ответе, что его хорошо известная проблема с ListView в Windows XP. Другим обходным решением является регистрация события ListView.DrawColumnHeader и сброс в нем шрифта заголовка. Вы должны установить ListView.OwnerDraw на true. Код MSDN выглядит следующим образом.

// Draws column headers. 
private void listView1_DrawColumnHeader(object sender, 
    DrawListViewColumnHeaderEventArgs e) 
{ 
    using (StringFormat sf = new StringFormat()) 
    { 
     // Store the column text alignment, letting it default 
     // to Left if it has not been set to Center or Right. 
     switch (e.Header.TextAlign) 
     { 
      case HorizontalAlignment.Center: 
       sf.Alignment = StringAlignment.Center; 
       break; 
      case HorizontalAlignment.Right: 
       sf.Alignment = StringAlignment.Far; 
       break; 
     } 

     // Draw the standard header background. 
     e.DrawBackground(); 

     // Draw the header text. 
     using (Font headerFont = 
        new Font("Helvetica", 10, FontStyle.Bold)) 
     { 
      e.Graphics.DrawString(e.Header.Text, headerFont, 
       Brushes.Black, e.Bounds, sf); 
     } 
    } 
    return; 
} 

В этом случае шрифт заголовка будет всегда "Helvetica", 10, FontStyle.Bold и не будет осуществляться шрифтом списка следует. Check MSDN для получения дополнительной информации.

+0

Нет, OwnerDraw - это не так, это невозможно повлиять на высоту заголовка ListView. – LihO

+0

@LihO Это не делает ничего с высотой заголовка, поскольку это невозможно в XP. Пожалуйста, внимательно прочитайте мой ответ, идея состоит в том, чтобы сохранить текст заголовка меньше, чтобы он соответствовал заголовку. – ABH

+0

Но мой вопрос заключается в том, как «заставить заголовок ListView иметь правильную высоту», а не как уменьшить текст заголовка ... – LihO

Смежные вопросы