Sistem yazı tipi ve dpi ayarlarına otomatik olarak ölçeklenen WinForms kodu nasıl yazılır?


143

Giriş: Orada "WinForms otomatik olarak DPI / yazı tipi ayarlarına iyi ölçeklenmiyor; WPF'ye geç" diyen birçok yorum var. Ancak, bu .NET 1.1 tabanlı olduğunu düşünüyorum; aslında .NET 2.0'da otomatik ölçeklendirme uygulamak için oldukça iyi bir iş yaptılar. En azından şimdiye kadar yaptığımız araştırma ve testlere dayanıyor. Ancak, bazılarınız daha iyi bilirse, sizden haber almak isteriz.(Lütfen WPF'ye geçmemiz gerektiğini savunarak zahmet etmeyin ... bu şu anda bir seçenek değil.)

Sorular:

  • WinForms'da neler otomatik olarak ölçeklendirilmez ve bundan kaçınılmalıdır?

  • Programcılar WinForms kodunu yazarken otomatik olarak iyi ölçeklendirilecek şekilde hangi tasarım yönergelerini izlemelidir?

Şimdiye kadar belirlediğimiz Tasarım Yönergeleri:

Bkz topluluk wiki cevabı aşağıda.

Bunlardan herhangi biri yanlış veya yetersiz mi? Benimsememiz gereken başka yönergeler var mı? Kaçınılması gereken başka kalıplar var mı? Bununla ilgili başka bir rehberlik çok takdir edilecektir.

Yanıtlar:


127

Ölçeklendirmeyi doğru şekilde desteklemeyen kontroller:

  • Labelile AutoSize = Falseve Fontmiras kaldı. Açıkça ayarlandıFontDenetimin üzerinde, Özellikler penceresinde kalın harflerle görünecek şekilde .
  • ListViewsütun genişlikleri ölçeklenmez. ScaleControlBunun yerine formları geçersiz kılın . GörmekBu cevaba
  • SplitContainerVar Panel1MinSize, Panel2MinSizeveSplitterDistance özellikleri
  • TextBoxile MultiLine = Trueve Fontmiras kaldı. Açıkça ayarlandıFontDenetimin üzerinde, Özellikler penceresinde kalın harflerle görünecek şekilde .
  • ToolStripButtonkullanıcısının görüntüsü. Formun yapıcısında:

    • Ayarlamak ToolStrip.AutoSize = False
    • Set ToolStrip.ImageScalingSizegöreCreateGraphics.DpiX ve.DpiY
    • Ayarlamak ToolStrip.AutoSize = TrueGerekirse .

    Bazen AutoSizeatlanabilir, Trueancak bazen bu adımlar olmadan yeniden boyutlandırılamaz. O bir değişiklik olmadan çalışır .NET Framework 4.5.2 veEnableWindowsFormsHighDpiAutoResizing .

  • TreeViewadlı kullanıcının resimleri. Set ImageList.ImageSizegöre CreateGraphics.DpiXve .DpiY. İçin StateImageList, .NET Framework 4.5.1 veEnableWindowsFormsHighDpiAutoResizing .
  • Formboyutu. Oluşturulduktan Formsonra sabit boyutu elle ölçeklendirin .

Tasarım Kuralları:

  • Tüm ContainerControls aynı şekilde ayarlanmalıdır AutoScaleMode = Font. (Yazı tipi, hem DPI değişikliklerini hem de sistem yazı tipi boyutu ayarındaki değişiklikleri işleyecektir; DPI, sistem yazı tipi boyutu ayarındaki değişiklikleri değil, yalnızca DPI değişikliklerini işleyecektir.)

  • AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);96dpi (bir sonraki madde işaretine bakın) ve varsayılan MS Sans Serif Yazı Tipi (aşağıdaki madde işaretine bakınız) varsayarak, tüm ContainerController aynı şekilde ayarlanmalıdır . Bu, tasarımcı tarafından açtığınız DPI temel alınarak tasarımcı tarafından otomatik olarak eklenir ... ancak en eski tasarımcı dosyalarımızın çoğunda eksikti. Belki de Visual Studio .NET (VS 2005'ten önceki sürüm) bunu düzgün bir şekilde eklemiyordu.

  • Tüm tasarımcı çalışmalarınızı 96dpi'de yapın (120dpi'ye geçebiliriz; ancak internetteki bilgelik 96dpi'ye bağlı kalıyor diyor; deneme orada; tasarım gereği, sadece AutoScaleDimensionsçizgiyi değiştirdiği için önemli olmamalı tasarımcı ekler). Visual Studio'yu yüksek çözünürlüklü bir ekranda sanal 96dpi'de çalışacak şekilde ayarlamak için .exe dosyasını bulun, özellikleri düzenlemek için sağ tıklatın ve Uyumluluk altında "Yüksek DPI ölçeklendirme davranışını geçersiz kıl. Ölçekleme: Sistem" seçeneğini belirleyin.

  • Yazı tipini hiçbir zaman kap düzeyinde ayarladığınızdan emin olun ... MS Sans Serif dışında bir uygulama genelinde varsayılan Yazı Tipi kullanmak istiyorsanız, yalnızca en temel Formunuzun yapıcısında VEYA yaprak denetimlerinde. (Bir Kapsayıcıda Yazı Tipini Ayarlamak, kapsayıcıyı otomatik ölçeklendirmeyi kapatmış gibi görünmektedir çünkü AutoScaleMode ve AutoScaleDimensions ayarlarının ayarından sonra alfabetik olarak gelir.) Çoğu temel Formunuzun yapıcısında Yazı Tipi'ni değiştirirseniz, bunun nedeni 6x13'ten farklı hesaplamak için AutoScaleDimensions'ınız; özellikle, Segoe UI (Win 10 varsayılan yazı tipi) olarak değiştirirseniz, 7x15 olacaktır ... Tasarımcıdaki her bir Form'a dokunmanız gerekir, böylece bu .designer dosyasındaki tüm boyutları yeniden hesaplayabilir. AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);.

  • Ankraj KULLANMAYIN Rightveya Bottombir UserControl'e ankraj KULLANMAYIN ... konumu otomatik olarak ölçeklenmez; bunun yerine, Kullanıcı Denetimine bir Panel veya başka bir kap bırakın ve diğer Denetimlerinizi bu Panele Bağlayın; İskeleye Paneli kullanımı var Right, Bottomya Fillda UserControl.

  • Sadece Kontroller listelerinde kontroller ResumeLayoutsonunda InitializeComponentdinamik kontrolleri eklerseniz otomatik ölçekli olacak denir ..., o zaman gerek SuspendLayout(); AutoScaleDimensions = new SizeF(6F, 13F); AutoScaleMode = AutoScaleMode.Font; ResumeLayout();sen eklemeden önce o kumandada. Ve konumlandırma da ayarlanması gerekir dock modları ya da benzeri bir Düzen Yöneticisi kullanılarak değilse FlowLayoutPanelveya TableLayoutPanel.

  • Baz türetilmiş sınıfları ContainerControlterk etmelidir AutoScaleModeayarlı Inherit(sınıfta varsayılan değer kümesi ContainerControl; fakat DEĞİL tasarımcı tarafından varsayılan ayar). Başka bir şeye ayarlarsanız ve türetilmiş sınıfınız Yazı Tipi'ne (olması gerektiği gibi) ayarlamaya çalışırsa Font, tasarımcının ayarını temizleyecek AutoScaleDimensionsve gerçekte otomatik ölçeklendirmeyi devre dışı bırakacak şekilde ayarlama eylemi ! (Bu kılavuz öncekiyle birleştiğinde, bir tasarımcıda temel sınıfları asla başlatamayacağınız anlamına gelir ... tüm sınıfların ya temel sınıflar ya da yaprak sınıfları olarak tasarlanması gerekir!)

  • Form.MaxSizeStatik olarak / Tasarımcıda kullanmaktan kaçının . MinSizeve MaxSizeForm üzerinde her şey kadar ölçeklenmez. Bu nedenle, tüm çalışmalarınızı 96 dpi'de yaparsanız, daha yüksek DPI'de MinSizesorunlara neden olmazsınız, ancak beklediğiniz kadar kısıtlayıcı MaxSizeolmayabilir , ancak Boyutunuzun ölçeklendirmesini sınırlandırabilir, bu da sorunlara neden olabilir. İsterseniz bunu MinSize == Size == MaxSizeTasarımcı'da yapmayın ... bunu yapıcıda yapın veya OnLoadgeçersiz kılın ... her ikisini de MinSizeve MaxSizeuygun şekilde ölçeklendirilmiş Boyutunuza ayarlayın.

  • Belirli bir alandaki tüm Kontroller Panelveya ContainerAnchoring veya Docking kullanmalıdır. Bunları karıştırırsanız, bunun tarafından yapılan otomatik ölçeklendirme Panelgenellikle tuhaf şekillerde yanlış davranır.

  • Otomatik ölçeklendirme yaptığında, genel Formu ölçeklendirmeye çalışacaktır ... ancak, bu işlemde ekran boyutunun üst sınırına girerse, bu daha sonra vidalanabilen (klips) sabit bir sınırdır ölçeklendirme. Bu nedenle,% 100 / 96dpi'deki Tasarımcıdaki tüm Formların 1024x720'den büyük olmadığından (1080p ekranda% 150 veya 4K ekranda Windows tarafından önerilen değer olan% 300'e karşılık gelir) emin olmalısınız. Ancak dev Win10 başlık / altyazı çubuğunu çıkarmanız gerekiyor ... daha çok 1000x680 maksimum Boyut gibi ... tasarımcıda 994x642 ClientSize gibi olacak. (Böylece, ihlal edenleri bulmak için ClientSize'da bir FindAll Referansları yapabilirsiniz.)


NumericUpDownMargindoğru şekilde ölçeklemiyor . Marj iki kez ölçeklendirilmiş gibi görünüyor. Bir kez daha ölçeklendirirsem iyi görünüyor.
ygoe

AutoScaleMode = Fontçok büyük yazı tipi kullanan ve Ubuntu'da olan kullanıcılar için iyi çalışmaz. Tercih ediyoruzAutoScaleMode = DPI
KindDragon

> MultiLine içeren TextBox = True ve Font devralındı. Bütün gün çıldırmak - düzeltme buydu! Çok teşekkürler! Bu arada, aynı düzeltme ListBox denetimleri için de düzeltmedir. : D
neminem

Benim için miras alınan yazı tipi olan liste kutuları iyi ölçeklenmiyor. Açıkça ayarlandıktan sonra yaparlar. (.NET 4.7)
PulseJet


27

Deneyimlerim şu anki en çok oy alan cevaptan oldukça farklıydı. .NET çerçeve kodunu atlayarak ve referans kaynak kodunu inceleyerek, otomatik ölçeklemenin çalışması için her şeyin yerinde olduğu sonucuna vardım ve bir yere karışan sadece küçük bir sorun vardı. Bu doğru çıktı.

Düzgün yeniden akıtılabilir / otomatik boyutlu bir düzen oluşturursanız, neredeyse her şey tam olarak olması gerektiği gibi çalışır, otomatik olarak, Visual Studio tarafından kullanılan varsayılan ayarlarla (yani, üst formdaki AutoSizeMode = Yazı Tipi ve diğer her şeyde Devral).

Tek yakaladım, Font özelliğini tasarımcıda formda ayarladıysanız. Oluşturulan kod, alfabetik hangi araçları atamaları sıralanır AutoScaleDimensionsatanacaktır önce Font . Ne yazık ki, bu WinForms otomatik ölçeklendirme mantığını tamamen bozuyor.

Düzeltme olsa basit. Ya ayarlamayın Font(formunuz yapıcı sete o) hiç tasarımcı mülk veya el ile bu atamaları sipariş (ama o zaman tasarımcı formu düzenlemek bu her zaman yapmaya devam etmek gerekir). Voila, neredeyse mükemmel ve minimum güçlükle tam otomatik ölçeklendirme. Form boyutları bile doğru şekilde ölçeklendirilir.


Bilinen sorunları burada karşılaştığımda listeleyeceğim:

  • Yuvalanmış TableLayoutPanel kontrol kenar boşluklarını yanlış hesaplar . Kenar boşluklarından ve dolgulardan tamamen kaçınmak ya da iç içe geçmiş masa düzeni panellerinden kaçınmak için bilinen bir çözüm yoktur.

1
Ayarını değilsin Fonttasarımcı içinde: A düşünce akla gelir: İstenen yazı ile tasarlayabilirsiniz böylece devam edip tasarımcı yazı tipini ayarlayın. SONRA yapıcıda, mizanpajdan sonra, o font özelliğini okuyun ve aynı değeri tekrar ayarladınız mı? Ya da belki sadece düzenlemenin tekrar yapılmasını isteyin? [Dikkat: Bu yaklaşımı test etmek için nedenim yoktu.] Veya Knowleech'in cevabına göre , tasarımcıda piksel cinsinden belirtin (böylece Visual Studio tasarımcısı yüksek DPI monitöründe yeniden ölçeklenmeyecek) ve kodda bu değeri okuyun, piksellerden dönüştürün (doğru ölçeklendirme elde etmek için).
ToolmakerSteve

1
Kodumuzun her bir biti, otomatik ölçeklendirme modundan hemen önce ayarlanan otomatik ölçeklendirme boyutlarına sahiptir ve hepsi mükemmel ölçeklenir. Çoğu durumda siparişin önemi yok gibi görünüyor.
Josh

En üst yanıtta tavsiye edildiği gibi AutoScaleDimensionsayarlanmadığı durumlar için kodumu aradım new SizeF(6F, 13F). Her durumda, formun Font özelliğinin ayarlandığı (varsayılan değil) ortaya çıktı. Öyle görünüyor ki zaman AutoScaleMode = Font, o AutoScaleDimensionsformun yazı tipi özelliğini esas alınarak hesaplanır. Ayrıca, Windows Denetim Masası'ndaki Ölçeklendirme ayarının bir etkisi olduğu görülmektedir . AutoScaleDimensions
Walter Stabosz

24

.Net Framework 4.7 için Uygulamanızı hedefleyin ve Windows 10 v1703 (Creators Update Build 15063) altında çalıştırın. Windows 10 (v1703) altındaki .Net 4.7 ile MS, birçok DPI iyileştirmesi yaptı .

.NET Framework 4.7'den başlayarak, Windows Forms yaygın yüksek DPI ve dinamik DPI senaryoları için geliştirmeler içerir. Bunlar:

  • MonthCalendar denetimi ve CheckedListBox denetimi gibi bir dizi Windows Forms denetiminin ölçeklendirilmesi ve düzenindeki geliştirmeler.

  • Tek geçişli ölçekleme. .NET Framework 4.6 ve önceki sürümlerinde, ölçekleme birden çok geçişle gerçekleştirildi ve bu da bazı kontrollerin gereğinden fazla ölçeklenmesine neden oldu.

  • Bir Windows Forms uygulaması başlatıldıktan sonra kullanıcının DPI veya ölçek faktörünü değiştirdiği dinamik DPI senaryoları desteği.

Bunu desteklemek için uygulamanıza bir uygulama bildirimi ekleyin ve uygulamanızın Windows 10'u desteklediğini işaret edin:

<compatibility xmlns="urn:schemas-microsoft.comn:compatibility.v1">
    <application>
        <!-- Windows 10 compatibility -->
        <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
    </application>
</compatibility>

Sonra, ekleyin app.configve uygulamayı Başına Monitör Haberdar. Bu ŞİMDİ app.config içinde yapılır ve daha önce olduğu gibi manifestte DEĞİLDİR!

<System.Windows.Forms.ApplicationConfigurationSection>
   <add key="DpiAwareness" value="PerMonitorV2" />
</System.Windows.Forms.ApplicationConfigurationSection> 

Bu PerMonitorV2 , Windows 10 Creators Güncellemesinden bu yana yenidir:

DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2

Monitör Başına v2 olarak da bilinir. Uygulamaların en üst düzey pencere temelinde yeni DPI ile ilgili ölçeklendirme davranışlarına erişmesini sağlayan, monitör başına orijinal DPI farkındalık modu üzerinde bir ilerleme.

  • Alt pencere DPI değişiklik bildirimleri - Monitör Başına v2 bağlamlarında, tüm pencere ağacında meydana gelen tüm DPI değişiklikleri bildirilir.

  • İstemci olmayan alanın ölçeklendirilmesi - Tüm pencerelerde otomatik olarak DPI duyarlı bir şekilde çizilir. EnableNonClientDpiScaling çağrıları gereksizdir.

  • S Win32 menülerin caling - Başına Monitor v2 bağlamlarda oluşturulan tüm NTUSER menüleri başına monitör moda ölçekleme edilecektir.

  • İletişim Kutusu Ölçekleme - Monitör Başına v2 bağlamlarında oluşturulan Win32 iletişim kutuları otomatik olarak DPI değişikliklerine yanıt verir.

  • Comctl32 denetimlerinin ölçeklendirmesi iyileştirildi - Çeşitli comctl32 denetimleri, Monitör Başına v2 bağlamlarında gelişmiş DPI ölçeklendirme davranışına sahiptir.

  • Geliştirilmiş tema davranışı - Monitör Başına v2 penceresi bağlamında açılan UxTheme tutamaçları, bu pencereyle ilişkili DPI açısından çalışır.

Artık DPI değişiklikleri hakkında bildirim almak için 3 yeni etkinliğe abone olabilirsiniz:

  • Ateşlenen Control.DpiChangedAfterParent , bir denetimin DPI ayarı, üst denetimi veya formu için bir DPI değişiklik olayı gerçekleştikten sonra programlı olarak değiştirildiğinde ortaya çıkar.

  • Bir denetimin DPI ayarı, üst denetimi veya formu için bir DPI değişiklik olayı gerçekleşmeden önce programlı olarak değiştirildiğinde tetiklenen Control.DpiChangedBeforeParent .

  • Form.DpiChanged , formun görüntülenmekte olduğu görüntü aygıtında DPI ayarı değiştiğinde tetiklenir.

DPI işleme / ölçeklendirme hakkında 3 yardımcı yönteminiz de vardır:

  • Bir değeri mantıksaldan aygıt piksellerine dönüştüren Control.LogicalToDeviceUnits .

  • Control.ScaleBitmapLogicalToDeviceBitmap görüntüsünü bir aygıtın mantıksal DPI'sına ölçeklendiren .

  • Geçerli aygıtın DPI'sını döndüren Control.DeviceDpi .

Hâlâ sorun görüyorsanız, app.config girişleri aracılığıyla DPI geliştirmelerinden çıkabilirsiniz .

Kaynak koduna erişiminiz yoksa, Windows Gezgini'nde uygulama özelliklerine gidebilir, uyumluluğa gidebilir ve System (Enhanced)

resim açıklamasını buraya girin

DPI işlemeyi de iyileştirmek için GDI ölçeklendirmeyi etkinleştirir:

GDI tabanlı Windows uygulamaları için artık bunları monitör başına ölçeklendirebilir. Bu, bu uygulamaların sihirli bir şekilde izlenen DPI başına farkında olacağı anlamına gelir.

Tüm bu adımları uygulayın ve WinForms uygulamaları için daha iyi bir DPI deneyimi edinmelisiniz. Ancak, uygulamanızı .net 4.7 için hedeflemeniz ve en azından Windows 10 Build 15063'e (İçerik Oluşturucu Güncellemesi) ihtiyacınız olduğunu unutmayın. Bir sonraki Windows 10 Güncelleştirme 1709'da daha fazla iyileştirme alabiliriz.


12

İşte yazdığım bir rehber:

WPF 'cihazdan bağımsız birimlerde' çalışır, yani tüm kontroller yüksek dpi ekranlara mükemmel şekilde ölçeklenir. WinForms'da daha fazla dikkat gerektirir.

WinForms piksel olarak çalışır. Metin, sistem dpi'sine göre ölçeklendirilir, ancak genellikle ölçeklendirilmemiş bir denetim tarafından kırpılır. Bu tür problemlerden kaçınmak için, açık boyutlandırma ve konumlandırmadan kaçınmalısınız. Şu kurallara uyun:

  1. Nerede bulursanız olun (etiketler, düğmeler, paneller) Otomatik Boyut özelliğini True olarak ayarlayın.
  2. Düzen için, vanilya Paneli yerine düzen için FlowLayoutPanel (la WPF StackPanel) ve TableLayoutPanel (la la WPF Grid) kullanın.
  3. Yüksek bir dpi makinesinde geliştiriyorsanız, Visual Studio tasarımcısı bir hayal kırıklığı olabilir. AutoSize = True ayarladığınızda, kontrol ekranınıza yeniden boyutlandırılır. Denetimin AutoSizeMode = GrowOnly değeri varsa, normal dpi kullanan kişiler için bu boyutta kalacaktır. beklenenden daha büyük olmak. Bunu düzeltmek için, tasarımcıyı normal dpi'ye sahip bir bilgisayarda açın ve sağ tıklayın, sıfırlayın.

3
yeniden boyutlandırılabilen diyaloglar için her şeyde Otomatik Boyutlandırma kabus olur, programı çalıştırırken diyaloglarımı manuel olarak büyüttüğüm için düğmelerimin daha büyük ve daha küçük olmasını istemiyorum.
Josh

10

WinForms'un yüksek DPI ile güzel oynamasını çok zor buldum. Bu nedenle, form davranışını geçersiz kılmak için bir VB.NET yöntemi yazdım:

Public Shared Sub ScaleForm(WindowsForm As System.Windows.Forms.Form)
    Using g As System.Drawing.Graphics = WindowsForm.CreateGraphics
        Dim sngScaleFactor As Single = 1
        Dim sngFontFactor As Single = 1
        If g.DpiX > 96 Then
            sngScaleFactor = g.DpiX / 96
            'sngFontFactor = 96 / g.DpiY
        End If
        If WindowsForm.AutoScaleDimensions = WindowsForm.CurrentAutoScaleDimensions Then
            'ucWindowsFormHost.ScaleControl(WindowsForm, sngFontFactor)
            WindowsForm.Scale(sngScaleFactor)
        End If
    End Using
End Sub

6

Kısa süre önce bu sorunla karşılaştım, özellikle editör yüksek dpi sisteminde açıldığında Visual Studio yeniden ölçekleme ile birlikte. Bence en iyisi bulundu tutmak AutoScaleMode = Font , ancak Formlar ayarlamak için Yazı varsayılan yazı tipine, ancak piksel cinsinden boyutunu belirterek yani değil noktası: Font = MS Sans; 11px. Kodda, daha sonra yazı tipini varsayılana sıfırladım: Font = SystemFonts.DefaultFontve her şey yolunda.

Sadece iki sentim. Paylaşmayı düşündüm, çünkü “AutoScaleMode = Font” tutmak ve “Tasarımcı için pikselde yazı tipi boyutunu ayarla” internette bulamadığım bir şeydi.

Blogum hakkında daha fazla ayrıntı var: http://www.sgrottel.de/?p=1581&lang=tr


4

Çapaların çok iyi çalışmalarına ek olarak: Bir adım daha ileri gider ve tam konumlandırmanın (aka, Location özelliğini kullanarak) yazı tipi ölçeklendirmesiyle çok iyi çalışmadığını söyleyebilirim. Bu konuyu iki farklı projede ele almak zorunda kaldım. Her ikisinde de, tüm WinForms denetimlerinin konumlarını TableLayoutPanel ve FlowLayoutPanel kullanarak dönüştürmek zorunda kaldık. TableLayoutPanel içindeki Dock (genellikle Doldur olarak ayarlanır) özelliğini kullanmak çok iyi çalışır ve sistem yazı tipi DPI'sıyla iyi ölçeklendirilir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.