Come posso ottenere DPI in WPF?Come posso ottenere DPI in WPF?
risposta
http://blogs.msdn.com/jaimer/archive/2007/03/07/getting-system-dpi-in-wpf-app.aspx sembra funzionare
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;
}
Tenete a mente che le unità WPF non sono pixel, ma sono "unità pixelish" indipendenti dal dispositivo @ 96DPI; così davvero quello che vuoi, è il fattore di scala tra 96 DPI e il DPI corrente (quindi come 1.5 per 144 DPI) –
Quindi non è quello che mi serve allora :(Come ottengo il fattore di scala? –
Devo usare 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);
Questo metodo funziona anche quando non si ha un riferimento a un controllo ma usa la riflessione quindi ha i suoi pro e contro, ma per la mia situazione questo era migliore dato che non avevo accesso a un controllo. –
Questo metodo ha il vantaggio che funziona prima dell'evento Loaded di una finestra. PresentationSource.FromVisual (myWindow) restituisce null fino ad allora. –
Funziona come un fascino. Mi piace il fatto che non ci siano ipotesi in questo approccio, a differenza di altre versioni con 96 dpi. –
L'unico modo che ho trovato per ottenere il "vero" dpi monitor è il seguente. Tutte le altre tecniche citate dicono semplicemente 96, che non è corretto per la maggior parte dei monitor.
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,
}
Qui è un metodo che si basa sulla tecnologia Direct2D (supportato su Windows Vista con SP2 e server), in modo che funziona bene in WPF (che si basa sugli stessi motivi). Esso utilizza il 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 Preview e superiori, è possibile chiamare VisualTreeHelper.GetDpi(Visual visual)
. Restituisce una struttura DpiScale
, che indica il DPI a cui il dato Visual
sarà o è stato reso.
Non riesco a chiamare questa funzione, appare come non definita. Sai perché? Sto facendo questo: 'VisualTreeHelper.GetDpi()' –
@AlexRosenfeld assicurati di utilizzare lo spazio dei nomi System.Windows.Media, e la tua versione del framework di destinazione è 4.6.2 atleast.È inoltre necessario passare un oggetto di tipo Visual a questa API. – rohit21agrawal
- 1. Come ottenere il DPI della stampante in WPF
- 2. Come ottenere DPI di immagine in C#
- 3. Come ottenere lo schermo DPI in java?
- 4. Un'applicazione WPF ignora le impostazioni DPI
- 5. Come ottenere il dpi di un'immagine (Java)
- 6. Come ottenere la scala DPI per tutti gli schermi?
- 7. Come ottenere DPI dello schermo (linux, mac) in modo programmato?
- 8. Come posso rilevare il dpi su un ipad mini?
- 9. Come ottenere ComboBox.SelectedText in WPF
- 10. come ottenere il doppio clic in WPF
- 11. come posso modificare la dpi di un'immagine con l'estensione imagick
- 12. Come ottenere l'effetto ombreggiatura inserto in WPF
- 13. come posso ottenere il genitore del controllo utente wpf
- 14. Posso usare NotifyIcon in WPF?
- 15. Ottenere l'URL in WPF WebBrowser
- 16. Come posso utilizzare RelayCommand in wpf?
- 17. come posso convertire un'applicazione wpf in exe
- 18. in datagid wpf come ottenere la riga vuota in cima?
- 19. Applicazione Windows - Problemi DPI
- 20. problemi DPI elevati
- 21. MySQL Workbench High DPI
- 22. Cambia "Dimensione carattere Windows (DPI)" in PowerShell?
- 23. getheight() px o dpi?
- 24. Posso impostare la risoluzione DPI della mia applicazione Java Swing senza modificare le impostazioni DPI del sistema?
- 25. Come posso elencare i colori in WPF con XAML?
- 26. Winforms C#: come modificare DPI di System.Drawing.BItmap?
- 27. Ottenere tag dell'elemento selezionato in WPF ComboBox
- 28. Dato un DependencyObject WPF in stile, come posso ottenere lo Style Key nel codice?
- 29. Come posso ottenere modelli WPF e Windows Phone in Expression Blend 2013?
- 30. Come posso ottenere le coordinate dello schermo del mouse in WPF?
Perché dovresti aver bisogno di farlo in WPF, di tutte le cose, e cosa hai intenzione di fare con il valore una volta ottenuto? WPF non ha modo di specificare alcuna coordinata in pixel dipendenti dalla periferica. Potrebbe sembrare che le sue dimensioni siano espresse in pixel, ma quelle sono "pixel virtuali": la dimensione di un pixel come è a 96 DPI. Crescerà o ridurrà se cambi il DPI del sistema, quindi una linea "spessa un pixel" disegnata usando WPF potrebbe non essere fisicamente spessa un pixel. –
Perché voglio arrotondare i pixel –
Se si desidera posizionare con precisione i pixel ai limiti dei pixel fisici, è molto meglio non utilizzare WPF in primo luogo. Non è lo scenario per il quale è stato progettato e non ci sono assolutamente garanzie riguardo a come le coordinate WPF possono essere arrotondate ecc. Se si desidera che i vertici si agganciano ai pixel fisici più vicini, utilizzare la proprietà 'UseLayoutRounding'. Se vuoi disegnare una linea che è lunga esattamente 10 pixel fisici, allora dimentica WPF. –