Как заставить GDI + рендеринг ComboBox в C # на панели инструментов панели задач DeskBand? (вопрос прозрачности) - PullRequest
2 голосов
/ 15 мая 2009

Я реализовал панель инструментов панели задач DeskBand с помощью BandObjectLib ( Расширение проводника с помощью объектов Band с использованием .NET и Windows Forms ) из Codeproject, модифицированного поддержкой интерфейса IDeskBand2, который позволяет использовать меню «Пуск» в Windows Vista, чтобы сохранить прозрачность, когда моя панель инструментов на панели задач DeskBand включена. Однако текст, отображаемый в поле со списком или в текстовом поле, отображает цвет фона рабочего стола, смешанного с исходным цветом текста.

Метка не имеет этой проблемы, так как обычно она рисуется с использованием GDI (+), который игнорирует DWMComposition в отображаемом тексте (не в фоне метки).

Я понял, что проблема в том, что DWM работает в Vista в отношении определенных текстовых элементов, что объясняется на следующих страницах:

Использование элементов управления Vista на Aero Glass
Windows Vista Aero Pt. 1 - Добавление Glass в приложение Windows Forms
Добавление или модернизация Aero Glass в устаревшие приложения Windows

Я использую только комбинированный список на панели инструментов DeskBand, поэтому мне нужно только знать, как заставить комбинированный список не отображать с помощью DWM, даже если DWM включен в системе и включен на DeskBand посредством реализации IDeskBand2. интерфейс.

Обновление : я рассмотрел этот вопрос подробнее, и код C ++ на Добавление или переоборудование Aero Glass в устаревшие приложения Windows кажется наиболее вероятным вариантом для того, чтобы это заработало, поэтому в комбинированном списке отображаемый текст не прозрачен. Если кто-нибудь сможет взглянуть на этот код, относящийся только к списку, и помочь мне заставить его работать с списком C #, это сделает мой месяц! Я получил награду, чтобы надеяться получить ответ.

Ниже приведен класс EditProc.cpp из вышеупомянутого проекта, который должен обеспечить быстрый взгляд на то, что я рассматриваю как решение. Чтобы получить полную картину, вам нужно посмотреть на полный проект:

/*
*
* $RCSfile: aeroedit.cpp,v $
* $Source: /cvs/common/aeroedit.cpp,v $
* $Author: cvs $
* $Revision: 1.12 $
* $Date: 2007/05/20 10:38:25 $
* $State: Exp $
* Copyright (c) Stefan Kuhr
*/

#include <windows.h>
#include <tchar.h>
#include "safassrt.h"
#include "aaeroint.h"
#include "aerosubc.h"
#include "aeroglss.h"
#include <windowsx.h>
#include <gdiplus.h>
using namespace Gdiplus;

static void UpdateIfSelChanged(HWND hWnd, PAERO_SUBCLASS_WND_DATA pWndData)
{
    DWORD dwFirst, dwLast;
    SendMessage(hWnd, EM_GETSEL, (WPARAM)&dwFirst, (LPARAM)&dwLast);
    if(dwFirst!=pWndData->m_dwSelFirst || dwLast!=pWndData->m_dwSelLast)
    {
        pWndData->m_dwSelFirst = dwFirst;
        pWndData->m_dwSelLast = dwLast;
        VERIFY(InvalidateRect(hWnd, NULL, TRUE));
        VERIFY(UpdateWindow(hWnd));
    }
}


static LRESULT CALLBACK EditProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    PAERO_SUBCLASS_WND_DATA pWndData = (PAERO_SUBCLASS_WND_DATA)GetProp(hWnd,         WINDOW_DATA_STRING);
    ASSERT(pWndData);
    ASSERT(pWndData->m_pDwmApiImpl);
    WNDPROC pOldProc = pWndData->m_oldWndProc;
    ASSERT(pOldProc);
    PAERO_SUBCLASS_WND_DATA pWndDataParent =     (PAERO_SUBCLASS_WND_DATA)GetProp(GetParent(hWnd), WINDOW_DATA_STRING);

    /// 
    /// if aero glass is turned off and if we are not in destruction code, 
    /// just call the original wnd proc we had prior to subclassing:
    /// 
    if(WM_DESTROY!=uMsg && WM_NCDESTROY!=uMsg && WM_DWMCOMPOSITIONCHANGED!=uMsg &&     pWndDataParent && !pWndData->m_pDwmApiImpl->IsDwmCompositionEnabled())
        return CallWindowProc(pOldProc, hWnd, uMsg, wParam, lParam);



    if(pWndData->m_uiRedrawMsg==uMsg && pWndData->m_dwFlags & WD_IN_PAINT_CONTROL)
    {
        HDC hdc = GetDC(hWnd);
        hdc = GetDC(hWnd);
        if(hdc)
        {
            RECT rcClient;
            GetClientRect(hWnd, &rcClient);

            BP_PAINTPARAMS params = { sizeof(BP_PAINTPARAMS) };
            params.dwFlags        = 0L;//BPPF_ERASE;
            HDC hdcPaint = NULL;
            HPAINTBUFFER hBufferedPaint = pWndData->m_pUxTheme->BeginBufferedPaint(hdc,     &rcClient, BPBF_TOPDOWNDIB, &params,     &hdcPaint);
            if (hdcPaint)
            {
                LONG_PTR dwStyle = GetWindowLongPtr(hWnd, GWL_STYLE);
                DWORD_PTR dwSyscolorIdx = (dwStyle&WS_DISABLED ||         dwStyle&ES_READONLY)?COLOR_3DFACE:COLOR_WINDOW;
                VERIFY(FillRect(hdcPaint, &rcClient, (HBRUSH)(dwSyscolorIdx+1)));

                SendMessage(hWnd, WM_PRINTCLIENT, (WPARAM) hdcPaint,     PRF_CLIENT|PRF_CHECKVISIBLE);

                /// Make every pixel opaque
                    VERIFY(S_OK==pWndData->m_pUxTheme->BufferedPaintMakeOpaque_(hBufferedPaint, &rcClient));
                VERIFY(S_OK==pWndData->m_pUxTheme->EndBufferedPaint(hBufferedPaint, TRUE));    
        }

        VERIFY(1==ReleaseDC(hWnd, hdc));
        pWndData->m_dwFlags &= ~WD_IN_PAINT_CONTROL;
    }

    return 1;
}

switch(uMsg)
{
    case WM_KEYDOWN:
    {    
        LONG_PTR dwStyle = GetWindowLongPtr(hWnd, GWL_STYLE);
        if(dwStyle&WS_VSCROLL || dwStyle&ES_MULTILINE)
        {
            if(!(pWndData->m_dwFlags&WD_CARET_HIDDEN))
            {
                HideCaret(hWnd);
                pWndData->m_dwFlags|=WD_CARET_HIDDEN;
            }
        }
    }
        break;
    case WM_KEYUP:
    case WM_LBUTTONDOWN:
    case WM_LBUTTONUP:
    case WM_MOUSELEAVE:
    {
        LONG_PTR dwStyle = GetWindowLongPtr(hWnd, GWL_STYLE);
        if(dwStyle&WS_VSCROLL || dwStyle&ES_MULTILINE)
        {
            if(pWndData->m_dwFlags&WD_CARET_HIDDEN)
            {
                ShowCaret(hWnd);
                pWndData->m_dwFlags&=~WD_CARET_HIDDEN;
            }

            UpdateIfSelChanged(hWnd, pWndData);
        }
    }
        break;
    case WM_NCPAINT:
        {
            LRESULT lRes = 0;
            lRes = CallWindowProc(pOldProc, hWnd, uMsg, wParam, lParam);
            DrawEditBorder(hWnd, pWndData);
            return lRes;
        }
    case WM_NCDESTROY:
    case WM_DESTROY:
        VERIFY(UnsubclassControl(hWnd, EditProc, pWndData));
        break;
}

return CallWindowProc(pOldProc, hWnd, uMsg, wParam, lParam);
}

BOOL AeroSubClassEdit(HWND hwnd)
{
    return AeroSubClassControl(hwnd, EditProc, WD_IN_PAINT_CONTROL);
}

Спасибо,

Джон Реннемайер
МувЭнум, ООО

1 Ответ

2 голосов
/ 30 мая 2009

Это полная боль, я не знаю, почему у Microsoft не было элементов управления WinForms, работающих с DWMManager. TextBox легко сделать, вы можете перерисовать его поверх него. DropDown сложнее, потому что внутри него есть поле «Edit» встроенного элемента управления. Поскольку это не элемент управления .Net (часть редактирования), вы не можете использовать классы .Net, чтобы легко перерисовать его (я все еще пытаюсь выяснить, как это сделать).

Я, однако, выяснил, как заставить DropDown отображать на стекле, но только если часть текстового поля отключена (что делается путем изменения стиля). Не совсем идеально. Мой в VB.Net, и я все еще работаю над этим. Тем не менее, я был вдохновлен этим проектом, в котором этот парень реализовал его на C #, и он может оказать вам большую помощь:

http://dwmwinform.codeplex.com/

Как примечание, WPF поддерживает эффект Aero Glass со всеми его элементами управления. Это более мощный, но и более трудоемкий в использовании (IMO ... и, WPF не принесет вам никакой пользы, если вы ретро-приложение WinForms). Мне просто нравятся WinForms, так как я пишу бизнес-приложения и мне все равно, у меня нет времени писать анимации (WPF - это круто, не ошибайтесь, я предпочитаю WinForms).

Это мой старт, когда я унаследовал ComboBox (в Vb.Net). Этот сайт не публикует весь класс правильно, поэтому я просто включу внутреннюю часть класса:

    ''' <summary>
''' Enum of Windows messages that will trigger the redraw of the control
''' </summary>
''' <remarks></remarks>
Public Enum WindowsMessage
    WM_CHAR = &H100
    WM_KEYDOWN = &H102
    WM_MOUSEMOVE = &H200
    WM_PAINT = 15
    WM_PRINT = &H314
End Enum

''' <summary>
''' Constructor
''' </summary>
''' <remarks></remarks>
Sub New()
    Me.DropDownStyle = ComboBoxStyle.DropDownList
End Sub

''' <summary>
''' Processing of incoming messages.  We're going to get a bitmap of the control and then
''' redraw it onto the form when a few specified windows messages come through.
''' </summary>
''' <param name="m"></param>    
Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
    MyBase.WndProc(m)

    Select Case m.Msg
        Case WindowsMessage.WM_PAINT, WindowsMessage.WM_CHAR, WindowsMessage.WM_KEYDOWN, _
             WindowsMessage.WM_MOUSEMOVE, WindowsMessage.WM_PRINT
            RedrawControlAsBitmap(Me.Handle)
    End Select

End Sub

''' <summary>
''' Redraws a given control as a bitmap ontop of itself.
''' </summary>
''' <param name="hwnd"></param>
''' <remarks></remarks>
Public Sub RedrawControlAsBitmap(ByVal hwnd As IntPtr)

    Dim c As Control = Control.FromHandle(hwnd)

    If c IsNot Nothing Then
        Using bm As New Bitmap(c.Width, c.Height)
            c.DrawToBitmap(bm, c.ClientRectangle)

            Using g As Graphics = c.CreateGraphics
                g.DrawImage(bm, New Point(0, 0))
            End Using

        End Using
    End If

    c = Nothing

End Sub
...