Umwandlung einer bekannten Größe in Gerätepixel
Wenn Ihr visuelles Element bereits mit einer PresentationSource verbunden ist (z. B. Teil eines Fensters, das auf dem Bildschirm sichtbar ist), wird die Transformation auf diese Weise gefunden:
var source = PresentationSource.FromVisual(element);
Matrix transformToDevice = source.CompositionTarget.TransformToDevice;
Falls nicht, verwenden Sie HwndSource, um ein temporäres hWnd zu erstellen:
Matrix transformToDevice;
using(var source = new HwndSource(new HwndSourceParameters()))
transformToDevice = source.CompositionTarget.TransformToDevice;
Beachten Sie, dass dies weniger effizient ist als die Konstruktion mit einem hWnd von IntPtr.Zero, aber ich halte es für zuverlässiger, weil das hWnd, das von HwndSource erstellt wird, an dasselbe Anzeigegerät angehängt wird wie ein tatsächlich neu erstelltes Fenster. Wenn verschiedene Anzeigegeräte unterschiedliche DPI-Werte haben, können Sie auf diese Weise sicher sein, dass Sie den richtigen DPI-Wert erhalten.
Sobald Sie die Transformation haben, können Sie jede Größe von einer WPF-Größe in eine Pixelgröße umwandeln:
var pixelSize = (Size)transformToDevice.Transform((Vector)wpfSize);
Umwandlung der Pixelgröße in Ganzzahlen
Wenn Sie die Pixelgröße in ganze Zahlen umwandeln möchten, können Sie dies einfach tun:
int pixelWidth = (int)pixelSize.Width;
int pixelHeight = (int)pixelSize.Height;
aber eine robustere Lösung wäre die von ElementHost verwendete:
int pixelWidth = (int)Math.Max(int.MinValue, Math.Min(int.MaxValue, pixelSize.Width));
int pixelHeight = (int)Math.Max(int.MinValue, Math.Min(int.MaxValue, pixelSize.Height));
Ermitteln der gewünschten Größe eines UIElements
Um die gewünschte Größe eines UIElements zu erhalten, müssen Sie sicherstellen, dass es gemessen wird. In einigen Fällen wird es bereits gemessen, entweder weil:
- Sie haben es bereits gemessen
- Sie haben einen seiner Vorfahren gemessen, oder
- Sie ist Teil einer PresentationSource (z. B. in einem sichtbaren Fenster) und wird unter DispatcherPriority.Render ausgeführt, so dass Sie wissen, dass die Messung bereits automatisch erfolgt ist.
Wenn Ihr visuelles Element noch nicht vermessen wurde, sollten Sie Measure für das Steuerelement oder einen seiner Vorfahren aufrufen und die verfügbare Größe (oder new Size(double.PositivieInfinity, double.PositiveInfinity)
wenn Sie die Größe an den Inhalt anpassen wollen:
element.Measure(availableSize);
Sobald die Messung abgeschlossen ist, muss die Matrix nur noch zur Transformation von DesiredSize verwendet werden:
var pixelSize = (Size)transformToDevice.Transform((Vector)element.DesiredSize);
Alles zusammenfügen
Hier ist eine einfache Methode, die zeigt, wie man die Pixelgröße eines Elements ermitteln kann:
public Size GetElementPixelSize(UIElement element)
{
Matrix transformToDevice;
var source = PresentationSource.FromVisual(element);
if(source!=null)
transformToDevice = source.CompositionTarget.TransformToDevice;
else
using(var source = new HwndSource(new HwndSourceParameters()))
transformToDevice = source.CompositionTarget.TransformToDevice;
if(element.DesiredSize == new Size())
element.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
return (Size)transformToDevice.Transform((Vector)element.DesiredSize);
}
Beachten Sie, dass ich in diesem Code Measure nur aufrufe, wenn keine DesiredSize vorhanden ist. Dies ist eine bequeme Methode, um alles zu tun, hat aber mehrere Mängel:
- Es kann sein, dass das übergeordnete Element eine kleinere availableSize übergeben hätte
- Es ist ineffizient, wenn die tatsächliche DesiredSize gleich Null ist (sie wird wiederholt neu gemessen)
- Es können Fehler maskiert werden, die dazu führen, dass die Anwendung aufgrund eines unerwarteten Timings fehlschlägt (z. B. weil der Code bei oder über DispatchPriority.Render aufgerufen wird).
Aus diesen Gründen wäre ich geneigt, den Measure-Aufruf in GetElementPixelSize wegzulassen und dies einfach dem Client zu überlassen.