Benutzer mit den meisten Antworten
Windows Aero Glas Effekte nutzen mit korrekter Darstellung der Steuerelemente

Frage
-
Hallo zusammen,
ich hofe jmand kann mir helfen.
Ich möchte gern ein Fenster in Aero Glass Optik erstrahlen lassen, was eigentlich ja auch kein Problem ist mit der DWMAPI, das bekomme ich ja auch hin.
Das Problem ist, dass Windows mir alle Teile im Fenster die Schwarz sind transparent gestaltet, da es denkt, dass es zu den Bereichen der Glass Oberfläche gehört.
Ich war auf der Suche nach Lösungen und bin auch fündig geworden. Eine war zb, die Steuerelemente abzuleiten und deren Darstellung selber zeichnen (Subclassing, Ownerdrawing) - dies ist aber keine gute Lösung für mich. (auch wenn es einigermaßen funktioniert)
Ich habe dann folgenden Artikel vonKenny Kerr gefunden, der beschreibt wie man die Farbe, die transparent dargestellt werden soll ändern kann.
Leider sind die Beispiele in C++ geschrieben und ich versuche diese in C# zu übersetzen. Bisher mit mäßigem Erfolg. Führe ich meinen übersetzten Code aus sieht mein Fenster so aus:klick -> Das Fenster zeichnet das was hinter ihm ist auf die Oberfläche, Glaß wird aber nicht dargestellt.
Es geht um folgenden Code von Kenny Kerr (C++):class SampleDialog : Public CDialogImpl<SampleDialog> { Public: enum { IDD = IDD_SAMPLE }; BEGIN_MSG_MAP(MainWindow) MSG_WM_INITDIALOG(OnInitDialog) MSG_WM_ERASEBKGND(OnEraseBackground) COMMAND_ID_HANDLER(IDCANCEL, OnCancel) END_MSG_MAP() SampleDialog() : m_transparencyKey(RGB(200, 201, 202)) { // Do Nothing } Private: LRESULT OnInitDialog(HWND /*Control*/ , LPARAM /*lParam*/ ) { SetWindowLong(GWL_EXSTYLE, GetExStyle() | WS_EX_LAYERED); VERIFY(::SetLayeredWindowAttributes(m_hWnd, m_transparencyKey, 0, LWA_COLORKEY)); Const MARGINS margins = { -1 }; COM_VERIFY(::DwmExtendFrameIntoClientArea(m_hWnd, &margins)); Return TRUE; // Yes, go ahead And Set the keyboard focus. } bool OnEraseBackground(CDCHandle dc) { CRect rect; VERIFY(GetClientRect(&rect)); dc.FillSolidRect(&rect, m_transparencyKey); Return True; // Yes, I erased the background. } LRESULT OnCancel(WORD /*notifyCode*/ , WORD identifier, HWND /*window*/ , BOOL& /*handled*/ ) { VERIFY(EndDialog(identifier)); Return 0; } Const COLORREF m_transparencyKey; };
____________________________________________________________________________
Ich habe das so umgesetzt:
public partial class Form1 : Form { [DllImport("user32.dll")] static extern bool SetLayeredWindowAttributes(IntPtr hwnd, uint crKey, byte bAlpha, uint dwFlags); [DllImport("user32.dll", CharSet = CharSet.Auto)] public static extern int GetWindowLong(IntPtr hWnd, int nIndex); [DllImport("user32.dll")] static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong); [DllImport("dwmapi.dll")] public static extern int DwmExtendFrameIntoClientArea(IntPtr hWnd, ref MARGINS pMarInset); [StructLayout(LayoutKind.Sequential)] public struct MARGINS { public int cxLeftWidth; public int cxRightWidth; public int cyTopHeight; public int cyBottomHeight; } public const int GWL_EXSTYLE = -20; public const int WS_EX_LAYERED = 0x80000; public const int LWA_ALPHA = 0x2; public const int LWA_COLORKEY = 0x1; public const int WS_EX_TRANSPARENT = 0x20; public Form1() { InitializeComponent(); } System.IntPtr hr; MARGINS m; private void Form1_Load(object sender, EventArgs e) { m = new MARGINS(); m.cxLeftWidth = -1; m.cxRightWidth = 0; m.cyBottomHeight = 0; m.cyTopHeight = 0; SetWindowLong(this.Handle, GWL_EXSTYLE, GetWindowLong(this.Handle, GWL_EXSTYLE) | WS_EX_LAYERED ); SetLayeredWindowAttributes(this.Handle, 0x00112233, 0, LWA_COLORKEY); DwmExtendFrameIntoClientArea(this.Handle, ref m); } protected override void OnPaintBackground(System.Windows.Forms.PaintEventArgs e) { e.Graphics.FillRectangle( new System.Drawing.SolidBrush(System.Drawing.Color.FromArgb(0x00112233)), this.ClientRectangle); this.Text += "!"; } }
Wie oben beschrieben funktioniert das ganze leider nciht so wirklich. Ich würde mich freuen, wenn mit jemand meinen Fehler aufzeigen könnte oder einen link zu einem Beispiel hat.
Danke!
- Bearbeitet Sebastian Gross Freitag, 16. Juli 2010 11:54 korrektur
Antworten
-
Ups, lies bitte späteren Kommentar des Autors:
The transparency key approach (using SetLayeredWindowAttributes) no longer works on RC1 and presumably won’t work in the RTM build.
und neuerer Artikel:
http://weblogs.asp.net/kennykerr/archive/2007/01/23/controls-and-the-desktop-window-manager.aspx
Unfortunately, when Microsoft finally released Windows Vista this "hack" no longer worked leaving developers to wonder how it could be done
- Als Antwort markiert Sebastian Gross Freitag, 16. Juli 2010 19:41
- Tag als Antwort aufgehoben Sebastian Gross Samstag, 17. Juli 2010 15:38
- Als Antwort markiert Sebastian Gross Samstag, 17. Juli 2010 15:40
Alle Antworten
-
Das Problem ist, dass Windows mir alle Teile im Fenster die Schwarz sind transparent gestaltet, da es denkt, dass es zu den Bereichen der Glass Oberfläche gehört.
Hallo Sebastian
nur zur Präzisierung (wie der Artikel schon erwähnt) das eigentliche 'Übel' ist wohl nicht die schwarze Farbe, sondern Elemente die per classic-GDI (und somit ohne Alpha) gezeichnet wurden.
Da einfach eine andere (spekulativ 'seltenere') Farbe für die Transparenz zu wählen ist immer nur ein 'Würgaround'...
Insbesondere wenn jemand gerade diese Farbe in den Windows-Farbeinstellungen irgendwo selektiert hat, werden deine Fenster/Steuerelemente hässlicher den je aussehen.
(Betroffen sind ggf auch entsprechende Pixels in Fotos + Farbverläufen) -
Ups, lies bitte späteren Kommentar des Autors:
The transparency key approach (using SetLayeredWindowAttributes) no longer works on RC1 and presumably won’t work in the RTM build.
und neuerer Artikel:
http://weblogs.asp.net/kennykerr/archive/2007/01/23/controls-and-the-desktop-window-manager.aspx
Unfortunately, when Microsoft finally released Windows Vista this "hack" no longer worked leaving developers to wonder how it could be done
- Als Antwort markiert Sebastian Gross Freitag, 16. Juli 2010 19:41
- Tag als Antwort aufgehoben Sebastian Gross Samstag, 17. Juli 2010 15:38
- Als Antwort markiert Sebastian Gross Samstag, 17. Juli 2010 15:40
-
Hallo Sebastian,
es gibt ein:
[Windows® API Code Pack for Microsoft® .NET Framework - Home]
http://code.msdn.microsoft.com/WindowsAPICodePackdort sind gute Glass-Beispiele enthalten und vor allen Dingen managed Wrapper für diese DWM-API-Calls, die Du momentan ja noch manuell aufrufst. Bzgl. Vista 64 Bit haben wir auch gerade einen (noch ungelösten) Thread laufen:
ciao Frank -
The transparency key approach (using SetLayeredWindowAttributes) no longer works on RC1 and presumably won’t work in the RTM build.
...
Hallo Thomas danke für den Hinweis, habe das total übersehen! Ohh mann, und ich saß da so lange dran und habe mich gewundert wo der Fehler ist. :(
Werde mir mal den weiteren Artikel angucken.
@Frank:Das Code Pack hatte ich mir auch angeschaut, wollte aber gerne eine schlanke Version haben die ich bei Bedarf anpassen kann, aber da führt wohl kein Weg dran vorbei...
"leaving developers to wonder how it could be done" - sehr schön! :)
-
Hallo Sebastian,
Du schriebst:
"Das Code Pack hatte ich mir auch angeschaut, wollte aber
gerne eine schlanke Version haben die ich bei Bedarf anpassen kann, ... "
Dann hast Du wohl nicht so richtig reingeschaut ;-) Das liegt als C# Code vor, und ist deswegen ja beliebig anpassbar. Deswegen habe ich es Dir ja empfohlen, weil Du daran ggf. Fehler entdecken kannst, denn die haben die Umsetzungen da gut nach best practice gemacht.
Aber trotzdem, wenn Du jetzt Deinen Fehler finden konntest und es funktioniert, besteht ja erstmal keine Notwendigkeit. Da kannst Du dann später drin schmökern.
ciao Frank -
Hallo Frank,
ich stöber gerade durch das Aero Sample aus dem Windows API Code Pack, und mir fällt auf, dass ich daraus einfach nicht schlau werde!
In dem Beispiel wird das Korrekte Darstellen der Steuerlemente dadurch erreicht, dass ein Panal benutzt wird, dass von der Glass-Oberfläche ausgeschlossen wird.
Hier der Ausschnitt aus der GlassForm Klasse:
public void ExcludeControlFromAeroGlass( Control control ) { if( AeroGlassCompositionEnabled ) { Rectangle clientScreen = this.RectangleToScreen( this.ClientRectangle ); Rectangle controlScreen = control.RectangleToScreen( control.ClientRectangle ); MARGINS margins = new MARGINS( ); margins.cxLeftWidth = controlScreen.Left - clientScreen.Left; margins.cxRightWidth = clientScreen.Right - controlScreen.Right; margins.cyTopHeight = controlScreen.Top - clientScreen.Top; margins.cyBottomHeight = clientScreen.Bottom - controlScreen.Bottom; // Extend the Frame into client area DesktopWindowManagerNativeMethods.DwmExtendFrameIntoClientArea( Handle, ref margins ); } }
Ich weiß ja nicht, aber in meinen Augen ist das keine Lösung! Denn so wird immer nur ein Control ausgeschlossen, dass dann alle anderen Controls beinhalten muss...
Und was ist, wenn ich die Controls direkt auf dem Glas plazieren will? Dann hilft mir das ganze überhaupt nicht weiter...
Gibts denn hier keine vernünftige Lösung, mit der man eine "normale" Darstellung erreichen kann, ohne auf WPF zu wechseln?
MfG, Basti
-
Hallo Basti,
- Du schriebst: "Gibts denn hier keine vernünftige Lösung, mit der man eine "normale" Darstellung erreichen kann, ohne auf WPF zu wechseln?"
Das Beispiel, was Du gepostet hast ist doch genau das für ein Windows Forms-Control (ohne WPF). Das, mit dem panel1 als Parameter ist die WPF Implementierung.
- Du schriebst: "Und was ist, wenn ich die Controls direkt auf dem Glas plazieren will? Dann hilft mir das ganze überhaupt nicht weiter..."
Hier dazu ggf. ein Beispiel:
[The Moth - Vista: Glass in C#]
http://www.danielmoth.com/Blog/Vista-Glass-In-C.aspxIn der MSDN sind natürlich auch Artikel vorhanden:
[Windows Vista for Developers – Part 3 – The Desktop Window Manager - Kenny Kerr]
http://weblogs.asp.net/kennykerr/archive/2006/08/10/Windows-Vista-for-Developers-_1320_-Part-3-_1320_-The-Desktop-Window-Manager.aspx
[Erweitern von Glasframe in eine WPF-Anwendung]
http://msdn.microsoft.com/de-de/library/ms748975.aspx
ciao Frank