Remarque
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de modifier des répertoires.
Un nombre croissant d’appareils sont expédiés avec des écrans « haute résolution ». Ces écrans ont généralement plus de 200 pixels par pouce (ppp). L’utilisation d’une application sur ces ordinateurs nécessite que le contenu soit mis à l’échelle pour répondre aux besoins de l’affichage du contenu à une distance normale pour l’appareil. À compter de 2014, la cible principale pour les écrans à haute densité est l’informatique mobile (tablettes, ordinateurs portables palourdes et téléphones).
Windows 8.1 et versions ultérieures contient plusieurs fonctionnalités pour permettre à ces ordinateurs d’utiliser des affichages et des environnements où l’ordinateur est attaché à des affichages à haute densité et à densité standard en même temps.
Windows peut vous permettre de mettre à l’échelle le contenu sur l’appareil à l’aide du paramètre « Rendre le texte et d’autres éléments plus volumineux ou plus petits » (disponible depuis Windows XP).
Windows 8.1 et versions ultérieures met automatiquement à l’échelle le contenu pour que la plupart des applications soient cohérentes lorsqu’elles sont déplacées entre les affichages de densités de pixels différentes. Lorsque l’affichage principal est à haute densité (200% mise à l’échelle) et que l’affichage secondaire est de densité standard (100%), Windows met automatiquement à l’échelle le contenu de la fenêtre d’application sur l’affichage secondaire (1 pixel affiché pour chaque 4 pixels affichés par l’application).
Windows effectue par défaut la mise à l’échelle appropriée pour la densité de pixels et la distance d’affichage de l’affichage (Windows 7 et versions ultérieures, configurables par OEM).
Windows peut mettre automatiquement à l’échelle le contenu jusqu’à 250% sur de nouveaux appareils qui dépassent 280 ppp (à partir de Windows 8.1 S14).
Windows dispose d’un moyen de faire évoluer l’interface utilisateur pour tirer parti d’un nombre accru de pixels. Une application adhère à ce système en se déclarant comme étant « compatible avec le DPI du système ». Les applications qui ne le font pas sont mises à l’échelle par le système. Cela peut entraîner une expérience utilisateur « floue » où l’ensemble de l’application est uniformément étiré de façon pixelisée. Par exemple:
Visual Studio est configuré pour prendre en charge la mise à l’échelle DPI et n'est par conséquent pas en mode de virtualisation.
Windows (et Visual Studio) tirent parti de plusieurs technologies d’interface utilisateur, qui ont différentes façons de traiter les facteurs de mise à l’échelle définis par le système. Par exemple:
WPF mesure les contrôles de manière indépendante de l’appareil (unités, et non pixels). L'interface utilisateur WPF s'adapte automatiquement au DPI actuel.
Toutes les tailles de texte, quel que soit le cadre de l'interface utilisateur, sont exprimées en points et sont donc traitées par le système comme indépendantes des PPP. Le texte dans Win32, WinForms et WPF est déjà mis à l’échelle correctement lorsqu’il est dessiné sur l’appareil d’affichage.
Les dialogues win32/WinForms et les fenêtres ont des moyens d’activer la disposition qui se redimensionne avec du texte (par exemple, via des panneaux de grille, de flux et de disposition de tableau). Elles permettent d’éviter les emplacements de pixels codés en dur qui ne sont pas mis à l’échelle lorsque les tailles de police sont augmentées.
Les icônes fournies par le système ou les ressources en fonction des métriques système (par exemple, SM_CXICON et SM_CXSMICON) sont déjà mises à l’échelle.
Ancienne interface utilisateur Win32 (GDI, GDI+) et WinForms
Bien que WPF soit déjà très sensible aux PPP, une grande partie de notre code Win32/GDI n’a pas été écrite à l’origine avec la prise en compte des PPP. Windows a mis à disposition des API pour la mise à l’échelle DPI. Les correctifs apportés aux problèmes Win32 doivent les utiliser de manière cohérente sur le produit. Visual Studio a fourni une bibliothèque de classes d’assistance pour éviter la duplication des fonctionnalités et garantir la cohérence entre le produit.
Images haute résolution
Cette section concerne principalement les développeurs qui étendent Visual Studio 2013. Pour Visual Studio 2015, utilisez le service d’images intégré à Visual Studio. Vous pouvez également constater que vous devez prendre en charge/cibler de nombreuses versions de Visual Studio et, par conséquent, l’utilisation du service d’images en 2015 n’est pas une option, car elle n’existe pas dans les versions précédentes. Cette section est également destinée à vous.
Agrandissement des images trop petites
Les images trop petites peuvent être mises à l’échelle et rendues sur GDI et WPF à l’aide de méthodes courantes. Les classes d’assistance DPI managées sont disponibles pour les intégrateurs Visual Studio internes et externes pour traiter les icônes de mise à l’échelle, les bitmaps, les imagestrips et les listes d’images. Les helpers natifs Win32 C/C++sont disponibles pour la mise à l’échelle de HICON, HBITMAP, HIMAGELIST et VsUI ::GdiplusImage. La mise à l’échelle d’une bitmap nécessite généralement une modification d’une ligne après avoir inclus une référence à la bibliothèque d’assistance. Par exemple:
La mise à l’échelle d'une liste d'images dépend de si la liste d'images est complète au moment du chargement ou est complétée au moment de l'exécution. Si tout est prêt au moment du chargement, appelez LogicalToDeviceUnits() avec la liste d'images comme pour une bitmap. Lorsque le code doit charger une image bitmap individuelle avant de composer la liste d’images, veillez à mettre à l’échelle la taille de l’image de la liste d’images :
imagelist.ImageSize = DpiHelper.LogicalToDeviceUnits(imagelist.ImageSize);
Dans le code natif, les dimensions peuvent être mises à l’échelle lors de la création de la liste d’images comme suit :
ImageList_Create(VsUI::DpiHelper::LogicalToDeviceUnitsX(16),VsUI::DpiHelper::LogicalToDeviceUnitsY(16), ILC_COLOR32|ILC_MASK, nCount, 1);
Les fonctions de la bibliothèque permettent de spécifier l’algorithme de redimensionnement. Lors de la mise à l’échelle d’images à placer dans des listes d’images, veillez à spécifier la couleur d’arrière-plan utilisée pour la transparence, ou utilisez la mise à l’échelle NearestNeighbor (ce qui entraînera des distorsions à 125% et 150%).
Consultez la DpiHelper documentation sur MSDN.
Le tableau suivant montre des exemples de mise à l’échelle des images à des facteurs de mise à l’échelle DPI correspondants. Les images décrites en orange indiquent notre meilleure pratique à partir de Visual Studio 2013 (100%-200% mise à l’échelle DPI) :
Problèmes de disposition
Les problèmes courants de disposition peuvent être évités principalement en conservant les points de l’interface utilisateur mis à l’échelle et par rapport à l’autre plutôt qu’en utilisant des emplacements absolus (en unités de pixels). Par exemple:
Les positions de disposition/texte doivent être ajustées pour prendre en compte les images mises à l’échelle.
Les colonnes dans les grilles doivent avoir des largeurs ajustées pour le texte mis à l’échelle.
Les tailles codées en dur ou l’espace entre les éléments doivent également être agrandis. Les tailles basées uniquement sur les dimensions de texte sont généralement correctes, car les polices sont automatiquement mises à l’échelle.
Les fonctions d’assistance sont disponibles dans la classe pour permettre la mise à l’échelle DpiHelper sur l’axe X et Y :
LogicalToDeviceUnitsX/LogicalToDeviceUnitsY (les fonctions permettent la mise à l’échelle sur l’axe X/Y)
int space = DpiHelper.LogicalToDeviceUnitsX (10) ;
int height = VsUI::DpiHelper::LogicalToDeviceUnitsY(5);
Il existe des surcharges LogicalToDeviceUnits pour permettre la mise à l’échelle d’objets tels que Rect, Point et Size.
Utilisation de la bibliothèque/classe DPIHelper pour mettre à l’échelle les images et la disposition
La bibliothèque d’assistance DPI Visual Studio est disponible dans des formulaires natifs et managés et peut être utilisée en dehors de l’interpréteur de commandes Visual Studio par d’autres applications.
Pour utiliser la bibliothèque, accédez aux exemples d’extensibilité VSSDK Visual Studio et clonez l’exemple High-DPI_Images_Icons.
Dans les fichiers sources, incluez VsUIDpiHelper.h et appelez les fonctions statiques de VsUI::DpiHelper la classe :
#include "VsUIDpiHelper.h"
int cxScaled = VsUI::DpiHelper::LogicalToDeviceUnitsX(cx);
VsUI::DpiHelper::LogicalToDeviceUnits(&hBitmap);
Note
N’utilisez pas les fonctions d’assistance dans les variables statiques au niveau du module ou au niveau de la classe. La bibliothèque utilise également des statiques pour la synchronisation de threads et vous pouvez rencontrer des problèmes d’initialisation par ordre. Convertissez ces variables statiques en variables membres non statiques, ou encapsulez-les dans une fonction pour qu'elles soient construites lors du premier accès.
Pour accéder aux fonctions d’assistance DPI à partir du code managé qui s’exécute dans l’environnement Visual Studio :
Le projet consommateur doit référencer la dernière version de Shell MPF. Par exemple:
<Reference Include="Microsoft.VisualStudio.Shell.14.0.dll" />Vérifiez que le projet a des références à System.Windows.Forms, PresentationCore et PresentationUI.
Dans le code, utilisez l’espace de noms Microsoft.VisualStudio.PlatformUI et appelez des fonctions statiques de la classe DpiHelper. Pour les types pris en charge (points, tailles, rectangles, et ainsi de suite), il existe des fonctions d’extension fournies qui retournent de nouveaux objets mis à l’échelle. Par exemple:
using Microsoft.VisualStudio.PlatformUI; double x = DpiHelper.LogicalToDeviceUnitsX(posX); Point ptScaled = ptOriginal.LogicalToDeviceUnits(); DpiHelper.LogicalToDeviceUnits(ref bitmap);
Gestion du flou de l'image WPF dans l'interface utilisateur zoomable
Dans WPF, les bitmaps sont redimensionnés automatiquement par WPF pour le niveau de zoom PPP actuel à l’aide d’un algorithme bicubique de haute qualité (valeur par défaut), qui fonctionne bien pour les images ou les grandes captures d’écran, mais il est inapproprié pour les icônes d’élément de menu, car il introduit un flou perçu.
Recommandations :
Pour les illustrations d’image de logo et de bannières, le mode de redimensionnement par défaut BitmapScalingMode peut être utilisé.
Pour les éléments de menu et les images d’iconographie, BitmapScalingMode doit être utilisé lorsqu’il n’entraîne pas d’autres artefacts de distorsion afin d’éliminer le flou (à 200 % et 300 %).
Pour les niveaux de zoom volumineux qui ne sont pas des multiples de 100 % (par exemple, 250 % ou 350 %), la mise à l’échelle d’images iconographiques avec le redimensionnement bicubique aboutit à une interface utilisateur floue et délavée. Un meilleur résultat est obtenu en mettant d’abord à l’échelle l’image avec NearestNeighbor vers le plus grand multiple de 100 % (par exemple, 200 % ou 300 %), puis en continuant le redimensionnement avec la méthode bicubic. Pour plus d'informations, consultez le cas spécial : préadapter les images WPF pour les niveaux de PPP élevés.
La classe DpiHelper dans l’espace de noms Microsoft.VisualStudio.PlatformUI fournit un membre BitmapScalingMode qui peut être utilisé pour la liaison. Il permet au shell Visual Studio de contrôler le mode de mise à l’échelle bitmap de manière uniforme dans l'ensemble du produit, en fonction du facteur de mise à l’échelle DPI.
Pour l’utiliser en XAML, ajoutez :
xmlns:vsui="clr-namespace:Microsoft.VisualStudio.PlatformUI;assembly=Microsoft.VisualStudio.Shell.14.0"
<Setter Property="RenderOptions.BitmapScalingMode" Value="{x:Static vs:DpiHelper.BitmapScalingMode}" />
L’interpréteur de commandes Visual Studio définit déjà cette propriété sur les fenêtres et les dialogues de niveau supérieur. L’interface utilisateur basée sur WPF exécutée dans Visual Studio l’héritera déjà. Si le paramètre ne se propage pas à vos éléments d’interface utilisateur particuliers, il peut être défini sur l’élément racine de l’interface utilisateur XAML/WPF. Les emplacements où cela se produit incluent des fenêtres contextuelles, sur des éléments avec des parents Win32 et des fenêtres de concepteur qui s’exécutent hors processus, telles que Blend.
Certaines interfaces utilisateur peuvent être mises à l’échelle indépendamment du niveau de zoom DPI défini par le système, comme l'éditeur de texte Visual Studio et les concepteurs basés sur WPF (Bureau WPF et Windows Store). Dans ces cas, DpiHelper.BitmapScalingMode ne doit pas être utilisé. Pour résoudre ce problème dans l’éditeur, l’équipe IDE a créé une propriété personnalisée intitulée RenderOptions.BitmapScalingMode. Définissez cette valeur de propriété sur HighQuality ou NearestNeighbor en fonction du niveau de zoom combiné du système et de votre interface utilisateur.
Cas spécial : pré-redimensionnement d’images WPF pour les niveaux de PPP élevés
Pour des niveaux de zoom très élevés qui ne sont pas multiples de 100 % (par exemple, 250 %, 350 %, etc.), l'utilisation de la mise à l'échelle bicubique pour les images iconographiques entraîne une interface utilisateur floue et délavée. L’impression de ces images avec du texte croustillant est presque comme celle d’une illusion optique. Les images semblent être plus proches de l’œil et hors focus par rapport au texte. Le résultat de la mise à l'échelle à cette taille agrandie peut être amélioré en mettant d'abord à l'échelle l'image avec la méthode NearestNeighbor jusqu'au plus grand multiple de 100 % (par exemple, 200 % ou 300 %) et en utilisant la méthode bicubique pour la mise à l'échelle supplémentaire de 50 %.
Voici un exemple des différences dans les résultats, où la première image est mise à l’échelle avec l’algorithme de double mise à l’échelle amélioré 100%->200%->250%, et le deuxième juste avec bicubic 100%->250%.
Pour permettre à l’interface utilisateur d’utiliser cette double mise à l’échelle, le balisage XAML pour l’affichage de chaque élément Image doit être modifié. Les exemples suivants montrent comment utiliser la mise à l’échelle double dans WPF dans Visual Studio à l’aide de la bibliothèque DpiHelper et de Shell.12/14.
Étape 1 : Mettre à l'échelle l'image à 200 %, 300 %, et ainsi de suite, en utilisant NearestNeighbor.
Préscalez l’image à l’aide d’un convertisseur appliqué à une liaison ou avec une extension de balisage XAML. Par exemple:
<vsui:DpiPrescaleImageSourceConverter x:Key="DpiPrescaleImageSourceConverter" />
<Image Source="{Binding Path=SelectedImage, Converter={StaticResource DpiPrescaleImageSourceConverter}}" Width="16" Height="16" />
<Image Source="{vsui:DpiPrescaledImage Images/Help.png}" Width="16" Height="16" />
Si l’image doit également être thématisée (la plupart, si ce n'est pas toutes, doivent), le balisage peut utiliser un convertisseur différent qui effectue d’abord le theming de l’image, puis le pré-rééchelonnage. Le balisage peut utiliser soit DpiPrescaleThemedImageConverter soit DpiPrescaleThemedImageSourceConverter, selon la sortie de conversion souhaitée.
<vsui:DpiPrescaleThemedImageSourceConverter x:Key="DpiPrescaleThemedImageSourceConverter" />
<Image Width="16" Height="16">
<Image.Source>
<MultiBinding Converter="{StaticResource DpiPrescaleThemedImageSourceConverter}">
<Binding Path="Icon" />
<Binding Path="(vsui:ImageThemingUtilities.ImageBackgroundColor)"
RelativeSource="{RelativeSource Self}" />
<Binding Source="{x:Static vsui:Boxes.BooleanTrue}" />
</MultiBinding>
</Image.Source>
</Image>
Étape 2 : Vérifiez que la taille finale est correcte pour le PPP actuel.
Étant donné que WPF met l'interface utilisateur à l'échelle pour le DPI actuel en utilisant la propriété BitmapScalingMode définie sur l'UIElement, un contrôle Image utilisant une image pré-redimensionnée comme sa source apparaîtra deux ou trois fois plus grande que prévu. Voici quelques façons de contrer cet effet :
Si vous connaissez la dimension de l’image d’origine à 100%, vous pouvez spécifier la taille exacte du contrôle Image. Ces tailles reflètent la taille de l’interface utilisateur avant l’application de la mise à l’échelle.
<Image Source="{Binding Path=SelectedImage, Converter={StaticResource DpiPrescaleImageSourceConverter}}" Width="16" Height="16" />Si la taille de l’image d’origine n’est pas connue, un LayoutTransform peut être utilisé pour effectuer un scale-down de l’objet Image final. Par exemple:
<Image Source="{Binding Path=SelectedImage, Converter={StaticResource DpiPrescaleImageSourceConverter}}" > <Image.LayoutTransform> <ScaleTransform ScaleX="{x:Static vsui:DpiHelper.PreScaledImageLayoutTransformScale}" ScaleY="{x:Static vsui:DpiHelper.PreScaledImageLayoutTransformScale}" /> </Image.LayoutTransform> </Image>
Activation de la prise en charge HDPI pour le WebOC
Par défaut, les contrôles WebOC (tels que le contrôle WebBrowser dans WPF ou l’interface IWebBrowser2) n’activent pas la détection et la prise en charge hdPI. Le résultat est un contrôle incorporé avec du contenu d’affichage trop petit sur un affichage haute résolution. L’exemple suivant explique comment activer la prise en charge haute résolution dans une instance web WebOC spécifique.
Implémentez l’interface IDocHostUIHandler (consultez l’article MSDN sur IDocHostUIHandler :
[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
Guid("BD3F23C0-D43E-11CF-893B-00AA00BDCE1A")]
public interface IDocHostUIHandler
{
[return: MarshalAs(UnmanagedType.I4)]
[PreserveSig]
int ShowContextMenu(
[In, MarshalAs(UnmanagedType.U4)] int dwID,
[In] POINT pt,
[In, MarshalAs(UnmanagedType.Interface)] object pcmdtReserved,
[In, MarshalAs(UnmanagedType.IDispatch)] object pdispReserved);
[return: MarshalAs(UnmanagedType.I4)]
[PreserveSig]
int GetHostInfo([In, Out] DOCHOSTUIINFO info);
[return: MarshalAs(UnmanagedType.I4)]
[PreserveSig]
int ShowUI(
[In, MarshalAs(UnmanagedType.I4)] int dwID,
[In, MarshalAs(UnmanagedType.Interface)] object activeObject,
[In, MarshalAs(UnmanagedType.Interface)] object commandTarget,
[In, MarshalAs(UnmanagedType.Interface)] object frame,
[In, MarshalAs(UnmanagedType.Interface)] object doc);
[return: MarshalAs(UnmanagedType.I4)]
[PreserveSig]
int HideUI();
[return: MarshalAs(UnmanagedType.I4)]
[PreserveSig]
int UpdateUI();
[return: MarshalAs(UnmanagedType.I4)]
[PreserveSig]
int EnableModeless([In, MarshalAs(UnmanagedType.Bool)] bool fEnable);
[return: MarshalAs(UnmanagedType.I4)]
[PreserveSig]
int OnDocWindowActivate([In, MarshalAs(UnmanagedType.Bool)] bool fActivate);
[return: MarshalAs(UnmanagedType.I4)]
[PreserveSig]
int OnFrameWindowActivate([In, MarshalAs(UnmanagedType.Bool)] bool fActivate);
[return: MarshalAs(UnmanagedType.I4)]
[PreserveSig]
int ResizeBorder(
[In] COMRECT rect,
[In, MarshalAs(UnmanagedType.Interface)] object doc,
bool fFrameWindow);
[return: MarshalAs(UnmanagedType.I4)]
[PreserveSig]
int TranslateAccelerator(
[In] ref MSG msg,
[In] ref Guid group,
[In, MarshalAs(UnmanagedType.I4)] int nCmdID);
[return: MarshalAs(UnmanagedType.I4)]
[PreserveSig]
int GetOptionKeyPath(
[Out, MarshalAs(UnmanagedType.LPArray)] string[] pbstrKey,
[In, MarshalAs(UnmanagedType.U4)] int dw);
[return: MarshalAs(UnmanagedType.I4)]
[PreserveSig]
int GetDropTarget(
[In, MarshalAs(UnmanagedType.Interface)] IOleDropTarget pDropTarget,
[MarshalAs(UnmanagedType.Interface)] out IOleDropTarget ppDropTarget);
[return: MarshalAs(UnmanagedType.I4)]
[PreserveSig]
int GetExternal([MarshalAs(UnmanagedType.IDispatch)] out object ppDispatch);
[return: MarshalAs(UnmanagedType.I4)]
[PreserveSig]
int TranslateUrl(
[In, MarshalAs(UnmanagedType.U4)] int dwTranslate,
[In, MarshalAs(UnmanagedType.LPWStr)] string strURLIn,
[MarshalAs(UnmanagedType.LPWStr)] out string pstrURLOut);
[return: MarshalAs(UnmanagedType.I4)]
[PreserveSig]
int FilterDataObject(
IDataObject pDO,
out IDataObject ppDORet);
}
Si vous le souhaitez, implémentez l’interface ICustomDoc (consultez l’article MSDN sur ICustomDoc :
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
Guid("3050F3F0-98B5-11CF-BB82-00AA00BDCE0B")]
public interface ICustomDoc
{
void SetUIHandler(IDocHostUIHandler pUIHandler);
}
Associez la classe qui implémente IDocHostUIHandler au document du WebOC. Si vous avez implémenté l’interface ICustomDoc ci-dessus, dès que la propriété de document du WebOC est valide, effectuez un cast vers un ICustomDoc et appelez la méthode SetUIHandler, en passant la classe qui implémente IDocHostUIHandler.
// "this" references that class that owns the WebOC control and in this case also implements the IDocHostUIHandler interface
ICustomDoc customDoc = (ICustomDoc)webBrowser.Document;
customDoc.SetUIHandler(this);
Si vous n’avez PAS implémenté l’interface ICustomDoc, dès que la propriété de document du WebOC est valide, vous devez la convertir en IOleObject et appeler la SetClientSite méthode, en passant la classe qui implémente IDocHostUIHandler. Définissez le indicateur DOCHOSTUIFLAG_DPI_AWARE dans le DOCHOSTUIINFO passé lors de l'appel de la méthode GetHostInfo.
public int GetHostInfo(DOCHOSTUIINFO info)
{
// This is what the default site provides.
info.dwFlags = (DOCHOSTUIFLAG)0x5a74012;
// Add the DPI flag to the defaults
info.dwFlags |=.DOCHOSTUIFLAG.DOCHOSTUIFLAG_DPI_AWARE;
return S_OK;
}
Cela devrait être tout ce dont vous avez besoin pour que votre contrôle WebOC prenne en charge HPDI.
Conseils
Si la propriété de document sur le contrôle WebOC change, vous devrez peut-être réassocier le document à la classe IDocHostUIHandler.
Si la solution ci-dessus ne fonctionne pas, il y a un problème connu avec le WebOC qui ne prend pas en compte le changement du paramètre DPI. Le moyen le plus fiable de résoudre ce problème consiste à basculer le zoom optique du WebOC, c'est-à-dire effectuer deux appels avec deux valeurs de pourcentage de zoom différentes. En outre, si cette solution de contournement est requise, il peut être nécessaire de l’effectuer sur chaque appel de navigation.
// browser2 is a SHDocVw.IWebBrowser2 in this case // EX: Call the Exec twice with DPI%-1 and then DPI% as the zoomPercent values IOleCommandTarget cmdTarget = browser2.Document as IOleCommandTarget; if (cmdTarget != null) { object commandInput = zoomPercent; cmdTarget.Exec(IntPtr.Zero, OLECMDID_OPTICAL_ZOOM, OLECMDEXECOPT_DONTPROMPTUSER, ref commandInput, ref commandOutput); }