visual tutorial studio que hechas español ejemplos desde cero aprender aplicaciones wpf scaling dpi

tutorial - Deshabilitar el reconocimiento de DPI para la aplicación WPF



wpf vs windows forms (7)

¡Buen día!

He estado trabajando en una aplicación WPF desde hace algún tiempo (como experiencia de aprendizaje y, oh, chico, fue una experiencia de aprendizaje) y finalmente está listo para su lanzamiento. Liberar significa instalarlo en mi HTPC donde se usará para explorar mi colección de películas.

Lo diseñé en mi PC, que funciona con 1920 * 1080, pero con la configuración normal de DPI, mientras que el HTPC / TV se ejecuta con la misma resolución pero con una configuración de DPI más alta por razones obvias.

El problema es que mi aplicación se vuelve loca en el HTPC, arruinando casi todo en lo que respecta a lo visual. Sé que esto se debe al mal diseño (mea culpa), pero como es una aplicación que solo utilizará, estoy buscando una solución rápida, no un rediseño completo. Leí que sería posible evitar que la aplicación tenga conocimiento de DPI agregando lo siguiente a AssemblyInfo.cs:

[assembly: System.Windows.Media.DisableDpiAwareness]

Sin embargo, no parece tener ningún efecto y el comportamiento de la aplicación sigue siendo el mismo.

¿Podría alguien apuntarme en la dirección correcta?

Gracias johan


DPIAwareness

Solo algunas ideas (no probadas):

¿Estás ejecutando en XP? Esa opción podría no funcionar en esa plataforma.

Lo que sigue son probablemente solo formas diferentes de configurar la misma opción de DpiAwareness:

  • mire la configuración del "modo de compatibilidad" en su EXE ... haga clic con el botón derecho en sus propiedades ... y active "Deshabilitar la escala de pantalla"

  • Crea un manifiesto y di que no eres consciente.

    <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3" > ... <asmv3:application> <asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings"> <dpiAware>false</dpiAware> </asmv3:windowsSettings> </asmv3:application> ... </assembly>

  • llame a SetProcessDPIAware (piense que debe llamar antes, por ejemplo, antes de crear Windows)

    http://msdn.microsoft.com/en-gb/library/windows/desktop/ms633543(v=vs.85).aspx

Puede llamar a IsProcessDPIAware para verificar si el proceso de sus aplicaciones ha tenido la configuración aplicada o no.

Averiguar el DPI

Así es como averiguas qué DPI estás utilizando actualmente:

Acceda a CompositionTarget través del PresentationSource de su Window para averiguar qué escala de DPI está utilizando ... luego puede usar los valores para hacer algunos ajustes de escala, es decir, reducir su "cosas" (cuyos tamaños / longitud / etc se especifican en Dispositivo Unidades independientes), de modo que cuando se amplía debido a un mayor DPI en efecto, no explota el uso físico de píxeles (... esto se puede hacer de varias formas, por ejemplo, ViewBox , o cálculos de anchos, etc. en elementos) .

double dpiX, double dpiY; PresentationSource presentationsource = PresentationSource.FromVisual(mywindow); if (presentationsource != null) // make sure it''s connected { dpiX = 96.0 * presentationsource.CompositionTarget.TransformToDevice.M11; dpiY = 96.0 * presentationsource.CompositionTarget.TransformToDevice.M22; }

Hacer ajustes de escala

  • usar el truco de ViewBox

    Ver esta respuesta que hice antes, que permitía a un Canvas usar posiciones que fueron interpretadas como píxeles "nativos" sin importar la escala de DPI.

    WPF para pantalla LCD Full HD

  • acceda a la matriz de escalamiento TransFormToDevice en CompositionTarget , y a partir de eso calcule una nueva matriz que simplemente deshaga esa escala y LayoutTransform en LayoutTransform o RenderTransform .

  • use un método (tal vez incluso póngalo en un convertidor) que modifique una posición / longitud DIP (Posición independiente del dispositivo) de forma explícita ... puede hacerlo si desea que el tamaño de la ventana coincida con un tamaño de píxel particular.


La respuesta de Calin Pirtea realmente deshabilita la escala de DPI.

Para aquellos que quieren estirar la aplicación para una escala de visualización de más del 100% y aceptar borrosas, la respuesta de Carlos Borau funciona. Aquí hay una manera de .NET 4.6 (C #):

1 Agrega un archivo de manifiesto a tu proyecto de aplicación

  1. haga clic derecho en el proyecto, Agregar-> Nuevo elemento
  2. Elija General-> Archivo de manifiesto de aplicación

2 Descomente lo siguiente y configure dpiAware = falso:

<application xmlns="urn:schemas-microsoft-com:asm.v3"> <windowsSettings> <dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">false</dpiAware> </windowsSettings> </application>


Ninguno de los anteriores realmente deshabilita la escala de ppp en WPF.

Así es como WPF calcula la escala de ppp en .net 4.6: 1) HwndTarget, que es el CompositionTarget utilizado por todos los elementos visuales. 2) UIElement, que es la clase base para visuales y el lugar donde se almacenan los resultados del cálculo de escala de ppp.

WPF se asegura de que la escala global se calcula una vez que se prepara la primera imagen. Esto se controla mediante un valor booleano en HwndTarget {private static bool _setDpi = true}. Después de calcular los ppp, el campo _setDpi se establece en falso y los métodos que reconocen ppp son atajos usando un código como este {if (! HwndTarget._setDpi) return;}

Algo similar sucede con cada UIElement, que tiene el mismo patrón usando {private static bool _setDpi = true} para permitir el cálculo por primera vez.

La siguiente verificación proviene de ProcessDpiAwareness, que puede ser Ninguno, Proceso o Monitor. Para evitar que WPF considere monitores individuales, necesita establecer ProcessDpiAwareness en Process (int 1).

Finalmente, cuando se calcula el dpi, el resultado se almacena en 2 listas llamadas DpiScaleXValues ​​y DpiScaleYValues ​​en UIElement. Así que necesitas inicializarlos para corregir los valores.

Aquí hay un código de ejemplo que uso para mí (solo funciona para .net 4.6):

var setDpiHwnd = typeof(HwndTarget).GetField("_setDpi", BindingFlags.Static | BindingFlags.NonPublic); setDpiHwnd?.SetValue(null, false); var setProcessDpiAwareness = typeof(HwndTarget).GetProperty("ProcessDpiAwareness", BindingFlags.Static | BindingFlags.NonPublic); setProcessDpiAwareness?.SetValue(null, 1, null); var setDpi = typeof(UIElement).GetField("_setDpi", BindingFlags.Static | BindingFlags.NonPublic); setDpi?.SetValue(null, false); var setDpiXValues = (List<double>)typeof(UIElement).GetField("DpiScaleXValues", BindingFlags.Static | BindingFlags.NonPublic)?.GetValue(null); setDpiXValues?.Insert(0, 1); var setDpiYValues = (List<double>)typeof(UIElement).GetField("DpiScaleYValues", BindingFlags.Static | BindingFlags.NonPublic)?.GetValue(null); setDpiYValues?.Insert(0, 1);


Para aquellos que usan VB.NET, la forma de acceder al app.manifest es:

y luego descomente esta parte y ajústela a "falso"


Una solución rápida sería simplemente envolver el contenido de su ventana en un Viewbox . Si el elemento secundario inmediato de Viewbox tiene un Ancho y una Altura explícitos, y si la relación de aspecto es la misma en ambas máquinas, esto debería ponerlo en funcionamiento casi inmediatamente.


Este artículo de blog explica cómo usar una subclase de Decorator para hacer precisamente eso.

En resumen, crea una clase como esta:

namespace MyNamespace { public class DpiDecorator : Decorator { public DpiDecorator() { this.Loaded += (s, e) => { Matrix m = PresentationSource.FromVisual(this).CompositionTarget.TransformToDevice; ScaleTransform dpiTransform = new ScaleTransform(1 / m.M11, 1 / m.M22); if (dpiTransform.CanFreeze) dpiTransform.Freeze(); this.LayoutTransform = dpiTransform; }; } }; };

Luego agregue algo como xmlns:custom="clr-namespace:MyNamespace" a su definición de ventana de nivel superior, luego incluya su interfaz de usuario independiente de DPI con <custom:DpiDecorator> ... </custom:DpiDecorator> .


DpiAwareness solo afecta a la virtualización de DPI. En Windows, aparece como "Usar la escala de estilo de Windows XP" en el cuadro de resolución personalizada de Windows 7 y 8, donde marcado significa inhabilitado y no marcado significa habilitado. (¡Recuerda aplicar en la pantalla de tamaño de fuente principal si la cambias! Aceptar el cuadro no es suficiente).

Si tiene desactivada la virtualización de DPI, entonces no hace ninguna diferencia lo que su aplicación le dice al sistema operativo que admite, siempre utilizará la escala estándar. Cuando está activado, marca la diferencia entre la escala real (consciente) y la simple aplicación de un cambio de tamaño bilineal en toda la aplicación (sin darse cuenta).

Acabo de recordar otra advertencia, DPI virt no funcionará en absoluto sin que funcione Aero Glass.