공통 기능을 공유 할 Windows 양식을위한 최고의 디자인


20

과거에는 상속을 사용하여 응용 프로그램에서 Windows 양식을 확장 할 수있었습니다. 모든 양식에 공통 컨트롤, 아트 워크 및 기능이있는 경우 공통 컨트롤 및 기능을 구현하는 기본 양식을 만든 다음 다른 컨트롤이 해당 기본 양식에서 상속 할 수 있습니다. 그러나 그 디자인에 몇 가지 문제가 있습니다.

  1. 컨트롤은 한 번에 하나의 컨테이너에만있을 수 있으므로 정적 컨트롤은 까다로울 수 있습니다. 예를 들어,이 클래스의 다른 모든 파생 인스턴스가 동일한 TreeView를 수정하고 표시 할 수 있도록 보호하고 정적으로 만드는 TreeView를 포함하는 BaseForm이라는 기본 양식이 있다고 가정하십시오. TreeView는 한 번에 하나의 컨테이너에만있을 수 있기 때문에 BaseForm에서 상속되는 여러 클래스에는 작동하지 않습니다. 아마도 마지막으로 초기화 된 형태 일 것입니다. 모든 인스턴스가 컨트롤을 편집 할 수 있지만 주어진 시간에 하나씩 만 표시됩니다. 물론 해결 방법이 있지만 모두 추악합니다. (이것은 나에게 정말 나쁜 디자인 인 것 같습니다. 여러 컨테이너가 동일한 객체에 대한 포인터를 저장할 수없는 이유는 무엇입니까? 어쨌든 그것이 무엇입니까.)

  2. 폼 사이의 상태, 즉 버튼 상태, 레이블 텍스트 등은 전역 변수를 사용하고로드시 상태를 재설정해야합니다.

  3. 이것은 Visual Studio의 디자이너가 실제로 잘 지원하지 않습니다.

더 우수하면서도 쉽게 유지 관리 할 수있는 디자인이 있습니까? 아니면 양식 상속이 여전히 가장 좋은 방법입니까?

업데이트 MVC에서 MVP로, 관찰자 ​​패턴에서 이벤트 패턴으로 보았습니다. 내가 지금 생각하고있는 것은 다음과 같습니다.

내 BaseForm 클래스에는 컨트롤과 해당 컨트롤에 연결된 이벤트 만 포함됩니다. 처리하기 위해 어떤 종류의 로직이 필요한 모든 이벤트는 즉시 BaseFormPresenter 클래스로 전달됩니다. 이 클래스는 UI의 데이터를 처리하고 논리 연산을 수행 한 다음 BaseFormModel을 업데이트합니다. 모델은 상태가 변경 될 때 발생하는 이벤트를 Presenter 클래스에 노출 시키며이 이벤트는 구독하거나 관찰합니다. 발표자가 이벤트 알림을 받으면 논리를 수행 한 다음 발표자가 그에 따라보기를 수정합니다.

메모리에는 각 Model 클래스 중 하나만 있지만 BaseForm과 BaseFormPresenter의 인스턴스가 많이있을 수 있습니다. 이렇게하면 BaseForm의 각 인스턴스를 동일한 데이터 모델로 동기화하는 문제가 해결됩니다.

질문 :

마지막으로 누른 버튼과 같은 항목을 저장 해야하는 레이어는 양식 사이에서 사용자를 위해 CSS 메뉴와 같이 강조 표시 할 수 있습니까?

이 디자인을 비판하십시오. 당신의 도움을 주셔서 감사합니다!


나는 왜 당신이 전역 변수를 사용 해야하는지 알지 못하지만 그렇다면 그렇다면 더 나은 접근 방법이 있어야합니다. 어쩌면 팩토리는 상속 대신 컴포지션과 결합 된 공통 구성 요소를 만들 수 있습니까?
stijn

전체 디자인에 결함이 있습니다. 원하는 것을 이미 이해하고 있다면 Visual Studio에서 지원하지 않는 것이 있습니다.
Ramhound

1
@Ramhound 그것은 비주얼 스튜디오에서 잘 지원되지 않습니다. 이것이 Microsoft가 지시하는 방법입니다. 나는 그것이 A. msdn.microsoft.com/en-us/library/aa983613(v=vs.71).aspx 에서 고통스러워 한다는 것을 알았습니다.
Jonathan Henson

@stijn 각 기본 형태로 제어 상태를 다른 인스턴스에로드하는 메소드를 가질 수 있다고 가정합니다. 즉 LoadStatesToNewInstance (BaseForm 인스턴스)입니다. 기본 형식의 새로운 형식을 보여주고 싶을 때 언제든지 호출 할 수 있습니다. form_I_am_about_to_hide.LoadStatesToNewInstance (this);
Jonathan Henson

저는 .net 개발자가 아닙니다. 포인트 1을 확장 할 수 있습니까? 나는 해결책있을 수 있습니다
이므 란 오마르 Bukhsh

답변:


6
  1. 왜 정적 컨트롤이 필요한지 모르겠습니다. 내가 모르는 것을 아실 수도 있습니다. 나는 많은 시각적 상속을 사용했지만 정적 컨트롤이 필요한 것을 본 적이 없습니다. 공통 트 리뷰 컨트롤이있는 경우 모든 폼 인스턴스에 자체 컨트롤 인스턴스 가 있고 트 리뷰에 바인딩 된 데이터 의 단일 인스턴스를 공유하십시오 .

  2. 양식간에 제어 상태를 공유하는 것 (데이터와 반대)도 특별한 요구 사항입니다. FormB에서 FormA의 단추 상태에 대해 정말로 알아야합니까? MVP 또는 MVC 디자인을 고려하십시오. 각 양식을 다른보기 나 응용 프로그램 자체에 대해서는 전혀 모르는 바보 같은 "보기"로 생각하십시오. 스마트 발표자 / 컨트롤러로 각보기를 감독하십시오. 말이된다면, 한 발표자가 여러 견해를 감독 할 수 있습니다. 상태 객체를 각보기와 연결합니다. 뷰간에 공유해야하는 상태가있는 경우 발표자가이를 중재하게하고 데이터 바인딩을 고려하십시오 (아래 참조).

  3. 동의, Visual Studio는 두통을 줄 것입니다. 양식 또는 사용자 컨트롤 상속을 고려할 때 양식 디자이너의 실망스러운 단점과 한계로 인해 레슬링의 잠재적 (및 가능한) 비용과 비교하여 이점을 신중하게 평가해야합니다. 양식 상속을 최소로 유지하는 것이 좋습니다. 급여가 높을 때만 사용하십시오. 서브 클래 싱의 대안으로 일반적인 "기본"양식을 작성하고 각 "자식"에 대해 한 번만 인스턴스화 한 후 즉시 사용자 정의 할 수 있습니다. 이것은 양식의 각 버전 간의 차이점이 공유 측면과 비교할 때 사소한 경우에 적합합니다. (IOW : 복잡한 기본 양식, 약간 더 복잡하고 복잡한 하위 양식)

UI 개발의 중복을 방지하는 데 도움이 될 때 사용자 정의 컨트롤을 사용하십시오. usercontrol 상속을 고려하지만 양식 상속과 동일한 고려 사항을 적용하십시오.

내가 제공 할 수있는 가장 중요한 조언은 현재 어떤 형태의보기 / 컨트롤러 패턴을 사용하지 않는 경우 시작하는 것이 좋습니다. 느슨한 쿠핑과 레이어 분리의 이점을 배우고 이해하게합니다.

업데이트에 대한 응답

마지막으로 누른 버튼과 같은 항목을 저장 해야하는 레이어는 사용자를 위해 강조 표시 할 수 있습니다 ...

발표자와 뷰간에 상태를 공유하는 것처럼 뷰간에 상태를 공유 할 수 있습니다. 특수 클래스 SharedViewState를 작성하십시오. 단순화하기 위해 단일 톤으로 만들거나 주 발표자에서 인스턴스화하여 (발표자를 통해) 모든 뷰에 전달할 수 있습니다. 상태가 컨트롤과 관련된 경우 가능한 경우 데이터 바인딩을 사용하십시오. 대부분의 Control속성은 데이터 바인딩 될 수 있습니다. 예를 들어 Button의 BackColor 속성은 SharedViewState 클래스의 속성에 바인딩 될 수 있습니다. 버튼이 동일한 모든 양식에 대해이 바인딩을 수행하면을 설정하여 모든 양식에서 Button1을 강조 표시 할 수 있습니다 SharedViewState.Button1BackColor = someColor.

WinForms 데이터 바인딩에 익숙하지 않은 경우 MSDN을 누르고 약간의 읽기를 수행하십시오. 어렵지 않습니다. 배우고 INotifyPropertyChanged반쯤 있습니다.

다음은 Button1BackColor 속성을 예로 들어 viewstate 클래스의 일반적인 구현입니다.

public class SharedViewState : INotifyPropertyChanged
{
    // boilerplate INotifyPropertyChanged stuff
    public event PropertyChangedEventHandler PropertyChanged;
    protected void NotifyPropertyChanged(string info)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(info));
        }
    }

    // example of a property for data-binding
    private Color button1BackColor;
    public Color Button1BackColor
    {
        get { return button1BackColor; }
        set
        {
            if (value != button1BackColor)
            {
                button1BackColor = value;
                NotifyPropertyChanged("Button1BackColor");
            }
        }
    }
}

당신의 사려 깊은 답변에 감사드립니다. 뷰 / 컨트롤러 패턴에 대한 좋은 참조를 알고 있습니까?
Jonathan Henson

1
나는 이것이이었다 생각하고 기억하고 꽤 좋은 소개 : codebetter.com/jeremymiller/2007/05/22/...
Igby Largeman

내 업데이트를 참조하십시오.
Jonathan Henson

@JonathanHenson : 답변이 업데이트되었습니다.
Igby Largeman 2016

5

MVVM 패턴 및 업데이트 컨트롤을 기반으로 새 WinForms / WPF 응용 프로그램을 유지 관리합니다 . WinForms로 시작한 다음보기 좋은 UI의 마케팅 중요성 때문에 WPF 버전을 만들었습니다. 동일한 백엔드 코드 (뷰 모델 및 모델)로 완전히 다른 두 가지 UI 기술을 지원하는 응용 프로그램을 유지 관리하는 것이 흥미로운 디자인 제약이 될 것이라고 생각했으며이 접근 방식에 상당히 만족한다고 말해야합니다.

내 응용 프로그램에서 UI의 부분간에 기능을 공유해야 할 때마다 사용자 정의 컨트롤 또는 사용자 정의 컨트롤 (WPF UserControl 또는 WinForms UserControl에서 파생 된 클래스)을 사용합니다. WinForms 버전에는 TabPage의 파생 클래스 안에있는 다른 UserControl 안에 UserControl이 있으며, 마지막으로 기본 폼의 탭 컨트롤 안에 있습니다. WPF 버전에는 실제로 UserControls가 한 수준 더 깊게 중첩되어 있습니다. 사용자 지정 컨트롤을 사용하면 앞에서 만든 UserControls에서 새 UI를 쉽게 작성할 수 있습니다.

MVVM 패턴을 사용하기 때문에 가능한 많은 프로그램 로직을 ViewModel ( Presentation / Navigation Model 포함 ) 또는 Model (코드가 사용자 인터페이스와 관련이 있는지 여부에 따라 다름)에 넣었 지만 동일한 ViewModel 이후 WinForms보기와 WPF보기에서 모두 사용되는 경우 ViewModel에는 WinForms 또는 WPF 용으로 설계되었거나 UI와 직접 상호 작용하는 코드를 포함 할 수 없습니다. 그러한 코드는 반드시보기에 들어가야합니다.

또한 MVVM 패턴에서 UI 객체는 서로 상호 작용하지 않아야합니다! 대신 뷰 모델과 상호 작용합니다. 예를 들어 TextBox는 근처의 ListBox에 어떤 항목이 선택되었는지 묻지 않습니다. 대신 목록 상자는 뷰 모델 레이어 어딘가에 현재 선택된 항목에 대한 참조를 저장하고 TextBox는 뷰 모델 레이어를 쿼리하여 현재 선택된 항목을 찾습니다. 이렇게하면 다른 양식 내에서 어떤 양식을 어떤 버튼으로 눌렀는지 찾는 문제를 해결할 수 있습니다. 두 양식간에 탐색 모델 객체 (응용 프로그램의 뷰 모델 레이어의 일부)를 공유하고 어떤 버튼을 눌렀는지 나타내는 속성을 해당 객체에 넣습니다.

WinForms 자체는 MVVM 패턴을 잘 지원하지 않지만 Update Controls 는 WinForms 위에있는 라이브러리로서 고유 한 접근 방식 MVVM을 제공합니다.

제 생각에, 프로그램 설계에 대한 이러한 접근 방식은 매우 잘 작동하며 향후 프로젝트에 사용할 계획입니다. 잘 작동하는 이유는 (1) Update Controls가 종속성을 자동으로 관리하고 (2) 일반적으로 코드를 구성하는 방법이 매우 분명하다는 것입니다. UI 개체와 상호 작용하는 모든 코드는 View에 있으며 모든 코드는 UI 관련이지만 UI 객체와 상호 작용하지 않는 것은 ViewModel에 속합니다. 종종 코드를 두 부분으로 나눕니다. 하나는 View 부분과 다른 하나는 ViewModel 부분입니다. 시스템에서 상황에 맞는 메뉴를 디자인하는 데 어려움이 있었지만 결국에는 그에 대한 디자인도 생각해 냈습니다.

나는 한 내 블로그에 업데이트 컨트롤에 대한 헛소리 가 너무. 그러나이 방법은 많은 시간이 걸리고 대규모 앱 (예 : 목록 상자에 수천 개의 항목이 포함 된 경우)에서는 자동 종속성 관리의 현재 제한으로 인해 성능 문제가 발생할 수 있습니다.


3

이미 답변을 수락했지만이 답변을 드리겠습니다.

다른 사람들이 지적했듯이, 나는 왜 정적 인 것을 사용해야하는지 이해하지 못한다. 이것은 당신이 매우 잘못하고있는 것처럼 들립니다.

어쨌든, 나는 당신과 같은 문제를 겪었습니다. WinForms 응용 프로그램에는 기능과 컨트롤을 공유하는 여러 양식이 있습니다. 또한 모든 폼은 이미 응용 프로그램에 관계없이 프레임 워크 수준의 기능을 추가하는 기본 폼 ( "MyForm"이라고 함)에서 파생됩니다. Visual Studio의 폼 디자이너는 다른 폼에서 상속되는 폼 편집을 지원하지만 연습은 "Hello, world!-OK-Cancel"이상을 수행하지 않는 한 작동합니다.

내가 끝낸 것은 이것이다. 나는 공통의 기본 클래스 인 "MyForm"을 유지하는 것이 매우 복잡하다. 그리고 나는 그것으로부터 나의 어플리케이션의 모든 폼을 계속 파생시킨다. 그러나 이러한 형식에서는 절대 아무 것도 수행하지 않으므로 VS Forms Designer에서 편집하는 데 아무런 문제가 없습니다. 이러한 양식은 양식 디자이너가 해당 양식에 대해 생성하는 코드로만 구성됩니다. 그런 다음 컨트롤 초기화, 폼 및 컨트롤에서 생성 된 이벤트 처리 등과 같은 모든 응용 프로그램 별 기능을 포함하는 "Surrogates"라고하는 별도의 병렬 계층 개체가 있습니다. 일대일이 있습니다. 내 응용 프로그램의 대리 클래스와 대화 상자 간의 통신 : "MyForm"에 해당하는 기본 대리 클래스가 있고 "MyApplicationForm"에 해당하는 다른 대리 클래스가 파생됩니다.

각 대리자는 특정 유형의 양식을 구성 시간 매개 변수로 승인하고 이벤트에 등록하여 자체적으로 첨부합니다. 또한 "MyForm"을 허용하는 "MySurrogate"까지 기본으로 위임합니다. 해당 대리자는 양식의 "Disposed"이벤트에 등록되므로 양식이 소멸 될 때 대리자가 자체에서 재정의 가능 항목을 호출하여 양식 및 모든 하위 항목이 정리를 수행 할 수 있습니다. (이벤트 등에서 등록 해제)

지금까지 잘 작동했습니다.

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