Làm cách nào để có được DPI trong WPF?Làm cách nào để có được DPI trong WPF?
Trả lời
http://blogs.msdn.com/jaimer/archive/2007/03/07/getting-system-dpi-in-wpf-app.aspx dường như làm việc
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;
}
Hãy nhớ rằng các đơn vị WPF không phải là pixel, chúng độc lập với thiết bị @ 96DPI "pixelish-units"; Vì vậy, thực sự những gì bạn muốn, là yếu tố quy mô giữa 96DPI và DPI hiện tại (vì vậy như 1,5 cho 144DPI) –
Vì vậy, đó không phải là những gì tôi cần sau đó :(Làm thế nào để có được các yếu tố quy mô? –
Tôi có nên sử dụng 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);
Phương thức này hoạt động ngay cả khi bạn không có tham chiếu đến một điều khiển nhưng nó sử dụng sự phản chiếu để nó có ưu và khuyết điểm của nó nhưng đối với tình huống của tôi, cái này tốt hơn vì tôi không có quyền kiểm soát. –
Phương pháp này có lợi thế là nó hoạt động trước khi sự kiện được tải của một cửa sổ. PresentationSource.FromVisual (myWindow) trả về null cho đến lúc đó. –
Làm việc như một sự quyến rũ. Tôi thích rằng không có giả định trong cách tiếp cận này, không giống như các phiên bản khác với 96 dpi. –
Cách duy nhất tôi tìm thấy để có được những "thực" màn dpi là như sau. Tất cả các kỹ thuật được đề cập khác chỉ nói 96 điều không đúng đối với hầu hết các màn hình.
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,
}
Dưới đây là một phương pháp dựa trên công nghệ Direct2D (hỗ trợ trên Windows Vista SP2 và cao hơn và server), vì vậy nó hoạt động tốt trong WPF (mà là dựa trên cơ sở giống nhau). Nó sử dụng số điện thoại 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
}
}
Với .NET 4.6.2 Xem trước và cao hơn, bạn có thể gọi VisualTreeHelper.GetDpi(Visual visual)
. Nó trả về cấu trúc DpiScale
, cho bạn biết DPI mà tại đó Visual
nhất định sẽ được hoặc đã được trả lại.
Tôi không thể gọi chức năng này, nó xuất hiện dưới dạng không xác định. Bạn có biết tại sao? Tôi đang làm điều này: 'VisualTreeHelper.GetDpi()' –
@AlexRosenfeld đảm bảo rằng bạn đang sử dụng không gian tên System.Windows.Media và phiên bản khung mục tiêu của bạn là 4.6.2 ít nhất.Bạn cũng cần truyền vào một đối tượng kiểu Visual cho api này. – rohit21agrawal
- 1. Làm thế nào để có được DPI trong C# .NET?
- 2. Làm cách nào để phát hiện dpi trên iPad mini?
- 3. Làm thế nào để có được màn hình DPI (linux, mac) theo chương trình?
- 4. Làm cách nào để tạo trang cơ sở trong WPF?
- 5. Làm thế nào để có được một đối tượng trên cùng (Window hoặc Page) trong WPF?
- 6. Làm thế nào để có được kích thước của màn hình hiện tại trong WPF?
- 7. Làm cách nào để có được BitmapImage từ Tài nguyên?
- 8. Làm cách nào để ẩn một hàng trong lưới WPF?
- 9. Làm cách nào để dừng hoạt ảnh trong C#/WPF?
- 10. Làm cách nào để tạo bộ hẹn giờ trong WPF?
- 11. Làm cách nào để sử dụng RelayCommand trong wpf?
- 12. Làm cách nào để thực hiện nút gửi trong WPF?
- 13. trong datagrid wpf làm thế nào để có được hàng trống trên đầu trang?
- 14. Trong WPF, làm thế nào để có được nền nút của chủ đề hiện tại?
- 15. Làm thế nào để Nhận DPI của hình ảnh trong C#
- 16. Làm cách nào để thêm lệnh được định tuyến tùy chỉnh trong WPF?
- 17. Cách tốt nhất để tạo drawables cho dpi khác nhau
- 18. WPF Làm thế nào để có được một UserControl để kế thừa một Button?
- 19. Làm thế nào tôi có thể nhận được các phông chữ sẵn có trong WPF
- 20. Làm thế nào để có được điều khiển trong WPF để điền vào không gian có sẵn?
- 21. Cách thiết kế hình ảnh trong java được in trên máy in 300 dpi
- 22. Làm cách nào để kiểm tra xem cuộn hiện có được hiển thị trong WPF DataGrid không?
- 23. Có cách nào để sử dụng DPI trong các truy vấn phương tiện css thay vì px
- 24. Làm cách nào để làm cho cột dữ liệu WPF không tập trung được?
- 25. Cách lấy dpi của ảnh (Java)
- 26. Làm cách nào để in trực tiếp, không có Hộp thoại In trong WPF?
- 27. Làm cách nào để biết một lần kéo/thả có bị hủy trong WPF
- 28. Làm cách nào để vẽ một đường trên canvas trong WPF có độ dày 1 pixel
- 29. Làm cách nào để chuyển đổi kích thước WPF thành pixel vật lý?
- 30. Làm thế nào để có được một cửa sổ của WPF ClientSize?
Tại sao bạn cần phải làm điều đó trong WPF, của tất cả mọi thứ, và bạn sẽ làm gì với giá trị khi bạn nhận được nó? WPF không có cách nào để chỉ định bất kỳ tọa độ nào trong pixel phụ thuộc vào thiết bị. Dường như kích thước của nó bằng pixel, nhưng đó là "pixel ảo" - kích thước của pixel là 96 pixel. Nó sẽ phát triển hoặc thu nhỏ nếu bạn thay đổi hệ thống DPI, do đó, một đường "dày một điểm ảnh" được vẽ bằng cách sử dụng WPF có thể không dày một pixel. –
Vì tôi muốn làm tròn pixel –
Nếu bạn muốn có vị trí chính xác pixel ở ranh giới pixel vật lý, bạn nên sử dụng WPF ngay từ đầu. Nó không phải là kịch bản mà nó được thiết kế, và hoàn toàn không có sự bảo đảm đối với cách các tọa độ WPF có thể được làm tròn vv. Nếu bạn chỉ muốn các đỉnh chụp tới các điểm vật lý gần nhất, sử dụng thuộc tính 'UseLayoutRounding'. Nếu bạn muốn vẽ một đường thẳng chính xác là 10 pixel vật lý, hãy quên đi WPF. –