วิธีเขียนรหัส WinForms ที่ปรับขนาดเป็นแบบอักษรของระบบและการตั้งค่า dpi โดยอัตโนมัติ


143

อินโทร:มีความคิดเห็นมากมายที่บอกว่า "WinForms ไม่ได้ปรับสเกลให้เป็น DPI / การตั้งค่าแบบอักษรได้อย่างอัตโนมัติ แต่เปลี่ยนเป็น WPF" อย่างไรก็ตามฉันคิดว่าเป็นไปตาม. NET 1.1 ดูเหมือนว่าพวกเขาใช้งานการปรับขนาดอัตโนมัติใน. NET 2.0 อย่างน้อยก็มาจากการวิจัยและการทดสอบของเรา อย่างไรก็ตามหากคุณบางคนในที่นี้รู้ดีกว่านี้เรายินดีรับฟังจากคุณ (โปรดอย่ากังวลกับการโต้เถียงเราควรเปลี่ยนเป็น WPF ... นั่นไม่ใช่ตัวเลือกในขณะนี้)

คำถาม:

  • อะไรใน WinForms ไม่ปรับขนาดอัตโนมัติอย่างถูกต้องดังนั้นควรหลีกเลี่ยง

  • แนวทางการออกแบบอะไรที่โปรแกรมเมอร์ควรปฏิบัติตามเมื่อเขียนโค้ด WinForms ซึ่งจะทำให้การปรับสเกลอัตโนมัติดีขึ้นหรือไม่

แนวทางการออกแบบที่เราได้ระบุไว้:

ดูคำตอบวิกิของชุมชนด้านล่าง

มีสิ่งใดที่ไม่ถูกต้องหรือไม่เพียงพอหรือไม่? แนวทางอื่น ๆ ที่เราควรนำมาใช้? มีรูปแบบอื่น ๆ ที่จำเป็นต้องหลีกเลี่ยงหรือไม่? คำแนะนำอื่น ๆ เกี่ยวกับเรื่องนี้จะได้รับการชื่นชมอย่างมาก

คำตอบ:


127

การควบคุมที่ไม่รองรับการปรับขนาดอย่างถูกต้อง:

  • Labelด้วยAutoSize = FalseและFontสืบทอด ตั้งค่าอย่างชัดเจนFontบนตัวควบคุมเพื่อให้ปรากฏเป็นตัวหนาในหน้าต่างคุณสมบัติ
  • ListViewความกว้างคอลัมน์ไม่ได้ปรับขนาด แทนที่ฟอร์มที่ScaleControlจะทำแทน ดูคำตอบนี้
  • SplitContainer's Panel1MinSize, Panel2MinSizeและSplitterDistanceคุณสมบัติ
  • TextBoxด้วยMultiLine = TrueและFontสืบทอด ตั้งค่าอย่างชัดเจนFontบนตัวควบคุมเพื่อให้ปรากฏเป็นตัวหนาในหน้าต่างคุณสมบัติ
  • ToolStripButtonรูปภาพของ ในตัวสร้างของฟอร์ม:

    • ชุด ToolStrip.AutoSize = False
    • ตั้งค่าToolStrip.ImageScalingSizeตามCreateGraphics.DpiXและ.DpiY
    • ตั้งค่าToolStrip.AutoSize = Trueหากจำเป็น

    บางครั้งAutoSizeสามารถถูกทิ้งไว้ที่Trueแต่บางครั้งก็ไม่สามารถปรับขนาดโดยไม่ต้องทำตามขั้นตอนเหล่านั้น ทำงานโดยไม่มีการเปลี่ยนแปลงที่มี.NET Framework 4.5.2EnableWindowsFormsHighDpiAutoResizingและ

  • TreeViewรูปภาพของ ตั้งImageList.ImageSizeตามและCreateGraphics.DpiX .DpiYสำหรับการStateImageListทำงานโดยไม่มีการเปลี่ยนแปลงที่มี.NET Framework 4.5.1EnableWindowsFormsHighDpiAutoResizingและ
  • Formขนาดของ ปรับขนาดคงFormที่ด้วยตนเองหลังจากการสร้าง

แนวทางการออกแบบ:

  • ContainerControls AutoScaleMode = Fontทั้งหมดจะต้องตั้งค่าเดียวกัน (แบบอักษรจะจัดการกับการเปลี่ยนแปลง DPI และการเปลี่ยนแปลงการตั้งค่าขนาดแบบอักษรของระบบ DPI จะจัดการการเปลี่ยนแปลง DPI เท่านั้นไม่ใช่การเปลี่ยนแปลงการตั้งค่าขนาดแบบอักษรของระบบ)

  • ContainerControls ทั้งหมดจะต้องตั้งค่าเหมือนกันAutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);สมมติว่า 96dpi (ดูสัญลักษณ์แสดงหัวข้อย่อยถัดไป) และแบบอักษรเริ่มต้นของ MS Sans Serif (ดูหัวข้อย่อยสองลง) นั่นคือการเพิ่มอัตโนมัติโดยนักออกแบบตาม DPI ที่คุณเปิดนักออกแบบใน ... แต่ขาดหายไปจากไฟล์นักออกแบบที่เก่าแก่ที่สุดของเรา บางที Visual Studio .NET (รุ่นก่อน VS 2005) อาจไม่ได้เพิ่มเข้าไปอย่างถูกต้อง

  • นักออกแบบทั้งหมดของคุณทำงานใน 96dpi (เราอาจเปลี่ยนเป็น 120dpi ได้ แต่ภูมิปัญญาบนอินเทอร์เน็ตบอกว่าให้ติดกับ 96dpi การทดลองนั้นอยู่ในลำดับนั้นโดยการออกแบบมันไม่สำคัญว่ามันจะเปลี่ยนAutoScaleDimensionsเส้นที่ ผู้ออกแบบแทรก) ในการตั้งค่า Visual Studio ให้ทำงานที่ 96dpi เสมือนจริงบนหน้าจอความละเอียดสูงให้ค้นหาไฟล์. exe คลิกขวาเพื่อแก้ไขคุณสมบัติและภายใต้ความเข้ากันได้เลือก "แทนที่พฤติกรรมการปรับสเกล DPI สูงการปรับขนาดดำเนินการโดย: ระบบ"

  • ตรวจสอบให้แน่ใจว่าคุณไม่เคยตั้งค่าฟอนต์ที่ระดับคอนเทนเนอร์ ... เฉพาะบนตัวควบคุมลีฟหรือในตัวสร้างของฟอร์มพื้นฐานที่สุดของคุณหากคุณต้องการฟอนต์ปริยายแบบกว้าง ๆ ของแอปพลิเคชันนอกเหนือจาก MS Sans Serif (การตั้งค่าแบบอักษรบนคอนเทนเนอร์ดูเหมือนว่าปิดการปรับขนาดอัตโนมัติของคอนเทนเนอร์นั้นเนื่องจากตัวอักษรจะมาหลังจากการตั้งค่าของ AutoScaleMode และการตั้งค่า AutoScaleDimensions ตามลำดับตัวอักษร) โปรดทราบว่าหากคุณเปลี่ยนแบบอักษรในตัวสร้างฟอร์มฐานที่สุดของคุณ AutoScaleDimensions ของคุณเพื่อคำนวณแตกต่างจาก 6x13; โดยเฉพาะอย่างยิ่งถ้าคุณเปลี่ยนเป็น Segoe UI (แบบอักษรเริ่มต้น Win 10) มันจะเป็น 7x15 ... คุณจะต้องแตะทุกรูปแบบใน Designer เพื่อให้สามารถคำนวณขนาดทั้งหมดในไฟล์. designer นั้นรวมถึงAutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);

  • อย่าใช้ Anchor RightหรือBottomยึดกับ UserControl ... การวางตำแหน่งจะไม่ปรับระดับอัตโนมัติ ให้วางพาเนลหรือคอนเทนเนอร์อื่นลงใน UserControl ของคุณและยึดการควบคุมอื่น ๆ ไว้ในพาเนลนั้น มีแผงใช้ Dock Right, BottomหรือFillใน UserControl ของคุณ

  • เฉพาะการควบคุมในรายการการควบคุมเมื่อResumeLayoutสิ้นสุดการInitializeComponentเรียกเท่านั้นที่จะถูกปรับขนาดอัตโนมัติ ... หากคุณเพิ่มการควบคุมแบบไดนามิกคุณจะต้องSuspendLayout(); AutoScaleDimensions = new SizeF(6F, 13F); AutoScaleMode = AutoScaleMode.Font; ResumeLayout();ควบคุมการนั้นก่อนที่คุณจะเพิ่มมันและตำแหน่งของคุณจะต้องมีการปรับด้วย ถ้าคุณไม่ได้ใช้โหมด Dock หรือผู้จัดการเค้าโครงเหมือนหรือFlowLayoutPanelTableLayoutPanel

  • คลาสพื้นฐานที่ได้รับมาContainerControlควรปล่อยให้AutoScaleModeตั้งค่าเป็นInherit(ค่าเริ่มต้นที่กำหนดไว้ในคลาสContainerControlแต่ไม่ใช่ค่าเริ่มต้นที่กำหนดโดยผู้ออกแบบ) หากคุณตั้งค่าเป็นสิ่งอื่นจากนั้นคลาสที่ได้รับของคุณจะพยายามตั้งค่าเป็นฟอนต์ (เท่าที่ควร) จากนั้นการตั้งค่าที่Fontจะล้างการตั้งค่าของนักออกแบบAutoScaleDimensionsส่งผลให้เกิดการสลับการปรับขนาดอัตโนมัติ! (คำแนะนำนี้รวมกับหนึ่งก่อนหน้านี้หมายความว่าคุณไม่สามารถยกตัวอย่างคลาสพื้นฐานในนักออกแบบ ... ทุกคลาสจำเป็นต้องได้รับการออกแบบเป็นคลาสฐานหรือคลาสลีฟ!

  • หลีกเลี่ยงการใช้Form.MaxSizeแบบคงที่ / ในตัวออกแบบ MinSizeและMaxSizeบนแบบฟอร์มไม่ได้ปรับขนาดเท่ากับทุกอย่าง ดังนั้นหากคุณทำงานทั้งหมดของคุณใน 96dpi แล้วเมื่อ DPI ที่สูงขึ้นคุณMinSizeจะไม่เกิดปัญหา แต่อาจไม่เข้มงวดเท่าที่คุณคาดหวัง แต่คุณMaxSizeอาจ จำกัด ขนาดของการปรับขนาดซึ่งอาจทำให้เกิดปัญหา หากคุณต้องการMinSize == Size == MaxSizeอย่าทำเช่นนั้นใน Designer ... ทำเช่นนั้นใน Constructor หรือOnLoadOverride ... ตั้งค่าทั้งสองMinSizeและMaxSizeเป็นขนาดที่ปรับขนาดแล้ว

  • การควบคุมทั้งหมดโดยเฉพาะPanelหรือContainerควรใช้การยึดหรือเชื่อมต่อ หากคุณผสมพวกเขาการปรับขนาดอัตโนมัติที่ทำโดยPanelมักจะทำงานผิดปกติในรูปแบบที่แปลกประหลาด

  • เมื่อทำการปรับขนาดอัตโนมัติมันจะพยายามปรับขนาดแบบฟอร์มโดยรวม ... อย่างไรก็ตามหากในกระบวนการนั้นจะมีขนาดถึงขีด จำกัด สูงสุดของขนาดหน้าจอนั่นเป็นข้อ จำกัด ที่ยากซึ่งจะทำให้สกรู (คลิป) การปรับขนาด ดังนั้นคุณควรตรวจสอบให้แน่ใจว่าแบบฟอร์มทั้งหมดใน Designer ที่ 100% / 96dpi มีขนาดไม่เกิน 1024x720 (ซึ่งตรงกับ 150% บนหน้าจอ 1080p หรือ 300% ซึ่งเป็นค่า Windows ที่แนะนำบนหน้าจอ 4K) แต่คุณต้องลบแถบชื่อเรื่อง / คำบรรยายภาพ Win10 ยักษ์ ... เช่นขนาดสูงสุด 1000x680 สูงสุด ... ซึ่งในนักออกแบบจะเป็น 994x642 ขนาดลูกค้า (ดังนั้นคุณสามารถทำการอ้างอิง FindAll บน ClientSize เพื่อค้นหาผู้ฝ่าฝืนได้)


NumericUpDownไม่ปรับขนาดMarginอย่างเหมาะสมเช่นกัน ดูเหมือนว่าจะได้รับการปรับขนาดสองครั้ง ถ้าฉันปรับขนาดมันอีกครั้งมันก็ดูดี
ygoe

AutoScaleMode = Fontใช้งานไม่ได้กับผู้ใช้ที่ใช้แบบอักษรขนาดใหญ่มากและใช้งานบน Ubuntu เราชอบAutoScaleMode = DPI
KindDragon

> TextBox พร้อม MultiLine = True และ Font จะบ้าไปทั้งวัน - นั่นคือการแก้ไข! ขอบคุณมาก! โดยวิธีการแก้ไขเดียวกันนี้ยังแก้ไขการควบคุมกล่องรายการ : D
neminem

สำหรับฉันกล่องรายการที่มีแบบอักษรที่สืบทอดมานั้นไม่ได้ขยายขนาด พวกเขาทำหลังจากตั้งค่าอย่างชัดเจน (.NET 4.7)
PulseJet


27

ประสบการณ์ของฉันแตกต่างจากคำตอบที่ได้รับการโหวตสูงสุดในปัจจุบัน ด้วยการใช้โค้ดเฟรมเวิร์ก. NET และอ่านซอร์สโค้ดอ้างอิงฉันได้ข้อสรุปว่าทุกอย่างพร้อมจะถูกปรับขนาดอัตโนมัติให้ทำงานได้และมีเพียงปัญหาเล็กน้อยที่จะทำให้สับสน เรื่องนี้กลายเป็นจริง

หากคุณสร้างเลย์เอาต์ที่ปรับขนาดได้ / ขนาดอัตโนมัติได้อย่างถูกต้องแล้วเกือบทุกอย่างจะทำงานอย่างที่ควรจะเป็นโดยอัตโนมัติด้วยการตั้งค่าเริ่มต้นที่ใช้โดย Visual Studio (กล่าวคือ AutoSizeMode = Font บนฟอร์มหลักและสืบทอดทุกอย่างอื่น)

gotcha เพียงอย่างเดียวคือถ้าคุณตั้งค่าคุณสมบัติฟอนต์ในแบบฟอร์มในตัวออกแบบ ที่สร้างรหัสที่ได้รับมอบหมายจะเรียงลำดับตามตัวอักษรซึ่งหมายความว่าAutoScaleDimensionsจะได้รับมอบหมายก่อน Fontโชคไม่ดีที่สิ่งนี้ทำให้ตรรกะการปรับขนาดอัตโนมัติของ WinForms สมบูรณ์

การแก้ไขนั้นง่ายแม้ว่า ไม่ต้องตั้งค่าFontคุณสมบัติในตัวออกแบบเลย (ตั้งค่าในตัวสร้างแบบฟอร์มของคุณ) หรือเรียงลำดับการมอบหมายเหล่านี้ใหม่ด้วยตนเอง (แต่คุณต้องทำสิ่งนี้ทุกครั้งที่คุณแก้ไขแบบฟอร์มในตัวออกแบบ) Voila เกือบสมบูรณ์แบบและการปรับขนาดโดยอัตโนมัติด้วยความยุ่งยากน้อยที่สุด แม้ขนาดของแบบฟอร์มจะถูกลดขนาดอย่างถูกต้อง


ฉันจะแสดงรายการปัญหาที่ทราบที่นี่เมื่อฉันพบพวกเขา:

  • ซ้อนคำนวณอัตรากำไรที่ควบคุมไม่ถูกต้องTableLayoutPanel ไม่ทราบว่าจะหลีกเลี่ยงระยะขอบและแผงรองโดยรวมที่ทราบได้หรือไม่

1
ไม่ตั้งค่าFontในตัวออกแบบ: ความคิดคำนึงถึง: ไปข้างหน้าและตั้งค่าแบบอักษรในตัวออกแบบเพื่อให้คุณสามารถออกแบบด้วยตัวอักษรที่ต้องการ แล้วในตัวสร้างหลังจากเค้าโครงอ่านคุณสมบัติแบบอักษรนั้นและตั้งค่าเดิมอีกครั้ง? หรืออาจแค่ขอเค้าโครงที่จะทำอีกครั้ง? [Caveat: ฉันไม่มีเหตุผลที่จะทดสอบวิธีการนี้] หรือตามคำตอบของ Knowleechในผู้ออกแบบระบุเป็นพิกเซล (ดังนั้นนักออกแบบ Visual Studio จะไม่ขายบนหน้าจอ DPI สูง) และในรหัสอ่านค่าแปลงจากพิกเซล ถึงคะแนน (เพื่อปรับอัตราส่วนให้ถูกต้อง)
ToolmakerSteve

1
โค้ดของเราทุกบิตมีการตั้งค่าขนาดสเกลอัตโนมัติก่อนโหมดโหมดสเกลอัตโนมัติ ดูเหมือนว่าคำสั่งไม่สำคัญในกรณีส่วนใหญ่
Josh

ฉันค้นหารหัสของฉันสำหรับกรณีที่AutoScaleDimensionsไม่ได้ตั้งค่าnew SizeF(6F, 13F)ตามคำแนะนำในคำตอบยอดนิยม ปรากฏว่าในทุกกรณีคุณสมบัติแบบอักษรของแบบฟอร์มได้รับการตั้งค่า (ไม่ใช่ค่าเริ่มต้น) ปรากฏว่าเมื่อAutoScaleMode = FontใดAutoScaleDimensionsจะมีการคำนวณตามคุณสมบัติแบบอักษรของแบบฟอร์ม นอกจากนี้การปรับขนาดการตั้งค่าในแผงควบคุมของ WindowsAutoScaleDimensionsดูเหมือนว่าจะมีผลกระทบต่อ
วอลเตอร์ Stabosz

24

กำหนดเป้าหมายแอปพลิเคชันของคุณสำหรับ. Net Framework 4.7 และรันภายใต้ Windows 10 v1703 (ผู้สร้างอัปเดตผู้สร้าง 15063) กับสุทธิ 4.7 ภายใต้ Windows 10 (v1703), MS ทำมากของการปรับปรุง

เริ่มต้นด้วย. NET Framework 4.7, Windows Forms มีการปรับปรุงสำหรับ DPI สูงทั่วไปและสถานการณ์ DPI แบบไดนามิก เหล่านี้รวมถึง:

  • การปรับปรุงในมาตราส่วนและเค้าโครงของตัวควบคุมฟอร์ม Windows จำนวนหนึ่งเช่นตัวควบคุม MonthCalendar และตัวควบคุม CheckedListBox

  • การปรับสเกลผ่านครั้งเดียว ใน. NET Framework 4.6 และเวอร์ชันก่อนหน้านี้การปรับสเกลถูกดำเนินการผ่านการส่งหลายครั้งซึ่งทำให้การควบคุมบางอย่างถูกปรับขนาดมากกว่าที่จำเป็น

  • รองรับสถานการณ์ DPI แบบไดนามิกที่ผู้ใช้เปลี่ยน DPI หรือตัวประกอบสเกลหลังจากเปิดใช้งานแอปพลิเคชัน Windows Forms

หากต้องการสนับสนุนให้เพิ่มรายการแอปพลิเคชันลงในแอปพลิเคชันของคุณและส่งสัญญาณว่าแอปของคุณรองรับ Windows 10:

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

ถัดไปเพิ่มapp.configและประกาศแอพต่อการตรวจสอบรอบรู้ ตอนนี้เสร็จแล้วในแอปตั้งค่าและไม่แสดงในรายการเหมือนก่อน!

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

PerMonitorV2นี้เป็นของใหม่ตั้งแต่ Windows 10 ผู้สร้างอัพเดท:

DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2

หรือที่รู้จักในชื่อ Per Monitor v2 ความก้าวหน้าเหนือกว่าโหมดการรับรู้ DPI ต่อจอภาพดั้งเดิมซึ่งช่วยให้แอปพลิเคชันเข้าถึงพฤติกรรมการปรับขนาดที่เกี่ยวข้องกับ DPI ใหม่บนพื้นฐานหน้าต่างระดับบนสุด

  • หน้าต่างลูก DPI แจ้งเตือนการเปลี่ยนแปลง - ในบริบทการตรวจสอบ v2 โครงสร้างหน้าต่างทั้งหมดจะได้รับแจ้งการเปลี่ยนแปลง DPI ใด ๆ ที่เกิดขึ้น

  • การปรับขนาดของพื้นที่ที่ไม่ใช่ลูกค้า - หน้าต่างทั้งหมดจะดึงพื้นที่ที่ไม่ใช่ลูกค้าโดยอัตโนมัติในรูปแบบที่ละเอียดอ่อน DPI การโทรไปที่ EnableNonClientDpiScaling นั้นไม่จำเป็น

  • การทำเมนู Win32 ทุกเมนู - เมนู NTUSER ทั้งหมดที่สร้างขึ้นในบริบทการตรวจสอบ v2 จะถูกปรับอัตราส่วนในแบบต่อจอภาพ

  • กล่องโต้ตอบการปรับมาตราส่วน - กล่องโต้ตอบ Win32 ที่สร้างขึ้นในบริบทการตรวจสอบ v2 จะตอบสนองต่อการเปลี่ยนแปลง DPI โดยอัตโนมัติ

  • การปรับมาตราส่วนที่ปรับปรุงให้ดีขึ้นของตัวควบคุม comctl32 - ตัวควบคุม comctl32 ที่หลากหลายได้ปรับปรุงพฤติกรรมการปรับสเกล DPI ในบริบทของ Per Monitor v2

  • ปรับปรุงพฤติกรรมของชุดรูปแบบ - ตัวจัดการ UxTheme ที่เปิดในบริบทของหน้าต่าง Per Monitor v2 จะทำงานในแง่ของ DPI ที่เกี่ยวข้องกับหน้าต่างนั้น

ตอนนี้คุณสามารถสมัครรับ 3 กิจกรรมใหม่เพื่อรับการแจ้งเตือนเกี่ยวกับการเปลี่ยนแปลง DPI:

  • Control.DpiChangedAfterParentซึ่งเกิดขึ้นเมื่อการตั้งค่า DPI สำหรับตัวควบคุมถูกเปลี่ยนโดยทางโปรแกรมหลังจากเหตุการณ์การเปลี่ยนแปลง DPI สำหรับตัวควบคุมหลักหรือฟอร์มเกิดขึ้น

  • Control.DpiChangedBeforeParentซึ่งถูกเรียกใช้เมื่อการตั้งค่า DPI สำหรับตัวควบคุมถูกเปลี่ยนโดยทางโปรแกรมก่อนเหตุการณ์ DPI เปลี่ยนสำหรับการควบคุมหลักหรือฟอร์มเกิดขึ้น

  • Form.DpiChangedซึ่งจะทำงานเมื่อการตั้งค่า DPI เปลี่ยนแปลงบนอุปกรณ์แสดงผลที่มีการแสดงฟอร์มในปัจจุบัน

คุณมีวิธีช่วยเหลือ 3 วิธีเกี่ยวกับการจัดการ / ปรับ DPI:

  • Control.LogicalToDeviceUnitsซึ่งแปลงค่าจากโลจิคัลเป็นพิกเซลอุปกรณ์

  • Control.ScaleBitmapLogicalToDeviceซึ่งปรับขนาดภาพบิตแมปเป็นโลจิคัล DPI สำหรับอุปกรณ์

  • Control.DeviceDpiซึ่งจะส่งคืน DPI สำหรับอุปกรณ์ปัจจุบัน

หากคุณยังคงเห็นปัญหาคุณสามารถเลือกที่จะปรับปรุง DPI ผ่านรายการ

หากคุณไม่มีสิทธิ์เข้าถึงซอร์สโค้ดคุณสามารถไปที่คุณสมบัติของแอพพลิเคชั่นใน Windows Explorer ไปที่ความเข้ากันได้และเลือก System (Enhanced)

ป้อนคำอธิบายรูปภาพที่นี่

ซึ่งเปิดใช้งานการปรับขนาด GDI เพื่อปรับปรุงการจัดการ DPI ด้วย:

สำหรับแอปพลิเคชันที่ใช้ Windows เป็นแบบ GDI สามารถปรับ DPI เหล่านี้เป็นแบบต่อจอภาพ ซึ่งหมายความว่าแอพพลิเคชั่นเหล่านี้จะรับรู้ DPI ต่อจอภาพอย่างน่าอัศจรรย์

ทำตามขั้นตอนเหล่านั้นทั้งหมดและคุณควรได้รับประสบการณ์ DPI ที่ดีขึ้นสำหรับแอปพลิเคชัน WinForms แต่จำไว้ว่าคุณต้องกำหนดเป้าหมายแอปของคุณสำหรับ. net 4.7 และต้องการ Windows 10 Build 15063 เป็นอย่างน้อย (อัปเดตผู้สร้าง) ใน Windows 10 Update 1709 ถัดไปเราอาจได้รับการปรับปรุงเพิ่มเติม


12

คำแนะนำที่ฉันเขียนในที่ทำงาน:

WPF ทำงานใน 'อุปกรณ์ที่ไม่ขึ้นกับอุปกรณ์' ซึ่งหมายถึงการควบคุมทั้งหมดปรับให้เข้ากับหน้าจอความละเอียดสูง ใน WinForms จะใช้ความระมัดระวังมากขึ้น

WinForms ทำงานเป็นพิกเซล ข้อความจะถูกปรับสัดส่วนตามระบบ dpi แต่มักจะถูกครอบตัดโดยตัวควบคุมที่ไม่ปรับสัดส่วน เพื่อหลีกเลี่ยงปัญหาดังกล่าวคุณต้องหลีกเลี่ยงการกำหนดขนาดและการวางตำแหน่งอย่างชัดเจน ทำตามกฎเหล่านี้:

  1. ไม่ว่าคุณจะพบที่ใด (ฉลากปุ่มแผงควบคุม) ให้ตั้งค่าคุณสมบัติปรับขนาดอัตโนมัติเป็น True
  2. สำหรับเลย์เอาต์ให้ใช้ FlowLayoutPanel (a WPF StackPanel) และ TableLayoutPanel (a la WPF Grid) สำหรับเลย์เอาต์แทนที่จะใช้ Vanilla Panel
  3. หากคุณกำลังพัฒนาบนเครื่องที่มีความละเอียดสูงนักออกแบบ Visual Studio อาจเป็นเรื่องที่ยุ่งยาก เมื่อคุณตั้งค่า AutoSize = True มันจะปรับขนาดการควบคุมหน้าจอของคุณ หากการควบคุมมี AutoSizeMode = GrowOnly มันจะยังคงขนาดนี้สำหรับคนที่มีความละเอียด dpi ปกติเช่น ใหญ่กว่าที่คาดไว้ ในการแก้ไขปัญหานี้ให้เปิดตัวออกแบบบนคอมพิวเตอร์ด้วย dpi ปกติแล้วคลิกขวาตั้งค่าใหม่

3
สำหรับกล่องโต้ตอบที่สามารถปรับขนาด AutoSize บนทุกสิ่งเป็นฝันร้ายฉันไม่ต้องการให้ปุ่มของฉันใหญ่ขึ้นและเล็กลงเมื่อฉันเพิ่มขนาดกล่องโต้ตอบด้วยตนเองขณะที่เรียกใช้โปรแกรม
Josh

10

ฉันพบว่ามันยากมากที่จะทำให้ WinForms เล่นได้ดีกับ DPI สูง ดังนั้นฉันเขียนวิธี VB.NET เพื่อแทนที่พฤติกรรมแบบฟอร์ม:

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

ฉันเพิ่งเจอปัญหานี้โดยเฉพาะอย่างยิ่งเมื่อรวมกับ Visual Studio rescaling เมื่อตัวแก้ไขถูกเปิดในระบบความละเอียดสูง ผมพบว่ามันที่ดีที่สุดเพื่อให้ AutoScaleMode = Fontแต่การตั้งค่าแบบฟอร์มFontแบบอักษรเริ่มต้น แต่การระบุขนาดในพิกเซลFont = MS Sans; 11pxไม่จุดเช่น: ในรหัสฉันแล้วรีเซ็ตแบบอักษรเป็นค่าเริ่มต้น:Font = SystemFonts.DefaultFontและทั้งหมดเป็นเรื่องปกติ

แค่สองเซ็นต์ของฉัน ฉันคิดว่าฉันแชร์เพราะ"การรักษา AutoScaleMode = Font"และ"กำหนดขนาดตัวอักษรเป็นพิกเซลสำหรับนักออกแบบ"เป็นสิ่งที่ฉันไม่พบในอินเทอร์เน็ต

ฉันมีรายละเอียดเพิ่มเติมเกี่ยวกับบล็อกของฉัน: http://www.sgrottel.de/?p=1581&lang=th


4

นอกจากแองเคอร์ทำงานได้ไม่ดีนัก: ฉันจะไปอีกขั้นหนึ่งและบอกว่าการวางตำแหน่งที่แน่นอน (หรือที่รู้จักโดยใช้คุณสมบัติตำแหน่ง) ไม่ทำงานได้ดีมากเมื่อปรับขนาดตัวอักษร ฉันต้องแก้ไขปัญหานี้ในสองโครงการที่แตกต่างกัน ในทั้งสองเราต้องแปลงตำแหน่งของการควบคุม WinForms ทั้งหมดเพื่อใช้ TableLayoutPanel และ FlowLayoutPanel การใช้คุณสมบัติ Dock (มักจะถูกตั้งค่าเป็น Fill) ภายใน TableLayoutPanel ทำงานได้ดีมากและปรับขนาดได้ด้วยฟอนต์ DPI ของระบบ

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.