La transformation d'un format connu de pixels de l'appareil
Si votre élément visuel est déjà attaché à un PresentationSource (par exemple, c'est une partie d'une fenêtre qui est visible sur l'écran), la transformation est trouvé de cette façon:
var source = PresentationSource.FromVisual(element);
Matrix transformToDevice = source.CompositionTarget.TransformToDevice;
Si non, utilisez HwndSource pour créer un temporaire hWnd:
Matrix transformToDevice;
using(var source = new HwndSource(new HwndSourceParameters()))
transformToDevice = source.TransformToDevice;
Notez que cette méthode est moins efficace que d'en construire à l'aide d'un hWnd de IntPtr.Zéro, mais je considère qu'il est plus fiable parce que le hWnd créé par HwndSource sera joint à la même dispositif d'affichage comme une réelle nouvellement créé à la Fenêtre. De cette façon, si différents dispositifs d'affichage ont différentes indicateur de performance, vous êtes sûr d'obtenir la bonne valeur des DPI.
Une fois que vous avez la transformation, vous pouvez convertir n'importe quelle taille de WPF taille à une taille de pixel:
var pixelSize = (Size)transformToDevice.Transform((Vector)wpfSize);
La conversion de la taille des pixels pour les entiers
Si vous voulez convertir la taille des pixels pour les entiers, vous pouvez tout simplement faire:
int pixelWidth = (int)pixelSize.Width;
int pixelHeight = (int)pixelSize.Height;
mais une solution plus robuste serait celui utilisé par ElementHost:
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));
L'obtention de la taille désirée de UIElement
Pour obtenir la taille souhaitée d'un UIElement vous devez vous assurer qu'elle est mesurée. Dans certaines circonstances, il sera déjà mesurée, soit parce que:
- Vous mesuré déjà
- Vous mesuré l'un de ses ancêtres, ou
- Il fait partie d'un PresentationSource (par exemple, il est dans une Fenêtre visible) et que vous êtes d'exécution ci-dessous DispatcherPriority.Le rendu de sorte que vous savez de mesure a déjà été fait automatiquement.
Si votre élément visuel n'a pas été mesurée encore, vous devriez téléphoner à Mesure sur le contrôle ou l'un de ses ancêtres, comme approprié, en passant dans la taille (ou new Size(double.PositivieInfinity, double.PositiveInfinity)
si vous voulez la taille au contenu:
element.Measure(availableSize);
Une fois que la mesure est effectuée, tout ce qui est nécessaire est d'utiliser la matrice de transformer le DesiredSize:
var pixelSize = (Size)transformToDevice.Transform((Vector)element.DesiredSize);
Mettre tous ensemble
Voici une méthode simple qui montre comment obtenir la taille en pixels d'un élément:
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);
}
Notez que dans ce code, je l'ai appeler Mesurer uniquement si aucun DesiredSize est présent. Cette fournit une méthode pratique pour tout faire, mais a plusieurs lacunes:
- Il se peut que l'élément parent aurait passé un petit availableSize
- Il est inefficace si la DesiredSize est zéro (c'est réévalué à plusieurs reprises)
- Il peut masquer des bugs dans une manière qui provoque l'échec de l'application en raison de inattendus de synchronisation (par exemple. le code appelé à ou au-dessus de DispatchPriority.Le rendu)
En raison de ces raisons, j'ai tendance à omettre la Mesure appel dans GetElementPixelSize et de laisser le client faire.