GUI를 설계하고 구현하기위한 일종의 체계적인 전략이 있습니까?


18

Visual Studio를 사용하여 C #에서 GUI 응용 프로그램을 만들고 있습니다. 도구 상자는 멋진 구성 요소 팔레트 역할을하여 버튼과 다른 요소 ( "제어"를 의미 할 때마다 버튼이라고 명료 함)를 양식에 쉽게 끌어서 놓을 수있어 정적 양식을 매우 쉽게 수행 할 수 있습니다. 그러나 두 가지 문제가 발생합니다.

  • 처음에 버튼을 만드는 것은 많은 작업입니다. 정적이 아닌 양식이있는 경우 (예 : 사용자의 작업에 따라 버튼 또는 기타 컨트롤이 런타임에 작성 됨) 팔레트를 전혀 사용할 수 없습니다. 대신 사용중인 모든 메소드에서 생성자를 호출하여 각 버튼을 수동으로 생성 한 다음 버튼 높이, 너비, 위치, 레이블, 이벤트 핸들러 등을 지정하여 수동으로 초기화해야합니다. 폼의 모양을 보지 않고 이러한 모든 미용 매개 변수를 추측해야하기 때문에 매우 지루하고 각 버튼마다 반복되는 많은 코드가 생성됩니다.
  • 버튼으로 무언가를하는 것도 많은 작업입니다. 모든 기능을 갖춘 응용 프로그램에서 이벤트를 처리하는 것은 큰 고통입니다. 내가하는 방법을 아는 유일한 방법은 버튼을 선택하고 속성의 이벤트 탭으로 이동하여 이벤트를 클릭하여 코드 OnClick에서 이벤트를 생성 한 다음 이벤트 Form본문을 채우는 것입니다. 논리와 프리젠 테이션을 분리하려고하므로 모든 이벤트 핸들러는 결국 적절한 비즈니스 논리 기능에 대한 단일 행 호출이됩니다. 그러나 많은 버튼에 이것을 사용하면 (예를 들어, MS Word와 같은 응용 프로그램에 존재하는 버튼의 수를 상상해보십시오) 내 코드 Form를 수십 개의 상용구 이벤트 처리기 메소드로 오염 시키므로 이것을 유지하기가 어렵습니다.

이 때문에 Hello World보다 복잡한 GUI 프로그램은 실제로 저에게 실제로 비현실적입니다. 분명히, 나는 UI가 최소한 인 프로그램의 복잡성을 다루는 데 아무런 문제가 없습니다. 비즈니스 로직 코드를 깔끔하게 구성하기 위해 상당한 수준의 역량으로 OOP를 사용할 수 있다고 생각합니다. 그러나 GUI를 개발할 때 나는 붙어 있습니다. 바퀴를 재발 명하는 것처럼 지루한 것처럼 보이며, 읽지 않은 GUI를 올바르게 수행하는 방법을 설명하는 책이 있습니다.

뭔가 빠졌습니까? 아니면 모든 C # 개발자가 반복적 인 이벤트 처리기 및 버튼 생성 코드의 끝없는 목록을 수락합니까?


(희망스럽게 도움이되는) 힌트로서, 나는 좋은 대답이 다음에 대해 이야기 할 것으로 기대합니다.

  • 반복되는 버튼 생성을 단순화하기 위해 OOP 기술 (예 : 팩토리 패턴) 사용
  • 많은 이벤트 핸들러를 단일 메소드로 결합하여 Sender호출 한 단추 를 확인 하고 그에 따라 작동
  • XAML 및 Windows Forms 대신 WPF 사용

당신은하지 않습니다 물론,이 중 하나를 언급. 내가 어떤 종류의 답변을 찾고 있는지에 대한 최선의 추측 일뿐입니다.


내가 볼 수 있듯이 공장은 좋은 패턴 일 것이지만 이벤트 대신 컨트롤에 명령이 연결된 모델보기 컨트롤러 패턴이 훨씬 더 많습니다. WPF는 일반적으로 MVVM이지만 MVC가 가능합니다. 현재 WVC에는 MVC를 90 %로 사용하는 거대한 소프트웨어가 있습니다. 모든 명령은 컨트롤러로 전달되며 모든 것을 처리합니다
Franck

GUI 편집기를 사용하여 가능한 모든 버튼으로 동적 양식을 작성하고 동적으로 보이지 않는 것을 만들 수 없습니까? 훨씬 적은 작업처럼 들립니다.
Hans-Peter Störr 2016 년

@hstoerr 그러나 레이아웃이 작동하기 어렵습니다. 많은 버튼이 겹칠 것입니다.
Superbest

답변:


22

UI 프레임 워크가 최근 몇 년 동안 해결해야했던 두 가지 주요 문제인 앞서 언급 한 이러한 문제를 해결하기 위해 수년에 걸쳐 진화 한 몇 가지 방법론이 있습니다. WPF 배경에서 나오면 다음과 같이 접근합니다.

명령이 아닌 선언적 디자인

컨트롤을 인스턴스화하고 속성을 설정하기 위해 코드를 작성하는 데 어려움을 겪을 때 UI 디자인의 필수 모델을 설명합니다. WinForms 디자이너를 사용하더라도 해당 모델 위에 래퍼를 사용하고 있습니다. Form1.Designer.cs 파일을 열면 해당 코드가 모두 표시됩니다.

WPF 및 XAML과 HTML 이후의 다른 프레임 워크의 유사한 모델을 사용하면 레이아웃을 설명하고 프레임 워크가이를 구현하는 데 많은 도움이됩니다. UI 요소 사이의 관계를 설명하기 위해 패널 (Grid 또는 WrapPanel 등)과 같은 더 스마트 한 컨트롤을 사용하지만 수동으로 배치하지 않을 것으로 예상됩니다. ASP.NET의 Repeater 또는 WPF의 ItemsControl과 같은 반복 가능한 컨트롤과 같은 유연한 개념을 사용하면 반복적 인 코드를 작성하지 않고도 동적으로 확장 가능한 UI를 만들 수 있으므로 동적으로 증가하는 데이터 엔터티를 동적으로 컨트롤로 표현할 수 있습니다.

WPF의 DataTemplates를 사용하면 UI의 장점에 대한 작은 덩어리를 다시 선언적으로 정의하여 데이터와 일치시킬 수 있습니다. 예를 들어 Customer 데이터 개체 목록은 ItemsControl에 바인딩 될 수 있으며 정규 직원 (이름과 주소가있는 표준 그리드 행 템플릿 사용)인지 Prime Customer인지에 따라 다른 데이터 템플릿이 호출 될 수 있습니다. , 사진과 함께 사용하기 쉬운 버튼이 표시됩니다. 다시 말하지만, 특정 창에 코드를 작성하지 않고도 데이터 컨텍스트를 인식하는 똑똑한 컨트롤만으로 데이터에 바인딩하여 관련 작업을 수행 할 수 있습니다.

데이터 바인딩 및 명령 분리

WPF의 데이터 바인딩 및 AngularJS와 같은 다른 프레임 워크에서 데이터 바인딩을 만지면 컨트롤 (예 : 텍스트 상자)을 데이터 엔터티 (예 : 고객 이름)와 연결하여 의도를 진술 할 수 있습니다. 프레임 워크는 배관을 처리합니다. 논리도 비슷하게 처리됩니다. 코드 숨김 이벤트 처리기를 컨트롤러 기반 비즈니스 논리에 수동으로 연결하는 대신 데이터 바인딩 메커니즘을 사용하여 컨트롤러의 동작 (예 : 단추의 Command 속성)을 활동의 너깃을 나타내는 Command 객체에 연결합니다.

매번 이벤트 핸들러를 다시 작성하지 않고도이 명령을 창간에 공유 할 수 있습니다.

더 높은 추상화 수준

두 가지 문제에 대한이 두 가지 솔루션은 모두 합리적으로 귀찮은 Windows Forms의 이벤트 중심 패러다임보다 더 높은 수준의 추상화로의 이동을 나타냅니다.

아이디어는 코드에서 컨트롤이 갖는 모든 단일 속성과 버튼 클릭부터 시작하여 모든 단일 동작을 정의하고 싶지 않다는 것입니다. 컨트롤과 기본 프레임 워크가 더 많은 작업을 수행하고보다 추상적 인 데이터 바인딩 개념 (WinForms에는 있지만 WPF에서 거의 유용하지 않음)과 UI 사이의 링크를 정의하는 명령 패턴에 대해 생각할 수 있기를 원합니다. 그리고 금속으로 내려갈 필요가없는 행동.

MVVM의 패턴이 패러다임에 대한 마이크로 소프트의 접근 방식입니다. 나는 그것에 대해 읽는 것이 좋습니다.

이것은이 모델의 모양과 시간과 코드를 절약하는 방법에 대한 대략적인 예입니다. 이것은 컴파일되지 않지만 의사 WPF입니다. :)

애플리케이션 리소스 어딘가에 데이터 템플릿을 정의합니다.

<DataTemplate x:DataType="Customer">
   <TextBox Text="{Binding Name}"/> 
</DataTemplate>

<DataTemplate x:DataType="PrimeCustomer">
   <Image Source="GoldStar.png"/>
   <TextBox Text="{Binding Name}"/> 
</DataTemplate>

이제 기본 화면을 데이터를 노출하는 클래스 인 ViewModel에 연결합니다. Customers (간단히 a List<Customer>) 및 Command 객체 (다시 말해서 유형의 간단한 공용 속성) 모음입니다 ICommand. 이 링크는 바인딩을 허용합니다.

public class CustomersnViewModel
{
     public List<Customer> Customers {get;}
     public ICommand RefreshCustomerListCommand {get;}  
}

그리고 UI :

<ListBox ItemsSource="{Binding Customers}"/>
<Button Command="{Binding RefreshCustomerListCommand}">Refresh</Button>

그리고 그게 다야. ListBox의 구문은 ViewModel에서 고객 목록을 가져 와서 UI에 렌더링하려고 시도합니다. 앞서 정의한 두 개의 DataTemplate 때문에 PrimeCustomer가 Customer에서 상속한다고 가정하면 DataType을 기반으로 관련 템플릿을 가져 와서 ListBox의 내용으로 넣습니다. 코드를 통한 루핑, 동적 생성 제어가 없습니다.

마찬가지로 Button에도 기존 구문이있어 해당 동작을 ICommand 구현에 연결합니다.이 명령은 Customers속성 을 업데이트하는 것으로 알고 있으며 데이터 바인딩 프레임 워크에서 UI를 자동으로 다시 업데이트하도록합니다.

물론 여기에 몇 가지 지름길을 취했지만 이것이 요점입니다.


5

먼저이 기사 시리즈를 추천합니다 : http://codebetter.com/jeremymiller/2007/07/26/the-build-your-own-cab-series-table-of-contents/- 자세한 문제는 다루지 않습니다. 버튼 코드를 사용하여 고유 한 응용 프로그램 프레임 워크, 특히 GUI 응용 프로그램을 설계하고 구현하기위한 체계적인 전략을 제공하여 일반적인 Forms 응용 프로그램에 MVC, MVP, MVVM을 적용하는 방법을 보여줍니다.

"이벤트 처리"에 대한 질문 해결 : 비슷한 방식으로 작동하는 단추가있는 양식이 많으면 "응용 프로그램 프레임 워크"에서 이벤트 처리기 할당을 직접 구현하는 것이 좋습니다. GUI 디자이너를 사용하여 클릭 이벤트를 할당하는 대신 특정 이름의 버튼에 대해 "클릭"핸들러 의 이름을 지정 하는 방법에 대한 명명 규칙을 작성 하십시오. 예를 들어 MyNiftyButton_ClickHandler, 단추의 단추 MyNiftyButton입니다. 그런 다음 폼의 모든 버튼을 반복하는 재사용 가능한 루틴 (리플렉션 사용)을 작성하는 것이 어렵지 않습니다. 폼에 관련 클릭 처리기가 포함되어 있는지 확인하고 처리기를 자동으로 이벤트에 할당하십시오. 예를 보려면 여기 를 참조 하십시오 .

그리고 많은 버튼에 대해 하나의 이벤트 핸들러 만 사용하려는 경우 가능합니다. 각 이벤트 핸들러는 발신자를 전달하고 발신자는 항상 누른 단추이므로 각 단추의 "이름"특성을 사용하여 비즈니스 코드로 디스패치 할 수 있습니다.

버튼 (또는 다른 컨트롤)의 동적 생성 : 템플릿 을 사용하기 위해 디자이너가 사용하지 않는 양식으로 버튼 또는 다른 컨트롤을 생성 할 수 있습니다 . 그런 다음 리플렉션 ( 예 : 여기 참조 )을 사용하여 템플릿 컨트롤을 복제하고 위치 또는 크기와 같은 속성 만 변경합니다. 코드에서 2 ~ 3 개의 속성을 수동으로 초기화하는 것보다 훨씬 간단 할 것입니다.

Winforms를 염두에 두어 위의 내용을 썼지 만 (일반적으로 생각 하듯이) 일반적인 원칙은 비슷한 기능을 가진 WPF와 같은 다른 GUI 환경에 적용해야합니다.


실제로 WPF에서 할 수 있으며 훨씬 쉽습니다. 명령 목록 (사전 코딩 된 특정 기능)을 채우고 창에서 소스를 설정하기 만하면됩니다. 멋진 간단한 시각적 템플릿을 만들고 원하는 명령으로 컬렉션을 채우는 것만으로도 훌륭한 WPF 바인딩을 통해 나머지를 시각적으로 관리 할 수 ​​있습니다.
Franck
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.