Nota
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
API importantes
Nota
En esta página se trata el desarrollo de WPF heredado para Windows 8.1. Si está desarrollando aplicaciones de WPF para Windows 10, consulte la documentación más reciente en GitHub.
Windows 8.1 proporciona a los desarrolladores nuevas funcionalidades para crear aplicaciones de escritorio que son compatibles con PPP por monitor. Para aprovechar esta funcionalidad, una aplicación compatible con PPP por monitor debe hacer lo siguiente:
- Cambiar las dimensiones de la ventana para mantener un tamaño físico que parezca coherente en cualquier pantalla
- Volver a diseñar y volver a representar gráficos para el nuevo tamaño de ventana
- Seleccione las fuentes que se escalan correctamente para el nivel de PPP.
- Selección y carga de recursos de mapa de bits adaptados para el nivel de PPP
Para facilitar la creación de una aplicación compatible con PPP por monitor, Windows 8.1 proporciona las siguientes API de Microsoft Win32APIs:
- SetProcessDpiAwareness (o entrada de manifiesto de PPP) establece el proceso en un nivel de reconocimiento de PPP especificado, que determina cómo Windows escala la interfaz de usuario. Esto sustituye a SetProcessDPIAware.
- GetProcessDpiAwareness devuelve el nivel de reconocimiento de PPP. Esto sustituye a IsProcessDPIAware.
- GetDpiForMonitor devuelve el valor de PPP de un monitor.
- La notificación de la ventana de WM_DPICHANGED se envía a las aplicaciones compatibles con PPP por monitor cuando cambia la posición de una ventana de forma que la mayoría de su área intersece un monitor con un valor de PPP distinto del VALOR de PPP antes del cambio de posición o cuando el usuario mueve el control deslizante de pantalla. Para crear una aplicación que cambie el tamaño y vuelva a representarse cuando un usuario la mueve a otra pantalla, use esta notificación.
Para obtener más información sobre los distintos niveles de reconocimiento de PPP admitidos para las aplicaciones de escritorio en Windows 8.1 vea el tema Escribir aplicaciones de escritorio y Win32 de escritorio DPI-Aware.
Escalado de PPP y WPF
las aplicaciones de Windows Presentation Foundation (WPF) son compatibles con ppp del sistema de forma predeterminada. Para obtener definiciones de los distintos niveles de reconocimiento de PPP, consulte el tema Escribir DPI-Aware aplicaciones de escritorio y Win32. El sistema de gráficos de WPF usa unidades independientes del dispositivo para habilitar la resolución y la independencia del dispositivo. WPF escala cada píxel independiente del dispositivo automáticamente en función de ppp del sistema actual. Esto permite que las aplicaciones de WPF se escalen automáticamente cuando el ppp del monitor en el que se encuentra la ventana es el mismo ppp del sistema. Sin embargo, dado que las aplicaciones wpF son compatibles con ppp del sistema, el sistema operativo escalará la aplicación cuando la aplicación se mueva a un monitor con un ppp diferente o cuando se use el control deslizante en el panel de control para cambiar el PPP. El escalado en el sistema operativo puede dar lugar a que las aplicaciones wpF aparezcan borrosas especialmente cuando el escalado no es integral. Para evitar el escalado de aplicaciones WPF, deben actualizarse para que sean compatibles con PPP por monitor.
Tutorial de ejemplo de WPF compatible con monitor
El ejemplo wpF compatible con cada monitor es una aplicación WPF de ejemplo actualizada para que sea compatible con PPP por monitor. El ejemplo consta de dos proyectos:
- NativeHelpers.vcxproj: se trata de un proyecto auxiliar nativo que implementa la funcionalidad principal para hacer que una aplicación WPF sea compatible con PPP según el monitor utilizando las API win32APIs anteriores. El proyecto contiene dos clases:
- PerMonDPIHelpers: clase que proporciona funciones auxiliares para operaciones relacionadas con PPP, como recuperar el ppp actual del monitor activo, establecer un proceso para que sea compatible con PPP por monitor, etc.
- PerMonitorDPIWindow: una clase base derivada de System.Windows.Window que implementa la funcionalidad para hacer que una ventana de aplicación wpF sea compatible con ppp por monitor. Ajusta el tamaño de la ventana, el tamaño de representación de gráficos y el tamaño de fuente en función del ppp del monitor en lugar del ppp del sistema.
- WPFApplication.csproj: aplicación WPF de ejemplo que consume PerMonitorDPIWindow (PerMonitorDPIWindow) y muestra cómo cambia el tamaño de la ventana de la aplicación y la representación cuando la ventana se mueve a un monitor con un ppp diferente o cuando se usa el control deslizante en el panel de control mostrar para cambiar el valor de PPP.
Para ejecutar el ejemplo, siga estos pasos:
- Descargar y descomprimir el ejemplo de WPF compatible con cada monitor
- Inicie Microsoft Visual Studio y seleccione Archivo > abrir > proyecto o solución.
- Vaya al directorio que contiene el ejemplo descomprimido. Vaya al directorio denominado para el ejemplo y haga doble clic en el archivo de solución de Visual Studio (.sln).
- Presione F7 o use Compilar > solución para compilar el ejemplo.
- Presione Ctrl+F5 o use Depurar > Iniciar sin depurar para ejecutar el ejemplo.
Para ver el impacto del cambio de PPP en una aplicación WPF que se actualiza para que sea compatible con PPP por monitor mediante la clase base del ejemplo, mueva la ventana de la aplicación hacia y desde las pantallas que tienen diferentes DPIs. A medida que la ventana se mueve entre monitores, el tamaño de la ventana y la escala de la interfaz de usuario se actualizan en función del PPP de la pantalla mediante el sistema gráfico escalable de WPF, en lugar de ser escalado por el sistema operativo. La interfaz de usuario de la aplicación se representa de forma nativa y no aparece borrosa. Si no tiene dos pantallas con ppp diferentes, cambie el valor de PPP cambiando el control deslizante en el panel de control Mostrar. Cambiar el control deslizante y hacer clic en Aplicar cambiará el tamaño de la ventana de la aplicación y actualizará la escala de la interfaz de usuario automáticamente.
Actualización de una aplicación WPF existente para que sea compatible con ppp por monitor mediante el proyecto auxiliar en el ejemplo de WPF
Si tiene una aplicación WPF existente y desea aprovechar el proyecto auxiliar de PPP del ejemplo para que sea consciente de PPP, siga estos pasos.
Descargar y descomprimir el ejemplo de WPF compatible con cada monitor
Inicie Visual Studio y seleccione Archivo > abrir > proyecto o solución.
Vaya al directorio que contiene una aplicación WPF existente y haga doble clic en el archivo de solución de Visual Studio (.sln).
Haga clic con el botón derecho en Agregar >> proyecto existente
En el cuadro de diálogo de selección de archivos, vaya al directorio que contiene el ejemplo descomprimido. Abra el directorio denominado para el ejemplo, vaya a la carpeta "NativeHelpers", seleccione el archivo de proyecto de Visual C++ "NativeHelpers.vcxproj" y haga clic en Aceptar.
Haga clic con el botón derecho en el proyecto NativeHelpers y seleccione Compilar. Esto generará NativeHelpers.dll que se agregarán como referencia a la aplicación de WPF en el paso siguiente
.
Agregue una referencia a NativeHelpers.dll desde la aplicación WPF. Expanda el proyecto de aplicación WPF, haga clic con el botón derecho en Referencias y haga clic en Agregar referencia...
En el diálogo resultante, expanda la sección Solución . En Proyectos, seleccione NativeHelpers y haga clic en Aceptar
.
Expanda el proyecto de aplicación WPF, expanda Propiedades y abra AssemblyInfo.cs. Realice las siguientes adiciones a AssemblyInfo.cs
- Agregue referencia a System.Windows.Media en la sección de referencia (mediante System.Windows.Media;)
- Agregue el atributo DisableDpiAwareness (
[assembly: DisableDpiAwareness]
)
Heredar la clase de ventana principal de WPF de la clase base PerMonitorDPIWindow
Actualice el archivo .cs de la ventana principal de WPF para heredar de la clase base PerMonitorDPIWindow.
- Agregue una referencia a NativeHelpers en la sección de referencia agregando la línea
using NativeHelpers;
- Heredar la clase de ventana principal de la clase PerMonitorDPIWindow
- Agregue una referencia a NativeHelpers en la sección de referencia agregando la línea
Actualice el archivo .xaml de la ventana principal de WPF para heredar de la clase base PerMonitorDPIWindow.
- Agregue una referencia a NativeHelpers en la sección de referencia agregando la línea
xmlns:src="clr-namespace:NativeHelpers;assembly=NativeHelpers"
- Heredar la clase de ventana principal de la clase PerMonitorDPIWindow
- Agregue una referencia a NativeHelpers en la sección de referencia agregando la línea
Presione F7 o use Compilar > solución para compilar el ejemplo.
Presione Ctrl+F5 o use Depurar > Iniciar sin depurar para ejecutar el ejemplo.
La aplicación de ejemplo wpF con reconocimiento por monitor muestra cómo se puede actualizar una aplicación WPF para que sea compatible con PPP por monitor respondiendo a la notificación de ventana de WM_DPICHANGED . En respuesta a la notificación de ventana, el ejemplo actualiza la transformación de escala usada por WPF según el valor de PPP actual del monitor en el que se encuentra la ventana. El wParam de la notificación de ventana contiene el nuevo valor de PPP en wParam. LParam contiene un rectángulo que tiene el tamaño y la posición de la nueva ventana sugerida, escalado para el nuevo PPP.
Nota:
Nota
Dado que este ejemplo sobrescribe el tamaño de la ventana y la transformación de escala del nodo raíz de la ventana de WPF, el desarrollador de aplicaciones puede requerir más trabajo si:
- El tamaño de la ventana afecta a otras partes de la aplicación, como esta ventana de WPF que se hospeda dentro de otra aplicación.
- La aplicación WPF que extiende esta clase está estableciendo alguna otra transformación en el objeto visual raíz; El ejemplo puede sobrescribir alguna otra transformación que aplique la propia aplicación WPF.
Información general del proyecto auxiliar en el ejemplo de WPF
Para que una aplicación WPF existente sea compatible con PPP por monitor, la biblioteca NativeHelpers proporciona la siguiente funcionalidad:
Marca la aplicación WPF como compatible con PPP por ponitor: La aplicación WPF se marca como compatible con PPP por monitor mediante una llamada a SetProcessDpiAwareness para el proceso actual. Marcar la aplicación según el monitor con reconocimiento de PPP garantizará que
- El sistema operativo no escala la aplicación cuando el PPP del sistema no coincide con el PPP actual del monitor en el que se encuentra la ventana de la aplicación.
- El mensaje de WM_DPICHANGED se envía cada vez que cambia el VALOR de PPP de la ventana.
Ajusta la dimensión de ventana, vuelve a diseñar y volver a representar el contenido gráfico y selecciona fuentes basadas en el PPP inicial del monitor en el que se encuentra la ventana: Una vez que la aplicación se marca como compatible con PPP por monitor, WPF seguirá escalando el tamaño de la ventana, los gráficos y el tamaño de fuente en función del PPP del sistema. Puesto que, en el inicio de la aplicación, no se garantiza que el VALOR de PPP del sistema sea el mismo que el ppp del monitor en el que se inicia la ventana, la biblioteca ajusta estos valores una vez cargada la ventana. La clase base PerMonitorDPIWindow las actualiza en el controlador OnLoaded().
El tamaño de la ventana se actualiza cambiando las propiedades Width y Height de la ventana. El diseño y el tamaño se actualizan aplicando una transformación de escala adecuada al nodo raíz de la ventana de WPF.
void PerMonitorDPIWindow::OnLoaded(Object^ , RoutedEventArgs^ ) { if (m_perMonitorEnabled) { m_source = (HwndSource^) PresentationSource::FromVisual((Visual^) this); HwndSourceHook^ hook = gcnew HwndSourceHook(this, &PerMonitorDPIWindow::HandleMessages); m_source->AddHook(hook); //Calculate the DPI used by WPF. m_wpfDPI = 96.0 * m_source->CompositionTarget->TransformToDevice.M11; //Get the Current DPI of the monitor of the window. m_currentDPI = NativeHelpers::PerMonitorDPIHelper::GetDpiForWindow(m_source->Handle); //Calculate the scale factor used to modify window size, graphics and text m_scaleFactor = m_currentDPI / m_wpfDPI; //Update Width and Height based on the on the current DPI of the monitor Width = Width * m_scaleFactor; Height = Height * m_scaleFactor; //Update graphics and text based on the current DPI of the monitor UpdateLayoutTransform(m_scaleFactor); } } void PerMonitorDPIWindow::UpdateLayoutTransform(double scaleFactor) { // Adjust the rendering graphics and text size by applying the scale transform to the top level visual node of the Window if (m_perMonitorEnabled) { auto child = GetVisualChild(0); if (m_scaleFactor != 1.0) { ScaleTransform^ dpiScale = gcnew ScaleTransform(scaleFactor, scaleFactor); child->SetValue(Window::LayoutTransformProperty, dpiScale); } else { child->SetValue(Window::LayoutTransformProperty, nullptr); } } }
Responde a WM_DPICHANGED notificación de ventana: Actualice el tamaño de la ventana, los gráficos y el tamaño de fuente en función de los valores de PPP pasados en la notificación de la ventana. La clase base PerMonitorDPIWindow controla la notificación de ventana en el método HandleMessages().
El tamaño de la ventana se actualiza llamando a SetWindowPos mediante la información pasada en el lparam del mensaje de la ventana. El diseño y el tamaño de los gráficos se actualizan aplicando una transformación de escala adecuada al nodo raíz de la ventana de WPF. El factor de escala se calcula mediante el valor de PPP pasado en el wparam del mensaje de ventana.
IntPtr PerMonitorDPIWindow::HandleMessages(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, bool% ) { double oldDpi; switch (msg) { case WM_DPICHANGED: LPRECT lprNewRect = (LPRECT)lParam.ToPointer(); SetWindowPos(static_cast<HWND>(hwnd.ToPointer()), 0, lprNewRect->left, lprNewRect- >top, lprNewRect->right - lprNewRect->left, lprNewRect->bottom - lprNewRect->top, SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_NOACTIVATE); oldDpi = m_currentDPI; m_currentDPI = static_cast<int>(LOWORD(wParam.ToPointer())); if (oldDpi != m_currentDPI) { OnDPIChanged(); } break; } return IntPtr::Zero; } void PerMonitorDPIWindow::OnDPIChanged() { m_scaleFactor = m_currentDPI / m_wpfDPI; UpdateLayoutTransform(m_scaleFactor); DPIChanged(this, EventArgs::Empty); } void PerMonitorDPIWindow::UpdateLayoutTransform(double scaleFactor) { // Adjust the rendering graphics and text size by applying the scale transform to the top level visual node of the Window if (m_perMonitorEnabled) { auto child = GetVisualChild(0); if (m_scaleFactor != 1.0) { ScaleTransform^ dpiScale = gcnew ScaleTransform(scaleFactor, scaleFactor); child->SetValue(Window::LayoutTransformProperty, dpiScale); } else { child->SetValue(Window::LayoutTransformProperty, nullptr); } } }
Control del cambio de PPP para recursos como imágenes
Para actualizar el contenido gráfico, la aplicación WPF de ejemplo aplica una transformación de escala al nodo raíz de la aplicación WPF. Aunque esto funciona bien para el contenido representado de forma nativa por WPF (rectángulo, texto, etc.), esto implica que WPF escala los recursos de mapa de bits como imágenes.
Para evitar mapas de bits borrosos causados por el escalado, el desarrollador de aplicaciones WPF puede escribir un control de imagen de PPP personalizado que seleccione un recurso diferente basado en el PPP actual del monitor en el que se encuentra la ventana. El control de imagen puede basarse en el evento PPPChanged() desencadenado para la ventana de WPF que consume de PerMonitorDPIWindow, cuando cambia el PPP.
Nota
El control de imagen también debe seleccionar el control correcto durante el inicio de la aplicación en el controlador de eventos de ventana de WPF Loaded().