visual studio microsoft español descargar community c# .net wpf winapi dwm

c# - studio - Detectar cambios en el tema del sistema en WPF



visual studio installer (3)

El evento SystemEvents.UserPreferenceChanged también funciona. UserPreferenceChanged (en Japaense)

Necesito, para mi aplicación WPF, detectar cuándo se activa o desactiva el DWM o cuándo cambia el tema del sistema.
Hay un evento así en WinForms, pero no puedo ver ninguno en WPF.


Lamentablemente, la solución aceptada no funciona con los cambios de tema de color Aero, y los números hexadecimales del mensaje de WM están mezclados, pero estoy de acuerdo en que es muy útil si desea capturar los mensajes de WM en WPF. He estado tratando de encontrar una solución a este problema por un tiempo, y creo que lo he resuelto para todos los casos posibles (para temas aerodinámicos y clásicos).

El cambio de color Aero desencadena el mensaje WM_DWMCOLORIZATIONCOLORCHANGED.

Para detectar cuándo cambia el tema de color, debe usar varios métodos. El evento Form.StyleChanged detectará todos los cambios de tema, excepto los cambios de color Aero . Aquí hay una solución alternativa a StyleChanged. (Ok, sé que esto es WinForms, pero ya entendiste la idea. El equivalente de WPF está en la respuesta aceptada de todos modos).

private const int WM_DWMCOLORIZATIONCOLORCHANGED = 0x320; private const int WM_DWMCOMPOSITIONCHANGED = 0x31E; private const int WM_THEMECHANGED = 0x031A; protected override void WndProc(ref Message m) { switch(m.Msg) { case WM_DWMCOLORIZATIONCOLORCHANGED: case WM_DWMCOMPOSITIONCHANGED: case WM_THEMECHANGED: // you code here break; default: break; } base.WndProc(ref m); }

Para los temas de color Aero, el evento SystemEvents.UserPreferenceChanged también funciona (¡gracias, gracias!):

Microsoft.Win32.SystemEvents.UserPreferenceChanged += SystemEvents_UserPreferenceChanged; private void SystemEvents_UserPreferenceChanged(object sender, Microsoft.Win32.UserPreferenceChangedEventArgs e) { if (e.Category == Microsoft.Win32.UserPreferenceCategory.General) { // your code here, compare saved theme color with current one } }

Como puede ver arriba, está lejos de ser intuitivo. El cambio de color Aero desencadena un evento de cambio de preferencia ''General'', aunque hay muchos más adecuados para esto, como ''VisualStyle'', etc.

Si quieres ser minucioso, debes comparar el color DWM guardado con el color DWM actual, para asegurarte de que fue de hecho un tema de color Aero que activó este evento (utilizando la llamada API DwmGetColorizationParameters), y no de otra cosa. Vea estas respuestas sobre cómo se pueden recuperar los colores Aero: obtenga el color activo del tema de color automático de Windows 8


No he oído hablar de un evento de WinForms que se dispara cuando una ventana de WinForms recibe mensajes del sistema, sin embargo, tiene su propio método WndProc() que puede anular. Probablemente esté confundiendo los mensajes de la ventana para los eventos de formulario. Ah, entonces es el evento StyleChanged que se invoca en las ventanas de WinForms. El resto de mi respuesta aún se mantiene.

WPF no está estrechamente vinculado a la API de Windows, ya que es una tecnología de alto nivel que invierte una gran cantidad de abstracción de las partes internas. Por un lado, dibuja todo en una ventana por sí mismo, y no le pide al sistema que haga el dibujo ( EDIT: que es la razón por la que WPF carece de un evento StyleChanged ). Dicho esto, Windows envía mensajes a todas las ventanas cuando se alterna el DWM y cuando cambia el tema, y ​​aún se puede profundizar en el nivel bajo de la capa de WPF para acceder a estos mensajes y manipular los controles de WPF en consecuencia.

Adjunte un procedimiento de ventana al HWND de su ventana WPF (identificador de ventana) como parte del evento SourceInitialized de su ventana. En su procedimiento de ventana, maneje los mensajes de ventana WM_DWMCOMPOSITIONCHANGED y WM_THEMECHANGED respectivamente.

Aquí hay un ejemplo rápido (con un código repetitivo adaptado de esta pregunta mía ):

private IntPtr hwnd; private HwndSource hsource; private void Window_SourceInitialized(object sender, EventArgs e) { if ((hwnd = new WindowInteropHelper(this).Handle) == IntPtr.Zero) { throw new InvalidOperationException("Could not get window handle."); } hsource = HwndSource.FromHwnd(hwnd); hsource.AddHook(WndProc); } private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) { switch (msg) { case WM_DWMCOMPOSITIONCHANGED: // Define this as 0x31A case WM_THEMECHANGED: // Define this as 0x31E // Respond to DWM being enabled/disabled or system theme being changed return IntPtr.Zero; default: return IntPtr.Zero; } }