Anteckning
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
Allt fler enheter levereras med skärmar med hög upplösning. Dessa skärmar har vanligtvis över 200 bildpunkter per tum (ppi). Att arbeta med ett program på dessa datorer kräver att innehållet skalas upp för att uppfylla behoven av att visa innehållet på ett normalt visningsavstånd för enheten. Från och med 2014 är det primära målet för högdensitetsskärmar mobila datorenheter (surfplattor, clamshell-bärbara datorer och telefoner).
Windows 8.1 och senare innehåller flera funktioner som gör att dessa datorer kan arbeta med skärmar och miljöer där datorn är ansluten till både högdensitets- och standarddensitetsskärmar samtidigt.
Med Windows kan du skala innehåll till enheten med hjälp av inställningen "Gör text och andra objekt större eller mindre" (tillgängliga sedan Windows XP).
Windows 8.1 och senare kommer automatiskt att skala innehåll för att de flesta program ska vara konsekventa när de flyttas mellan skärmar med olika pixeltätheter. När den primära bildskärmen är hög densitet (200% skalning) och den sekundära bildskärmen är standarddensitet (100%) skalar Windows automatiskt ned innehållet i programfönstret på den sekundära skärmen (1 bildpunkt visas för var 4:e bildpunkt som återges av programmet).
Windows använder som standard rätt skalning för pixeldensiteten och visningsavståndet för skärmen (Windows 7 och senare, OEM-konfigurerbar).
Windows kan automatiskt skala innehåll upp till 250% på nya enheter som överskrider 280 ppi (från och med Windows 8.1 S14).
Windows har ett sätt att hantera uppskalning av användargränssnittet för att dra nytta av ökat antal bildpunkter. Ett program väljer det här systemet genom att deklarera sig själv som "system-DPI-medveten". Program som inte gör detta skalas upp av systemet. Detta kan resultera i en suddig användarupplevelse där applikationen är jämnt pixelförvrängd. Till exempel:
Visual Studio väljer att vara DPI-skalningsmedveten och är därför inte "virtualiserad".
Windows (och Visual Studio) använder flera användargränssnittstekniker, som har olika sätt att hantera skalningsfaktorer som anges av systemet. Till exempel:
WPF mäter kontroller på ett enhetsoberoende sätt (enheter, inte bildpunkter). WPF-användargränssnittet skalas automatiskt upp för den aktuella DPI:en.
Alla textstorlekar oavsett gränssnittsramverk uttrycks i punkter och behandlas därför av systemet som DPI-oberoende. Text i Win32, WinForms och WPF skalas redan upp korrekt när den ritas till visningsenheten.
Win32/WinForms-dialogrutor och fönster har medel för att aktivera layout som ändrar storlek på text (till exempel via rutnät, flöde och tabelllayoutpaneler). Dessa gör det möjligt att undvika hårdkodade pixelplatser som inte skalas när teckenstorlekarna ökas.
Ikoner som tillhandahålls av systemet eller resurserna baserat på systemmått (till exempel SM_CXICON och SM_CXSMICON) skalas redan upp.
Äldre Win32 (GDI, GDI+) och WinForms-baserat användargränssnitt
WPF är redan hög DPI-medveten, men mycket av vår Win32/GDI-baserade kod skrevs inte ursprungligen med DPI-medvetenhet i åtanke. Windows har tillhandahållit API:er för DPI-skalning. Korrigeringar av Win32-problem bör använda dessa konsekvent i hela produkten. Visual Studio har tillhandahållit ett hjälpklassbibliotek för att undvika duplicering av funktioner och säkerställa konsekvens i produkten.
Högupplösta bilder
Det här avsnittet är främst till för utvecklare som utökar Visual Studio 2013. För Visual Studio 2015 använder du bildtjänsten som är inbyggd i Visual Studio. Du kanske också upptäcker att du behöver stöd för/rikta in dig på många versioner av Visual Studio och därför är det inte ett alternativ att använda avbildningstjänsten 2015 eftersom den inte finns i tidigare versioner. Det här avsnittet är också till för dig då.
Skala upp bilder som är för små
Bilder som är för små kan skalas upp och återges på GDI och WPF med hjälp av några vanliga metoder. Hanterade DPI-hjälpklasser är tillgängliga för interna och externa Visual Studio-integrerare för att hantera skalningsikoner, bitmappar, imagestrips och bildlistor. Win32-baserade interna C/C++-hjälpverktyg är tillgängliga för skalning av HICON, HBITMAP, HIMAGELIST och VsUI::GdiplusImage. Skalning av en bitmapp kräver vanligtvis bara en enradsändring efter att en referens har inkluderats i hjälpbiblioteket. Till exempel:
Skalning av en bildlista beror på om bildlistan är färdig vid inläsningen eller om den läggs till under körning. Om det är klart vid inläsningen, anropa LogicalToDeviceUnits() med bildlistan som du skulle göra med en bitmapp. När koden behöver läsa in en enskild bitmapp innan du skapar bildlistan ska du skala bildstorleken för bildlistan:
imagelist.ImageSize = DpiHelper.LogicalToDeviceUnits(imagelist.ImageSize);
I intern kod kan dimensionerna skalas när du skapar avbildningslistan på följande sätt:
ImageList_Create(VsUI::DpiHelper::LogicalToDeviceUnitsX(16),VsUI::DpiHelper::LogicalToDeviceUnitsY(16), ILC_COLOR32|ILC_MASK, nCount, 1);
Funktioner i biblioteket tillåter att specificera algoritmen för storleksändring. När du skalar bilder som ska placeras i bildlistor måste du ange bakgrundsfärgen som används för transparens eller använda NearestNeighbor-skalning (vilket orsakar förvrängningar vid 125% och 150%).
Läs DpiHelper-dokumentationen på MSDN.
I följande tabell visas exempel på hur bilder ska skalas med motsvarande DPI-skalningsfaktorer. Bilderna som beskrivs i orange anger vår bästa praxis från och med Visual Studio 2013 (100%-200% DPI-skalning):
Layoutproblem
Vanliga layoutproblem kan undvikas främst genom att hålla punkter i användargränssnittet skalade och i förhållande till varandra i stället för att använda absoluta platser (särskilt i pixelenheter). Till exempel:
Layout-/textpositioner måste justeras för att ta hänsyn till uppskalade bilder.
Kolumner i rutnät måste ha bredden justerad för den uppskalade texten.
Hårdkodade storlekar eller utrymme mellan element måste också skalas upp. Storlekar som endast baseras på textdimensioner är vanligtvis bra, eftersom teckensnitt skalas upp automatiskt.
Hjälpfunktioner är tillgängliga i DpiHelper klassen för att tillåta skalning på X- och Y-axeln:
LogicalToDeviceUnitsX/LogicalToDeviceUnitsY (funktioner tillåter skalning på X/Y-axeln)
int space = DpiHelper.LogicalToDeviceUnitsX (10);
int height = VsUI::DpiHelper::LogicalToDeviceUnitsY(5);
Det finns överlagringar av LogicalToDeviceUnits för att möjliggöra skalning av objekt som Rect, Point och Size.
Använda DPIHelper-biblioteket/-klassen för att skala bilder och layout
Visual Studio DPI-hjälpbiblioteket är tillgängligt i interna och hanterade formulär och kan användas utanför Visual Studio-gränssnittet av andra program.
Om du vill använda biblioteket går du till Utökningsexemplen för Visual Studio VSSDK och klonar High-DPI_Images_Icons exempel.
I källfiler inkluderar du VsUIDpiHelper.h och anropar klassens VsUI::DpiHelper statiska funktioner:
#include "VsUIDpiHelper.h"
int cxScaled = VsUI::DpiHelper::LogicalToDeviceUnitsX(cx);
VsUI::DpiHelper::LogicalToDeviceUnits(&hBitmap);
Anmärkning
Använd inte hjälpfunktionerna i statiska variabler på modulnivå eller klassnivå. Biblioteket använder även statiska objekt för trådsynkronisering och du kan stöta på problem med orderinitiering. Konvertera antingen dessa statiska objekt till icke-statiska medlemsvariabler eller omsluta dem till en funktion (så att de skapas vid första åtkomsten).
Så här kommer du åt DPI-hjälpfunktionerna från hanterad kod som ska köras i Visual Studio-miljön:
Det förbrukande projektet måste använda den senaste versionen av Shell MPF. Till exempel:
<Reference Include="Microsoft.VisualStudio.Shell.14.0.dll" />Kontrollera att projektet har referenser till System.Windows.Forms, PresentationCore och PresentationUI.
I kod använder du namnområdet Microsoft.VisualStudio.PlatformUI och anropar statiska funktioner i klassen DpiHelper. För typer som stöds (punkter, storlekar, rektanglar och så vidare) finns det tilläggsfunktioner som returnerar nya skalbara objekt. Till exempel:
using Microsoft.VisualStudio.PlatformUI; double x = DpiHelper.LogicalToDeviceUnitsX(posX); Point ptScaled = ptOriginal.LogicalToDeviceUnits(); DpiHelper.LogicalToDeviceUnits(ref bitmap);
Hantera WPF-bildfuzziness i zoombart användargränssnitt
I WPF ändras bitmappar automatiskt av WPF för den aktuella DPI-zoomnivån med hjälp av en bicubic-algoritm av hög kvalitet (standard), vilket fungerar bra för bilder eller stora skärmbilder, men är olämpligt för menyikoner eftersom det introducerar upplevd oskärpa.
Rekommendationer:
För logotypbilder och banderoller kan standardstorleksläget BitmapScalingMode användas.
För menyobjekt och ikoner BitmapScalingMode bör användas när det inte orsakar andra förvrängningsartefakter för att eliminera oskärpa (vid 200% och 300%).
För stora zoomnivåer som inte är multiplar av 100% (till exempel 250% eller 350%), resulterar skalning av ikonografibilder med bikubisk i ett suddigt, urvattnat användargränssnitt. Ett bättre resultat erhålls genom att först skala bilden med NearestNeighbor till den största multipeln av 100% (till exempel 200% eller 300%) och skala med bicubic därifrån. Mer information finns i Specialfall: förskalning av WPF-avbildningar för stora DPI-nivåer.
Klassen DpiHelper i namnområdet Microsoft.VisualStudio.PlatformUI innehåller en medlem BitmapScalingMode som kan användas för bindning. Det gör att Visual Studio-gränssnittet kan styra bitmappens skalningsläge i produkten på ett enhetligt sätt, beroende på DPI-skalningsfaktorn.
Om du vill använda den i XAML lägger du till:
xmlns:vsui="clr-namespace:Microsoft.VisualStudio.PlatformUI;assembly=Microsoft.VisualStudio.Shell.14.0"
<Setter Property="RenderOptions.BitmapScalingMode" Value="{x:Static vs:DpiHelper.BitmapScalingMode}" />
Visual Studio-gränssnittet anger redan den här egenskapen i fönster och dialogrutor på den översta nivån. WPF-baserat användargränssnitt som körs i Visual Studio ärver det redan. Om inställningen inte sprids till dina specifika delar av användargränssnittet kan den ställas in på rotelementet i XAML/WPF-användargränssnittet. Platser där detta händer inkluderar popup-fönster, på element med Win32-föräldrar och designerfönster, som körs utanför processen, till exempel Blend.
Vissa användargränssnitt kan skalas oberoende av systemuppsättningens DPI-zoomnivå, till exempel Visual Studio-textredigeraren och WPF-baserade designers (WPF Desktop och Windows Store). I dessa fall bör DpiHelper.BitmapScalingMode inte användas. För att åtgärda det här problemet i redigeraren skapade IDE-teamet en anpassad egenskap med titeln RenderOptions.BitmapScalingMode. Ange egenskapsvärdet till HighQuality eller NearestNeighbor beroende på systemets och användargränssnittets kombinerade zoomnivå.
Specialfall: förskalning av WPF-bilder för höga DPI-nivåer
För mycket stora zoomnivåer som inte är multiplar av 100% (till exempel 250%, 350%, och så vidare), när ikonografibilder skalas med bicubic, resulterar det i suddigt, urvattnat användargränssnitt. Intrycket av dessa bilder tillsammans med skarp text är nästan som en optisk illusion. Bilderna verkar vara närmare ögat och ur fokus i förhållande till texten. Skalningsresultatet med den här förstorade storleken kan förbättras genom att först skala bilden med NearestNeighbor till den största multipeln av 100% (till exempel 200% eller 300%) och skala med bicubic till resten (ytterligare 50%).
Följande är ett exempel på skillnaderna i resultat, där den första bilden skalas med den förbättrade dubbelskalningsalgoritmen 100%->200%->250%och den andra bara med bicubic 100%->250%.
För att göra det möjligt för användargränssnittet att använda den här dubbelskalningen måste XAML-markering för att visa varje bildelement ändras. Följande exempel visar hur du använder dubbel skalning i WPF i Visual Studio med hjälp av DpiHelper-biblioteket och Shell.12/14.
Steg 1: Förskala avbildningen till 200%, 300%och så vidare med NearestNeighbor.
Förskala avbildningen med antingen en konverterare som tillämpas på en bindning eller med ett XAML-markeringstillägg. Till exempel:
<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" />
Om bilden också behöver tematiseras (vilket de flesta, om inte alla, bör göra) kan markeringen använda en annan konverterare som först gör tematisering av bilden och sedan förskalning. Markup kan använda antingen DpiPrescaleThemedImageConverter eller DpiPrescaleThemedImageSourceConverter, beroende på önskat konverteringsresultat.
<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>
Steg 2: Kontrollera att den slutliga storleken är korrekt för aktuell DPI.
Eftersom WPF skalar användargränssnittet för den aktuella DPI:en med hjälp av egenskapen BitmapScalingMode som angetts i UIElement, ser en bildkontroll med en förskalad bild som källa två eller tre gånger större ut än den borde. Följande är några sätt att motverka den här effekten:
Om du känner till dimensionen för den ursprungliga bilden på 100%kan du ange den exakta storleken på bildkontrollen. Dessa storlekar återspeglar storleken på användargränssnittet innan skalning tillämpas.
<Image Source="{Binding Path=SelectedImage, Converter={StaticResource DpiPrescaleImageSourceConverter}}" Width="16" Height="16" />Om storleken på den ursprungliga bilden inte är känd kan en LayoutTransform användas för att skala ned det slutliga bildobjektet. Till exempel:
<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>
Aktivera HDPI-stöd till WebOC
WebOC-kontroller (till exempel WebBrowser-kontrollen i WPF eller IWebBrowser2-gränssnittet) aktiverar som standard inte HDPI-identifiering och stöd. Resultatet blir en inbäddad kontroll med visningsinnehåll som är för litet på en bildskärm med hög upplösning. Följande beskriver hur du aktiverar stöd för hög DPI i en specifik web WebOC-instans.
Implementera gränssnittet IDocHostUIHandler (se MSDN-artikeln om 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);
}
Du kan också implementera ICustomDoc-gränssnittet (se MSDN-artikeln om ICustomDoc:
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
Guid("3050F3F0-98B5-11CF-BB82-00AA00BDCE0B")]
public interface ICustomDoc
{
void SetUIHandler(IDocHostUIHandler pUIHandler);
}
Associera klassen som implementerar IDocHostUIHandler med WebOC:s dokument. Om du har implementerat ICustomDoc-gränssnittet ovan skickar du den till en ICustomDoc så snart weboc-dokumentegenskapen är giltig och anropar metoden SetUIHandler och skickar den klass som implementerar 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);
Om du INTE implementerade ICustomDoc-gränssnittet måste du så snart som WebOC:s dokumentegenskap är giltig omvandla den till en IOleObject och anropa SetClientSite metoden och skicka den klass som implementerar IDocHostUIHandler. Ställ in flaggan DOCHOSTUIFLAG_DPI_AWARE i DOCHOSTUIINFO som skickas till metodanropet 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;
}
Detta bör vara allt du behöver för att konfigurera din WebOC-kontroll att stödja HPDI.
Råd
Om dokumentegenskapen på WebOC-kontrollen ändras kan du behöva associera dokumentet igen med klassen IDocHostUIHandler.
Om ovanstående inte fungerar finns det ett känt problem med att WebOC inte plockar upp ändringen av DPI-flaggan. Det mest tillförlitliga sättet att åtgärda detta är att växla den optiska zoomen för WebOC, vilket innebär två anrop med två olika värden för zoomprocenten. Om den här lösningen krävs kan det dessutom vara nödvändigt att utföra den vid varje navigeringsanrop.
// 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); }