시스템 글꼴 및 dpi 설정으로 자동 확장되는 WinForms 코드를 작성하는 방법은 무엇입니까?


143

소개 : "WinForms는 DPI / 글꼴 설정으로 자동 확장되지 않습니다. WPF로 전환하십시오."라는 많은 의견이 있습니다. 그러나 나는 이것이 .NET 1.1을 기반으로한다고 생각합니다. 그들은 실제로 .NET 2.0에서 자동 스케일링을 구현하는 데 꽤 좋은 일을 한 것으로 보입니다. 최소한 지금까지 우리의 연구와 테스트에 근거합니다. 그러나 여러분 중 일부가 더 잘 알고 있다면, 여러분의 의견을 듣고 싶습니다. (우리가 WPF로 전환해야한다고 주장하지 마십시오. 지금은 옵션이 아닙니다.)

질문 :

  • WinForms에서 무엇을 자동 확장 할 수 없으므로 피해야합니까?

  • WinForms 코드를 작성할 때 프로그래머는 어떤 설계 지침을 따라야 자동 확장이 잘됩니까?

지금까지 식별 한 설계 지침 :

아래의 커뮤니티 위키 답변을 참조하십시오 .

잘못되었거나 부적절한 것이 있습니까? 우리가 채택해야 할 다른 지침이 있습니까? 피해야 할 다른 패턴이 있습니까? 이것에 대한 다른 지침은 대단히 감사하겠습니다.

답변:


127

스케일링을 제대로 지원하지 않는 컨트롤 :

  • Label함께 AutoSize = False하고 Font상속. Font컨트롤에 명시 적으로 설정 되어 속성 창에 굵게 표시됩니다.
  • ListView열 너비는 조정되지 않습니다. ScaleControl대신 양식을 재정의하십시오 . 이 답변을 참조하십시오
  • SplitContainerPanel1MinSize, Panel2MinSizeSplitterDistance특성
  • TextBox함께 MultiLine = True하고 Font상속. Font컨트롤에 명시 적으로 설정 되어 속성 창에 굵게 표시됩니다.
  • ToolStripButton님의 이미지. 폼의 생성자에서 :

    • 세트 ToolStrip.AutoSize = False
    • 설정 ToolStrip.ImageScalingSize에 따라 CreateGraphics.DpiX.DpiY
    • ToolStrip.AutoSize = True필요한 경우 설정하십시오 .

    때로는 AutoSize남아있을 수 True있지만 때로는 이러한 단계가 없으면 크기가 조정되지 않습니다. 와 그 변경없이 작동 .NET 프레임 워크 4.5.2EnableWindowsFormsHighDpiAutoResizing.

  • TreeView님의 이미지. 및 ImageList.ImageSize에 따라 설정하십시오 . 들어 와 그 변화없이 작동 .NET 프레임 워크 4.5.1 와 .CreateGraphics.DpiX.DpiYStateImageListEnableWindowsFormsHighDpiAutoResizing
  • Form의 크기입니다. Form생성 후 고정 크기를 수동으로 조정합니다 .

설계 지침 :

  • 모든 ContainerControls는 동일하게 설정해야합니다 AutoScaleMode = Font. 글꼴은 DPI 변경 및 시스템 글꼴 크기 설정 변경을 모두 처리하며 DPI는 시스템 글꼴 크기 설정 변경이 아닌 DPI 변경 만 처리합니다.

  • AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);96dpi (다음 글 머리 기호 참조)와 MS Sans Serif의 기본 글꼴 (글 머리 기호 2 아래 참조)을 가정하면 모든 ContainerControls도 동일하게 설정해야합니다 . 디자이너를 여는 DPI를 기반으로 디자이너가 자동으로 추가하지만 가장 오래된 디자이너 파일에서 누락되었습니다. 아마도 Visual Studio .NET (VS 2005 이전 버전)이 제대로 추가하지 않았을 것입니다.

  • 모든 디자이너 작업을 96dpi로 수행하십시오 (120dpi로 전환 할 수는 있지만 인터넷상의 지혜는 96dpi를 고수한다고 말합니다. 실험은 순서대로 진행됩니다. 설계 상으로는 단순히 AutoScaleDimensions라인을 변경하기 때문에 중요하지 않습니다) 디자이너 삽입). 고해상도 디스플레이에서 가상 96dpi로 실행되도록 Visual Studio를 설정하려면 해당 .exe 파일을 찾아 마우스 오른쪽 단추로 클릭하여 속성을 편집 한 다음 호환성에서 "높은 DPI 스케일링 동작 무시 : 시스템에서 스케일링 수행"을 선택하십시오.

  • 컨테이너 수준에서 글꼴을 설정하지 마십시오 .MS Sans Serif 이외의 응용 프로그램 전체 기본 글꼴을 원할 경우 리프 컨트롤에서만 또는 가장 기본 양식의 생성자에서 리프 컨트롤에서만. 컨테이너에서 글꼴을 설정하면 해당 컨테이너의 자동 크기 조정 기능이 알파벳순으로 표시되므로 알파벳순으로 AutoScaleMode 및 AutoScaleDimensions 설정을 수행하므로 해당 컨테이너의 자동 크기 조정 기능이 해제 된 것 같습니다. 6x13과 다르게 계산하는 AutoScaleDimensions; 특히 Segoe UI (Win 10 기본 글꼴)로 변경하면 7x15가됩니다. Designer의 모든 양식을 터치하여 .designer 파일의 모든 치수를 다시 계산할 수 있도록해야합니다. AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);.

  • 앵커를 사용 Right하거나 BottomUserControl에 고정 하지 마십시오. 위치 조정이 자동 스케일되지 않습니다. 대신, 패널 또는 다른 컨테이너를 UserControl에 놓고 다른 컨트롤을 해당 패널에 고정하십시오. 독 패널의 사용이 Right, Bottom또는 Fill당신의 UserControl에 있습니다.

  • 컨트롤 ResumeLayout이 끝날 때 컨트롤 목록의 컨트롤 만 InitializeComponent자동으로 조정됩니다. 컨트롤을 동적으로 추가 한 경우 컨트롤 SuspendLayout(); AutoScaleDimensions = new SizeF(6F, 13F); AutoScaleMode = AutoScaleMode.Font; ResumeLayout();을 추가하기 전에 해당 컨트롤을 사용해야합니다. 그리고 위치도 조정해야합니다. 당신이 독 모드 또는 같은 레이아웃 관리자를 사용하지 않는 경우 FlowLayoutPanel또는 TableLayoutPanel.

  • 파생 된 기본 클래스 ContainerControl는로 AutoScaleMode설정 해야 합니다 Inherit(클래스에 설정된 기본값 ContainerControl; 디자이너가 설정 한 기본값은 아님). 다른 것으로 설정 한 다음 파생 클래스에서 글꼴로 설정하려고 시도하면 (필요한 경우) Font디자이너의 설정을 지우도록 설정하는 행위가 AutoScaleDimensions실제로 자동 스케일링을 토글합니다! (이 가이드 라인과 이전 가이드 라인은 디자이너에서 기본 클래스를 인스턴스화 할 수 없음을 의미합니다. 모든 클래스는 기본 클래스 또는 리프 클래스로 설계되어야합니다!)

  • Form.MaxSizeDesigner에서 정적으로 사용하지 마십시오 . MinSize그리고 MaxSize폼에는 다른 모든 것만 큼 확장되지 않습니다. 따라서 96dpi에서 모든 작업을 수행하면 DPI가 높을 때 MinSize문제가 발생하지 않지만 예상대로 제한되지는 않지만 MaxSize크기의 크기 조정이 제한되어 문제가 발생할 수 있습니다. 원하는 경우 MinSize == Size == MaxSizeDesigner에서 수행하지 마십시오. 생성자 또는 OnLoad재정의 에서 수행하십시오. MinSizeMaxSize적절한 크기의 크기로 설정하십시오.

  • 특정의 모든 컨트롤 Panel또는 Container고정 또는 도킹을 사용해야합니다. 그것들을 혼합하면, 그에 의해 수행되는 자동 스케일링 Panel은 종종 미묘한 기묘한 방식으로 오작동합니다.

  • 자동 크기 조정을 수행하면 전체 양식의 크기를 조정하려고 시도하지만 해당 프로세스에서 화면 크기의 상한선에 도달하면 하드 제한이 적용됩니다 (클립). 스케일링. 따라서 Designer의 100 % / 96dpi 크기의 모든 양식 크기가 1024x720 (1080p 화면의 150 % 또는 4K 화면의 Windows 권장 값인 300 %)보다 크지 않아야합니다. 그러나 거대한 Win10 타이틀 / 캡션 바를 빼야합니다 .1000x680 최대 크기와 비슷합니다. 디자이너의 경우 994x642 ClientSize와 같습니다. (따라서 ClientSize에서 FindAll References를 수행하여 위반자를 찾을 수 있습니다.)


NumericUpDownMargin제대로 확장되지 않습니다 . 여백이 두 번 조정 된 것 같습니다. 한 번 축소하면 좋아 보입니다.
ygoe 2016 년

AutoScaleMode = Font매우 큰 글꼴을 사용하고 Ubuntu를 사용하는 사용자에게는 제대로 작동하지 않습니다. 우리는 선호합니다AutoScaleMode = DPI
KindDragon

> MultiLine = True이고 Font가 상속 된 TextBox. 하루 종일 미쳐가는 것이 그 해결책이었습니다! 정말 고마워! 그건 그렇고, 같은 수정은 또한 ListBox 컨트롤에 대한 수정입니다. : D
neminem

저에게 상속 된 글꼴이있는 목록 상자는 확장 성이 좋지 않습니다. 그들은 명시 적으로 설정 한 후에 수행합니다. (.NET 4.7)
PulseJet


27

내 경험은 현재 가장 많이 투표 된 답변과 상당히 다릅니다. .NET 프레임 워크 코드를 단계별로 실행하고 참조 소스 코드를 숙독함으로써 모든 것이 자동 스케일링이 작동하고 있으며 어딘가에 미묘한 문제가 있다고 결론 내 렸습니다. 이것은 사실로 밝혀졌습니다.

적절하게 리플 로우 가능 / 자동 크기의 레이아웃을 만들면 Visual Studio에서 사용하는 기본 설정 (즉, 부모 폼의 AutoSizeMode = Font 및 다른 모든 것의 상속)을 사용하여 거의 모든 것이 자동으로 정확하게 작동합니다.

디자이너의 양식에서 Font 속성을 설정 한 경우 유일한 문제입니다. 생성 된 코드는 할당을 사전 순으로 정렬하므로 이전에AutoScaleDimensions 할당됩니다 . 불행히도, 이것은 WinForms 자동 스케일링 로직을 완전히 파괴합니다. Font

그래도 수정은 간단합니다. Font디자이너에서 속성을 전혀 설정하지 않거나 (양식 생성자에서 설정) 수동으로 이러한 할당을 재정렬하십시오 (그러나 디자이너에서 양식을 편집 할 때마다 계속 수행해야 함). Voila, 최소한의 번거 로움없이 완벽하고 완벽한 자동 스케일링. 양식 크기도 올바르게 조정됩니다.


알려진 문제는 다음과 같습니다.

  • 중첩은 TableLayoutPanel 제어 여백을 잘못 계산 합니다. 여백과 패딩을 피하거나 중첩 된 테이블 레이아웃 패널을 피하는 것으로 알려진 해결 방법은 없습니다.

1
Font디자이너에서 설정 안 함 : 생각이 떠 오릅니다. 디자이너에서 글꼴을 설정하여 원하는 글꼴로 디자인 할 수 있습니다. 그런 다음 생성자에서 레이아웃 후 해당 글꼴 속성을 읽고 동일한 값을 다시 설정합니까? 아니면 레이아웃을 다시 수행하도록 요청할 수 있습니까? [주의 :이 접근법을 테스트 할 이유가 없었습니다.] 또는 Knowleech의 대답 에 따라 디자이너는 픽셀로 지정하고 (Visual Studio 디자이너는 높은 DPI 모니터에서 크기를 조정하지 않음) 코드에서 해당 값을 읽으면 픽셀에서 변환됩니다 (정확한 스케일링을 얻기 위해).
ToolmakerSteve

1
코드의 모든 단일 비트는 자동 스케일 모드 직전에 설정된 자동 스케일 치수를 가지며 모든 스케일이 완벽하게 스케일됩니다. 대부분의 경우 순서가 중요하지 않은 것 같습니다.
Josh

최상위 답변에서 권장대로 AutoScaleDimensions설정되지 않은 인스턴스에 대한 코드를 검색했습니다 new SizeF(6F, 13F). 모든 경우에 폼의 Font 속성이 설정되었습니다 (기본값 아님). 그것은 나타납니다 때 AutoScaleMode = Font, 다음 AutoScaleDimensions폼의 글꼴 속성을 기준으로 계산됩니다. 또한 Windows 제어판배율 설정 이에 영향을주는 것 같습니다 . AutoScaleDimensions
Walter Stabosz

24

.Net Framework 4.7 용 응용 프로그램을 대상으로 지정하고 Windows 10 v1703 (Creators Update Build 15063)에서 실행하십시오. 함께 윈도우 10 (v1703)에서 닷넷 4.7, MS는 DPI 개선을 많이했다 .

.NET Framework 4.7부터 Windows Forms에는 일반적인 높은 DPI 및 동적 DPI 시나리오를위한 향상된 기능이 포함되어 있습니다. 여기에는 다음이 포함됩니다.

  • MonthCalendar 컨트롤 및 CheckedListBox 컨트롤과 같은 여러 Windows Forms 컨트롤의 확장 및 레이아웃이 향상되었습니다.

  • 단일 패스 스케일링. .NET Framework 4.6 및 이전 버전에서는 여러 단계를 통해 스케일링이 수행되어 일부 컨트롤이 필요한 것보다 더 스케일링되었습니다.

  • Windows Forms 응용 프로그램이 시작된 후 사용자가 DPI 또는 배율을 변경하는 동적 DPI 시나리오 지원

이를 지원하려면 응용 프로그램 매니페스트를 응용 프로그램에 추가하고 응용 프로그램이 Windows 10을 지원한다는 신호를 보내십시오.

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

다음으로 app.configPer Monitor Aware 앱을 추가 하고 선언하십시오. 이것은 이제 app.config에서 수행되며 이전과 같은 매니페스트에서는 수행되지 않습니다!

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

PerMonitorV2 는 Windows 10 Creators Update 이후 새로 추가되었습니다.

DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2

Per Monitor v2라고도합니다. 응용 프로그램이 최상위 창 단위로 새로운 DPI 관련 스케일링 동작에 액세스 할 수 있도록 원래 모니터 별 DPI 인식 모드를 개선했습니다.

  • 하위 창 DPI 변경 알림 -Per Monitor v2 컨텍스트에서 전체 창 트리에 발생하는 DPI 변경이 통지됩니다.

  • 비 클라이언트 영역 확장 -모든 창에는 비 클라이언트 영역이 DPI에 민감한 방식으로 자동 그려집니다. EnableNonClientDpiScaling에 대한 호출은 필요하지 않습니다.

  • S 는 Win32 메뉴의 caling - 당 모니터 v2의 맥락에서 생성 된 모든 NTUSER 메뉴는 당 모니터 방식으로 확장 될 것입니다.

  • 대화 상자 스케일링 -Per Monitor v2 컨텍스트에서 작성된 Win32 대화 상자는 DPI 변경에 자동으로 응답합니다.

  • comctl32 컨트롤의 향상된 스케일링 -다양한 comctl32 컨트롤이 Per Monitor v2 컨텍스트에서 향상된 DPI 스케일링 동작을 갖습니다.

  • 향상된 테마 동작 -Per Monitor v2 창의 컨텍스트에서 열린 UxTheme 핸들은 해당 창과 연관된 DPI 측면에서 작동합니다.

이제 3 개의 새로운 이벤트를 구독하여 DPI 변경에 대한 알림을받을 수 있습니다.

  • Control.DpiChangedAfterParent ( 발사 됨) 컨트롤의 부모 컨트롤이나 폼에 대한 DPI 변경 이벤트가 발생한 후 컨트롤의 DPI 설정이 프로그래밍 방식으로 변경되면 발생합니다.

  • Control.DpiChangedBeforeParent- 부모 컨트롤이나 폼에 대한 DPI 변경 이벤트가 발생하기 전에 컨트롤의 DPI 설정이 프로그래밍 방식으로 변경되면 시작됩니다.

  • Form.DpiChanged . 양식이 현재 표시된 디스플레이 장치에서 DPI 설정이 변경되면 시작됩니다.

DPI 처리 / 확장에 대한 3 가지 도우미 방법도 있습니다.

  • Control.LogicalToDeviceUnits- 값을 논리에서 장치 픽셀로 변환합니다.

  • Control.ScaleBitmapLogicalToDevice- 비트 맵 이미지를 장치의 논리적 DPI로 조정합니다.

  • Control.DeviceDpi- 현재 장치의 DPI를 반환합니다.

여전히 문제가 표시되면 app.config 항목을 통해 DPI 개선 사항을 옵트 아웃 할 수 있습니다 .

소스 코드에 액세스 할 수없는 경우 Windows 탐색기에서 응용 프로그램 속성으로 이동하여 호환성으로 이동하여 System (Enhanced)

여기에 이미지 설명을 입력하십시오

DPI 처리를 향상시키기 위해 GDI 스케일링을 활성화합니다.

GDI 기반 Windows 응용 프로그램의 경우 이제 모니터별로 DPI를 확장 할 수 있습니다. 즉, 이러한 응용 프로그램은 마술처럼 모니터 당 DPI를 인식하게됩니다.

이러한 모든 단계를 수행하면 WinForms 응용 프로그램에 대해 더 나은 DPI 경험을 얻을 수 있습니다. 그러나 .net 4.7 용 앱을 대상으로하고 Windows 10 Build 15063 (Creators Update) 이상이 필요합니다. 다음 Windows 10 업데이트 1709에서는 더 많은 기능이 개선 될 수 있습니다.


12

내가 직장에서 쓴 가이드 :

WPF는 '장치 독립 장치'에서 작동하므로 모든 컨트롤이 높은 dpi 화면으로 완벽하게 확장됩니다. WinForms에서는 더 많은주의가 필요합니다.

WinForms는 픽셀 단위로 작동합니다. 텍스트는 시스템 dpi에 따라 크기가 조정되지만 크기가 조절되지 않은 컨트롤에 의해 종종 잘립니다. 이러한 문제를 피하려면 명시적인 크기와 위치를 피해야합니다. 다음 규칙을 따르십시오.

  1. 찾은 곳 (레이블, 버튼, 패널)에서 AutoSize 속성을 True로 설정하십시오.
  2. 레이아웃의 경우 바닐라 패널 대신 FlowLayoutPanel (la WPF StackPanel) 및 TableLayoutPanel (la WPF Grid)을 레이아웃으로 사용하십시오.
  3. 고 dpi 시스템에서 개발하는 경우 Visual Studio 디자이너는 실망 스러울 수 있습니다. AutoSize = True를 설정하면 화면 크기에 맞게 컨트롤의 크기가 조정됩니다. 컨트롤에 AutoSizeMode = GrowOnly가있는 경우 일반 dpi에있는 사람에게는이 크기가 유지됩니다. 예상보다 큽니다. 이 문제를 해결하려면 일반적인 dpi로 컴퓨터에서 디자이너를 열고 마우스 오른쪽 버튼을 클릭하고 재설정하십시오.

3
모든 크기에서 AutoSize를 조정할 수있는 대화 상자의 경우 악몽이 될 수 있습니다. 프로그램을 실행하는 동안 대화 상자 크기를 수동으로 늘리면 단추가 커지고 작아지는 것을 원하지 않습니다.
Josh

10

높은 DPI로 WinForms를 재생하기가 매우 어렵다는 것을 알았습니다. 그래서 양식 동작을 재정의하는 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

최근 에이 문제가 발생했습니다. 특히 편집기가 고 DPI 시스템에서 열릴 때 Visual Studio 크기 조정과 함께 사용되었습니다. 유지 하는 것이 가장 AutoScaleMode = Font좋지만 양식 글꼴 을 기본 글꼴 로 설정하는 것이 좋지만 포인트가 아닌 픽셀 단위로 크기를 지정하십시오Font = MS Sans; 11px . 코드에서, 나는 다음 기본값으로 글꼴을 재설정 : Font = SystemFonts.DefaultFont모든 괜찮습니다.

내 두 센트. 내가 공유하는 줄 알았는데“AutoScaleMode = Font 유지”“디자이너의 글꼴 크기를 픽셀 단위로 설정” 이 인터넷에서 찾지 .

내 블로그에 대한 자세한 내용이 있습니다 : http://www.sgrottel.de/?p=1581&lang=en


4

앵커가 잘 작동하지 않는 것 외에도 한 걸음 더 나아가서 위치 지정 속성을 사용하는 정확한 위치 지정이 글꼴 크기 조정에서 잘 작동하지 않는다고 말합니다. 두 가지 프로젝트에서이 문제를 해결해야했습니다. 둘 다에서 모든 WinForms 컨트롤의 위치를 ​​TableLayoutPanel 및 FlowLayoutPanel을 사용하여 변환해야했습니다. TableLayoutPanel 내에서 Dock (보통 채우기로 설정 됨) 속성을 사용하면 시스템 글꼴 DPI로 잘 작동하고 잘 확장됩니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.