¿Cómo puedo obtener el DPI en WPF?¿Cómo puedo obtener el DPI en WPF?
Respuesta
http://blogs.msdn.com/jaimer/archive/2007/03/07/getting-system-dpi-in-wpf-app.aspx parece funcionar
PresentationSource source = PresentationSource.FromVisual(this);
double dpiX, dpiY;
if (source != null) {
dpiX = 96.0 * source.CompositionTarget.TransformToDevice.M11;
dpiY = 96.0 * source.CompositionTarget.TransformToDevice.M22;
}
Tenga en cuenta, sin embargo, que las unidades WPF no son píxeles, sino unidades de píxeles independientes de 96DPI del dispositivo; entonces realmente lo que quieres es el factor de escala entre 96DPI y el DPI actual (así que como 1.5 para 144DPI) –
Entonces eso no es lo que necesito entonces :(¿Cómo obtengo el factor de escala? –
¿Debo usar GetDeviceCaps (.., LOGPIXELSX)? –
var dpiXProperty = typeof(SystemParameters).GetProperty("DpiX", BindingFlags.NonPublic | BindingFlags.Static);
var dpiYProperty = typeof(SystemParameters).GetProperty("Dpi", BindingFlags.NonPublic | BindingFlags.Static);
var dpiX = (int)dpiXProperty.GetValue(null, null);
var dpiY = (int)dpiYProperty.GetValue(null, null);
Este método funciona incluso cuando no tiene una referencia un control pero sí usa el reflejo así que tiene sus pros y sus contras, pero para mi situación este fue mejor ya que no tuve acceso a un control. –
Este método tiene la ventaja de que funciona antes del evento cargado de una ventana. PresentationSource.FromVisual (myWindow) devuelve null hasta entonces. –
Funciona como un encanto. Me gusta que no haya suposiciones en este enfoque, a diferencia de otras versiones con 96 ppp. –
La única manera que encontré para obtener el "verdadero" monitor de dpi es la siguiente. Todas las demás técnicas mencionadas solo dicen 96, lo que no es correcto para la mayoría de los monitores.
public class ScreenInformations
{
public static uint RawDpi { get; private set; }
static ScreenInformations()
{
uint dpiX;
uint dpiY;
GetDpi(DpiType.RAW, out dpiX, out dpiY);
RawDpi = dpiX;
}
/// <summary>
/// Returns the scaling of the given screen.
/// </summary>
/// <param name="dpiType">The type of dpi that should be given back..</param>
/// <param name="dpiX">Gives the horizontal scaling back (in dpi).</param>
/// <param name="dpiY">Gives the vertical scaling back (in dpi).</param>
private static void GetDpi(DpiType dpiType, out uint dpiX, out uint dpiY)
{
var point = new System.Drawing.Point(1, 1);
var hmonitor = MonitorFromPoint(point, _MONITOR_DEFAULTTONEAREST);
switch (GetDpiForMonitor(hmonitor, dpiType, out dpiX, out dpiY).ToInt32())
{
case _S_OK: return;
case _E_INVALIDARG:
throw new ArgumentException("Unknown error. See https://msdn.microsoft.com/en-us/library/windows/desktop/dn280510.aspx for more information.");
default:
throw new COMException("Unknown error. See https://msdn.microsoft.com/en-us/library/windows/desktop/dn280510.aspx for more information.");
}
}
//https://msdn.microsoft.com/en-us/library/windows/desktop/dd145062.aspx
[DllImport("User32.dll")]
private static extern IntPtr MonitorFromPoint([In]System.Drawing.Point pt, [In]uint dwFlags);
//https://msdn.microsoft.com/en-us/library/windows/desktop/dn280510.aspx
[DllImport("Shcore.dll")]
private static extern IntPtr GetDpiForMonitor([In]IntPtr hmonitor, [In]DpiType dpiType, [Out]out uint dpiX, [Out]out uint dpiY);
const int _S_OK = 0;
const int _MONITOR_DEFAULTTONEAREST = 2;
const int _E_INVALIDARG = -2147024809;
}
/// <summary>
/// Represents the different types of scaling.
/// </summary>
/// <seealso cref="https://msdn.microsoft.com/en-us/library/windows/desktop/dn280511.aspx"/>
public enum DpiType
{
EFFECTIVE = 0,
ANGULAR = 1,
RAW = 2,
}
Aquí es un método que se basa en la tecnología Direct2D (compatible con Windows Vista con SP2 y superior y servidores), por lo que funciona bien en WPF (que se basa en los mismos motivos). Utiliza el ID2D1Factory::GetDesktopDpi method
public static class DpiUtilities
{
private static Lazy<Tuple<float, float>> _dpi = new Lazy<Tuple<float, float>>(ReadDpi);
public static float DesktopDpiX
{
get
{
return _dpi.Value.Item1;
}
}
public static float DesktopDpiY
{
get
{
return _dpi.Value.Item2;
}
}
public static void Reload()
{
ID2D1Factory factory;
int hr = D2D1CreateFactory(D2D1_FACTORY_TYPE.D2D1_FACTORY_TYPE_SINGLE_THREADED, typeof(ID2D1Factory).GUID, IntPtr.Zero, out factory);
if (hr != 0)
Marshal.ThrowExceptionForHR(hr);
factory.ReloadSystemMetrics();
Marshal.ReleaseComObject(factory);
}
private static Tuple<float, float> ReadDpi()
{
ID2D1Factory factory;
int hr = D2D1CreateFactory(D2D1_FACTORY_TYPE.D2D1_FACTORY_TYPE_SINGLE_THREADED, typeof(ID2D1Factory).GUID, IntPtr.Zero, out factory);
if (hr != 0)
Marshal.ThrowExceptionForHR(hr);
float x;
float y;
factory.GetDesktopDpi(out x, out y);
Marshal.ReleaseComObject(factory);
return new Tuple<float, float>(x, y);
}
[DllImport("d2d1.dll")]
private static extern int D2D1CreateFactory(D2D1_FACTORY_TYPE factoryType, [MarshalAs(UnmanagedType.LPStruct)] Guid riid, IntPtr pFactoryOptions, out ID2D1Factory ppIFactory);
private enum D2D1_FACTORY_TYPE
{
D2D1_FACTORY_TYPE_SINGLE_THREADED = 0,
D2D1_FACTORY_TYPE_MULTI_THREADED = 1,
}
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[Guid("06152247-6f50-465a-9245-118bfd3b6007")]
private interface ID2D1Factory
{
int ReloadSystemMetrics();
[PreserveSig]
void GetDesktopDpi(out float dpiX, out float dpiY);
// the rest is not implemented as we don't need it
}
}
Con .NET 4.6.2 Vista previa y superior, puede llamar VisualTreeHelper.GetDpi(Visual visual)
. Devuelve una estructura DpiScale
, que le indica el DPI en el que se proporcionará 0 se ha renderizado el Visual
dado.
No puedo llamar a esta función, aparece como indefinido. ¿Sabes por qué? Estoy haciendo esto: 'VisualTreeHelper.GetDpi()' –
@AlexRosenfeld asegúrate de que estás usando el espacio de nombres System.Windows.Media, y tu versión de framework objetivo es 4.6.2 atleast.También debe pasar un objeto de tipo Visual a esta api. – rohit21agrawal
- 1. ¿Cómo obtener DPI en C# .NET?
- 2. ¿Cómo obtener la pantalla DPI en Java?
- 3. Cómo puedo obtener Fuentes disponibles en WPF
- 4. Cómo obtener DPI de la imagen en C#
- 5. ¿Cómo obtener la pantalla DPI (linux, mac) programáticamente?
- 6. cómo puedo obtener el padre del control de usuario wpf
- 7. Cómo detectar el DPI pantalla utilizando JavaScript
- 8. ¿Cómo puedo obtener un borde discontinuo o punteado en WPF?
- 9. Cómo obtener ComboBox.SelectedText en WPF
- 10. Falta el título en la ventana de herramienta de WPF cuando la configuración DPI 125-150%
- 11. Cómo obtener el elemento bajo el cursor en WPF ListView
- 12. ¿Cómo obtener controles en WPF para llenar el espacio disponible?
- 13. ¿Cómo puedo obtener el delegado?
- 14. ¿Puedo obtener enlaces fuertemente tipados en WPF/XAML?
- 15. Dado un WPF DependencyObject con estilo, ¿cómo puedo obtener la clave de estilo en el código?
- 16. Windows GDI: horizontal/vertical DPI
- 17. Cómo obtener El punto medio de un ArcSegment en WPF
- 18. ¿Cómo detectar "correctamente" el DPI de la pantalla con Java?
- 19. Ayuda de ImageMagick: necesito cambiar DPI
- 20. C# winforms: ¿Cómo cambiar DPI del System.Drawing.BItmap?
- 21. Cómo obtener el ancho real de un WPF Popup
- 22. getheight() px o dpi?
- 23. Cómo comprobar Foto DPI con PHP
- 24. Obtener el objeto por su Uid en WPF
- 25. ¿Cómo puedo usar RelayCommand en wpf?
- 26. ¿Cómo establecer la información de DPI en una imagen?
- 27. Cómo puedo asignar el Caret a un control en WPF
- 28. ¿Cómo puedo suspender y reanudar el diseño en WPF?
- 29. Cómo obtener el nivel de celda ComboBox para WPF DataGrid?
- 30. Cómo puedo solicitar grupos en WPF
¿Por qué tendrías que hacerlo en WPF, de todas las cosas, y qué vas a hacer con el valor una vez que lo obtienes? WPF no tiene forma de especificar ninguna de las coordenadas en los píxeles dependientes del dispositivo. Puede parecer que sus tamaños están en píxeles, pero esos son "píxeles virtuales", el tamaño de un píxel, ya que es de 96 DPI. Crecerá o disminuirá si cambia el DPI del sistema, por lo que una línea de "un píxel de espesor" dibujada con WPF puede no tener un grosor de un píxel. –
Porque quiero redondear los píxeles –
Si desea una ubicación precisa de píxeles en los límites de píxeles físicos, es mejor que no utilice WPF en primer lugar. No es el escenario para el que está diseñado, y no hay absolutamente ninguna garantía con respecto a cómo se pueden redondear las coordenadas WPF, etc. Si solo desea que los vértices se ajusten a los píxeles físicos más cercanos, use la propiedad 'UseLayoutRounding'. Si desea dibujar una línea que tiene exactamente 10 píxeles físicos de largo, entonces olvídese de WPF. –