MVVM에서 ViewModel 또는 Model이 INotifyPropertyChanged를 구현해야합니까?


165

필자가 작업 한 대부분의 MVVM 예제에는 Model 구현 INotifyPropertyChanged이 있었지만 Josh Smith의 CommandSink 예제 에서는 ViewModel이 구현했습니다INotifyPropertyChanged .

나는 여전히 MVVM 개념을인지 적으로 통합하고 있으므로 다음과 같은 경우에 모르겠습니다.

  • 작업 INotifyPropertyChanged하려면 ViewModel에을 넣어야합니다 .CommandSink
  • 이것은 단지 표준의 수차이며 실제로 중요하지 않습니다.
  • 항상 Model 구현을 가져야 INotifyPropertyChanged하며 이것은 코드 예제에서 애플리케이션으로 개발 된 경우 수정되는 실수 일뿐입니다.

귀하가 작업 한 MVVM 프로젝트에 대한 다른 사람들의 경험은 무엇입니까?


4
INPC를 구현하는 경우 github.com/Fody/PropertyChanged 를 사용해보십시오. 입력하는 데 몇 주가 절약됩니다.
CAD bloke

답변:


104

나는 정반대로 말하고, 항상 INotifyPropertyChanged내 ViewModel에 배치했습니다. 와 같은 상당히 WPF 특정 기능으로 모델을 오염시키고 싶지는 않습니다 INotifyPropertyChanged.

나는 다른 사람들이 동의하지 않을 것이라고 확신하지만 그것이 내가 일하는 방식입니다.


84
모델에서 속성이 변경되면 어떻게합니까? 어떻게 든 뷰 모델에 가져와야합니다. 정직한 질문, 나는 지금이 수수께끼를 다루고 있습니다.
Roger Lipscombe

4
Prism 코드의 EventAggregator는 모델에서 INotifyPropertyChanged의 대안으로, 사용자 정의 특성이 이벤트 유형을 변경되었습니다. 해당 프로젝트의 이벤트 코드는 백그라운드와 UI 스레드 간의 이벤트 전달을 지원하며 때로는 문제가 될 수 있습니다.
Steve Mitcham

51
INotifyProperyChanged는 WPF에 한정되지 않으며 System.ComponentModel 네임 스페이스에 있으며 WinForms 응용 프로그램에서 사용했으며 INotifyPropertyChanged도 2.0 이후 .Net에있었습니다. WPF는 3.0 이후로만 사용되었습니다
benPearce

40
MODEL과 VIEWMODEL 모두에 INotifyPropertyChanged를 넣는 팬입니다. 나는 이것을하지 않는 이유를 생각할 수 없다. VIEWMODEL에 VIEWMODEL에 영향을 미치는 VIEWMODEL에 영향을 미치는 배경 변경이 발생하고 VIEWMODEL에 변경 사항이 있음을 VIEWMODEL에 알리는 우아한 방법입니다.
ScottCher

6
@Steve-ViewModel에 Model의 속성이 변경되었음을 알리는 것에 대해 INotifyPropertyChanged는 "viewmodel이 연결할 수있는 이벤트"처럼 잘 작동하는 것처럼 보입니다. 왜 사용하지 않습니까?
skybluecodeflier 2018 년

146

나는 Model이 구현해서는 안된다는 개념에 동의하지 않는다 INotifyPropertyChanged. 이 인터페이스는 UI 전용이 아닙니다! 단순히 변화를 알려줍니다. 실제로 WPF는이를 사용하여 변경 사항을 식별하지만 이것이 UI 인터페이스라는 의미는 아닙니다. 나는 다음과 같은 의견과 비교할 것이다 : " 타이어는 자동차 액세서리 ". 물론 자전거, 버스 등에서도 사용합니다. 요약하면 해당 인터페이스를 UI로 사용하지 마십시오.

그렇다고해서 반드시 모델이 알림을 제공해야한다고 믿는 것은 아닙니다. 실제로 경험상 모델은 필요하지 않은 한이 인터페이스를 구현하지 않아야합니다. 서버 데이터가 클라이언트 앱으로 푸시되지 않는 대부분의 경우 모델이 오래 될 수 있습니다. 그러나 금융 시장 데이터를 듣고 있다면 왜 모델이 인터페이스를 구현할 수 없는지 알 수 없습니다. 예를 들어, 특정 가치에 대해 입찰 또는 요청 가격을받을 때 경보 (예 : 이메일을 통해)를 발행하거나 주문하는 서비스와 같은 비 UI 논리가있는 경우 어떻게해야합니까? 이것은 가능한 깨끗한 솔루션 일 수 있습니다.

그러나 여러 가지 방법으로 달성 할 수 있지만 항상 단순성을 선호하고 중복성을 피한다고 주장합니다.

더 나은 게 뭐야? 뷰 모델에서 컬렉션 또는 속성 변경 사항에 대한 이벤트를 정의하고이를 모델에 전파하거나 뷰가 모델을 본질적으로 업데이트하도록 (뷰 모델을 통해)?

" 당신이 할 수 없다 "고 주장하는 누군가를 볼 때마다 가장 중요한 것은 그들이 말하는 것을 모르는 신호입니다.

그것은 실제로 귀하의 경우에 달려 있으며 실제로 MVVM은 많은 문제가있는 프레임 워크이며 보드 전체에서 MVVM의 일반적인 구현을 아직 보지 못했습니다.

MVVM의 다양한 특징과 일반적인 문제에 대한 해결책을 설명하는 데 더 많은 시간이 있었으면 좋겠습니다. 대부분 다른 개발자가 제공하지만 다른 시간에해야 할 것 같습니다.


7
이런 식으로 생각하십시오. 개발자가 모델과 함께 .dll을 사용하면 INotifyPropertyChanged를 지원하기 위해 .dll을 다시 쓰지 않을 것입니다.
Lee Treveil

2
당신에게 강력히 동의하십시오. 저와 마찬가지로 공식 MVVM 설명서 < msdn.microsoft.com/en-us/library/gg405484%28v=pandp.40%29.aspx > (모델 섹션)가 우리와 동의 한다는 것을 알게되어 기쁩니다 . :-)
Noldorin

"하지만 다른 방법으로 달성 할 수 있지만 항상 단순성에 찬성하여 중복성을 피해야합니다." 매우 중요.
Bastien Vandamme

1
INotifyPropertyChangedSystem.ComponentModel" 구성 요소 및 컨트롤의 런타임 및 디자인 타임 동작 "을위한 네임 스페이스의 일부입니다 . ViewModels에서만 모델에서 사용하지 마십시오 INotifyPropertyChanged . 문서 링크 : docs.microsoft.com/en-us/dotnet/api/system.componentmodel
Igor Popov

1
이전 게시물은 알고 있지만 MVVM을 사용하여 새 프로젝트를 시작할 때 종종 다시 방문합니다. 최근에 단일 책임 원칙을 훨씬 더 엄격하게 시행하기 시작했습니다. 모델은 하나의 책임이 있습니다. 모델이 되십시오. INotifyPropertyChanged를 모델에 추가하자마자 더 이상 단일 책임 원칙을 따르지 않습니다. ViewModel이 존재하는 전체 이유는 모델이 모델이되고 모델이 단일 책임을 갖도록하기 위함입니다.
Rhyous


13

MVVM의 이름이 잘못되어 ViewModel을 ViewModel이라고 부르면 많은 사람들이 잘 설계된 아키텍처의 중요한 기능을 놓치게됩니다.

View-Model을 더 많은 DataController로 생각하고 DataController가 데이터를 다루는 유일한 항목 인 아키텍처를 구현하는 경우 데이터를 직접 만지지 말고 항상 DataController를 사용하십시오. DataController는 UI에 유용하지만 반드시 UI에만 유용하지는 않습니다. 비즈니스 계층, UI 계층 등입니다.

DataModel -------- DataController ------ View
                  /
Business --------/

당신은 이런 모델로 끝납니다. 비즈니스조차도 ViewModel을 사용하여 데이터를 만져야합니다. 그러면 수수께끼가 사라집니다.


3
DataController가 데이터를 변경할 때만 데이터가 변경되면 좋습니다. 데이터가 변경을위한 또 다른 방법을 제공 할 수있는 데이터베이스 또는 다른 데이터 저장소에서 온 경우, VIEWMODEL (패턴의 DataController) 및 VIEW가 발생했을 때이를 알리는 방법이 필요할 수 있습니다. DataController를 사용하여 폴링하거나 일부 외부 프로세스에서 DataModel로 푸시하고 DataModel이 변경 알림을 DataController에 보내도록 허용 할 수 있습니다.
ScottCher

4
당신은 정확히 맞습니다. 디자인 패턴은 매우 높은 수준입니다. 대부분의 경우 디자인 패턴으로 작업을 올바르게 수행 할 수 있지만 지금은 잘못된 방향으로 전환됩니다. 디자인 패턴 외부에 있기 때문에 올바른 작업을 수행해서는 안됩니다.
Rhyous

또한 DataController가 제어하고 데이터 모델을 업데이트하고 업데이트하도록 지시 할 때 DataController에 푸시합니다.
Rhyous

또한 MVVM의 모델은 UI (예 : DTO)에서 필요에 따라 구체적으로 유지해야합니다. 따라서 DB 또는 복잡한 비즈니스 로직은 다른 계층에서 발생해야하며 뷰 모델을 통해 조잡한 데이터를 제공해야합니다.
코드 이름 Jack

9

모델을 어떻게 구현했는지에 달려 있습니다. 우리 회사는 Lhotka의 CSLA 객체와 유사한 비즈니스 객체를 사용 INotifyPropertyChanged하며 비즈니스 모델 전체에서 광범위하게 사용 합니다.

Google의 유효성 검사 엔진은이 메커니즘을 통해 속성이 변경된다는 알림을받는 데 크게 의존하며 매우 효과적입니다. 변경 알림이 조작에 중요하지 않은 비즈니스 오브젝트 이외의 다른 구현을 사용하는 경우 비즈니스 모델의 변경을 감지하는 다른 방법이있을 수 있습니다.

또한 필요한 경우 모델의 변경 사항을 전파하는 뷰 모델이 있지만 뷰 모델 자체는 기본 모델 변경 사항을 수신하고 있습니다.


3
Model의 OnPropertyChanged를 ViewModel의 OnPropertyChanged에 정확히 어떻게 전파합니까? ViewModel에 Model과 다른 속성 이름이있을 때 문제가 있습니다. 그렇다면 이름 대 이름 매핑이 필요합니다.
Martin Konicek

정말 정교하지는 않습니다. 단순히 이벤트를 전달합니다. 이름이 다르면 조회 테이블을 사용할 수 있다고 가정합니다. 변경 사항이 일대일 매핑이 아닌 경우 단순히 이벤트를 연결 한 다음 처리기에서 필요한 이벤트를 발생시킬 수 있습니다.
Steve Mitcham

6

Paulo의 답변에 동의합니다 INotifyPropertyChanged. Models 구현 은 완전히 받아 들일 수 있으며 Microsoft에서 제안합니다.

일반적으로이 모델은 뷰에 쉽게 바인딩 할 수있는 기능을 구현합니다. 이는 일반적으로 INotifyPropertyChangedINotifyCollectionChanged인터페이스를 통해 속성 및 컬렉션 변경 알림을 지원함을 의미합니다 . 객체 컬렉션을 나타내는 모델 클래스는 일반적으로 ObservableCollection<T>클래스 에서 파생되며 INotifyCollectionChanged인터페이스 의 구현을 제공합니다 .

해당 유형의 구현을 원하는지 여부를 결정하는 것은 당신에게 달려 있지만, 기억하십시오-

모델 클래스가 필요한 인터페이스를 구현하지 않으면 어떻게됩니까?

때때로 당신은 구현하지 않는 모델 객체와 함께 작동해야합니다 INotifyPropertyChanged, INotifyCollectionChanged, IDataErrorInfo, 또는 INotifyDataErrorInfo인터페이스를. 이 경우 뷰 모델은 모델 객체를 래핑하고 필요한 속성을 뷰에 노출해야 할 수 있습니다. 이러한 속성의 값은 모델 객체에 의해 직접 제공됩니다. 뷰 모델은 뷰가 데이터에 쉽게 바인딩 될 수 있도록 노출되는 속성에 필요한 인터페이스를 구현합니다.

출처 : http://msdn.microsoft.com/en-us/library/gg405484(PandP.40).aspx

나는 우리가 INotifyPropertyChanged모델에서 구현하지 않은 일부 프로젝트에서 일했으며 이로 인해 많은 문제에 직면했습니다. VM에서 불필요한 속성 복제가 필요했으며 동시에 BL / DL에 전달하기 전에 기본 개체 (업데이트 된 값으로)를 업데이트해야했습니다.

모델 객체 (예 : 편집 가능한 그리드 또는 목록) 또는 복잡한 모델의 컬렉션으로 작업해야하는 경우 특히 문제가 발생합니다. 모델 객체는 자동으로 업데이트되지 않으므로 VM에서 모든 객체를 관리해야합니다.


3

그러나 때로는 (이 프리젠 테이션 링크 텍스트 에서와 같이 ) 모델은 서비스로, 일부 데이터를 온라인으로 응용 프로그램에 제공 한 다음 새로운 데이터가 도착했거나 이벤트를 사용하여 데이터가 변경되었다는 알림을 구현해야합니다 ...


3

MV-VM을 준수하려면 대답이 분명하다고 생각합니다.

참조 : http://msdn.microsoft.com/en-us/library/gg405484(v=PandP.40).aspx

MVVM 패턴에서보기는 UI 및 모든 UI 논리를 캡슐화하고,보기 모델은 프리젠 테이션 논리 및 상태를 캡슐화하며, 모델은 비즈니스 논리 및 데이터를 캡슐화합니다.

"뷰는 데이터 바인딩, 명령 및 변경 알림 이벤트를 통해 뷰 모델과 상호 작용합니다. 뷰 모델은 모델에 대한 업데이트를 쿼리, 관찰 및 조정하고 뷰에 표시하는 데 필요한 데이터를 변환, 확인 및 집계합니다."


4
인용문은 해석하기에 열려 있습니다. 답을 명확하게하기 위해 해석을 추가해야한다고 생각합니다 :-)
Søren Boisen

@ John D :이 기사는 MVVM에 대한 해석과 구현 방법을 제공하며 MVVM을 정의하지는 않습니다.
akjoshi

또한 전체 기사를 읽으면 Model 클래스를 다음과 같이 정의합니다. "일반적으로 모델은보기에 쉽게 바인딩 할 수있는 기능을 구현합니다. 일반적으로 INotifyPropertyChanged 및 INotifyCollectionChanged 인터페이스를 통해 속성 및 컬렉션 변경 알림을 지원합니다. 개체 컬렉션을 나타내는 모델 클래스는 일반적으로 IservifyCollectionChanged 인터페이스의 구현을 제공하는 ObservableCollection <T> 클래스에서 파생됩니다. "
akjoshi

2

ViewModel에 말하고 싶습니다. 모델이 UI와 무관하므로 모델의 일부가 아닙니다. 모델은 '비즈니스에 관계없이 모든 것'이어야합니다


2

모델이 ViewModel에 명확하게 노출 된 경우 모델에서 INPC를 구현할 수 있습니다. 그러나 일반적으로 모델을 감싸는 ViewModel은 모델 복잡성을 줄이기 위해 자신의 클래스입니다 (바인딩에는 유용하지 않아야 함). 이 경우 INPC는 ViewModel에서 구현되어야합니다.


1

INotifyPropertyChange모델 에서 인터페이스를 사용하고 있습니다. 실제로 모델 속성 변경은 UI 또는 외부 클라이언트에서만 실행해야합니다.

몇 가지 장점과 단점을 발견했습니다.

장점

알리미는 비즈니스 모델에 있습니다

  1. 구동되는 도메인에 따라 맞습니다. 언제 올릴 것인지 아닌지를 결정해야합니다.

단점

이 모델에는 속성 (수량, 요금, 수수료, 총액)이 있습니다. Totalfrieght는 수량, 요금, 수수료 변경을 사용하여 계산됩니다.

  1. db에서 값을로드 할 때 총 frieght 계산을 3 회 (수량, 요율, 수수료)라고합니다. 한 번되어야합니다.

  2. 비즈니스 계층에 rate, qty가 지정된 경우 다시 알리미가 호출됩니다.

  3. 기본 클래스에서이를 비활성화하는 옵션이 있어야합니다. 그러나 개발자는이 작업을 잊어 버렸습니다.


귀하가 제시 한 모든 단점으로 인해, 우리는 모델에서 INPC를 구현하기 위해 비교적 큰 WPF 프로젝트에서 잘못된 결정이라고 결정했습니다. 지속성 계층 만 처리해야합니다. 유효성 검사, 변경 알림 및 계산 된 속성과 같은 다른 모든 사항은 ViewModel에서 처리해야합니다. 이제 ViewModel에서 모델 속성을 반복하는 것이 항상 DRY 원칙을 위반하는 것은 아니라는 것을 분명히 알고 있습니다.
try2fly.b4ucry

1

나는 그것이 모두 유스 케이스에 달려 있다고 생각합니다.

많은 속성을 가진 간단한 모델이있는 경우 INPC를 구현하도록 할 수 있습니다. 간단히 말해서이 모델은 오히려 POCO 처럼 보입니다 .

모델이 더 복잡하고 대화 형 모델 도메인 (모델을 참조하고 다른 모델의 이벤트를 구독하는 모델)에 거주하는 경우 INPC로 구현 된 모델 이벤트를 갖는 것은 악몽입니다.

다른 모델과 공동 작업을 수행해야하는 모델 엔터티의 위치에있게하십시오. 구독 할 다양한 이벤트가 있습니다. 그들 모두는 INPC로 구현됩니다. 가지고있는 이벤트 핸들러를 상상해보십시오. if-clauses 및 / 또는 switch claus의 거대한 캐스케이드.

INPC의 또 다른 문제. 구현이 아닌 추상화에 의존하도록 앱을 설계해야합니다. 이것은 일반적으로 인터페이스를 사용하여 수행됩니다.

동일한 추상화의 두 가지 다른 구현을 살펴 보겠습니다.

public class ConnectionStateChangedEventArgs : EventArgs
{
    public bool IsConnected {get;set;}
}

interface IConnectionManagerINPC : INotifyPropertyChanged
{
    string Name {get;}
    int ConnectionsLimit {get;}
    /*

    A few more properties

    */
    bool IsConnected {get;}
}

interface IConnectionManager
{
    string Name {get;}
    int ConnectionsLimit {get;}
    /*

    A few more properties

    */
    event EventHandler<ConnectionStateChangedEventArgs> ConnectionStateChanged;
    bool IsConnected {get;}
}

이제 둘 다 봅니다. IConnectionManagerINPC는 무엇을 알려줍니까? 일부 속성이 변경 될 수 있습니다. 당신은 그들 중 어느 것을 모른다. 실제로 디자인은 IsConnected 만 변경하고 나머지는 읽기 전용이므로 변경됩니다.

반대로 IConnectionManager의 의도는 분명합니다. "IsConnected 속성 값이 변경 될 수 있음을 알려줄 수 있습니다."


1

그냥를 사용하여 INotifyPropertyChange모델에서의 ViewModel에서가 아니라,

모델은 일반적으로 IDataErrorInfo유효성 검사 오류를 처리하기 위해를 사용 하므로 ViewModel을 유지하면 MVVM 도로에 있습니다.


1
여러 속성을 가진 모델은 어떻습니까? VM에서 코드를 반복하고 있습니다.
Luis

0

뷰에서 객체의 참조가 변경되었다고 가정하십시오. 올바른 값을 표시하기 위해 모든 속성을 업데이트하도록 알리는 방법은 무엇입니까? OnPropertyChanged모든 객체의 속성에 대한 당신의 견해를 부르는 것은 내 관점에 쓰레기입니다.

그래서 내가하는 일은 속성의 값이 변경 될 때 객체 자체가 누군가에게 알리도록하고 내 견해 Object.Property1에서 Object.Property2와 같은 바인딩을 사용 하는 것입니다. 그런 식으로 현재 뷰에서 유지 관리되는 객체를 변경하고 싶다면 그냥 수행하십시오 OnPropertyChanged("Object").

객체를로드하는 동안 수백 가지 알림을 피하기 위해 객체에서 확인되고 OnPropertyChanged아무것도하지 않는 로드하는 동안 true로 설정하는 개인 부울 표시기가 있습니다.


0

일반적으로 ViewModel은을 구현합니다 INotifyPropertyChanged. 모델은 무엇이든 가능합니다 (xml 파일, 데이터베이스 또는 객체). 모델은 데이터를 뷰 모델로 전달하는 데 사용되며 뷰 모델은 뷰로 전파됩니다.

여기를 보아라


1
음 .. 아니 모델은 xml 파일 또는 데이터베이스 일 수 없습니다. 그리고 모델은 데이터를 제공하는 데 사용되지 않습니다. 그렇지 않으면 "모델"이 아니라 "데이터"라고합니다 ..? 모델은 데이터를 설명하는 데 사용됩니다. 자기 설명이 아닌가? :)
타 라스

1
당신이 더 나은 답변을 가지고 있다면, pls는 공유! 우리는 모두 지식을 나누고 경쟁하지 않기 위해 여기 있습니다
Adam

0

imho 나는 viewmodel이 구현 INotifyPropertyChange하고 모델이 다른 "레벨"에서 알림을 사용할 수 있다고 생각합니다 .

예를 들어 일부 문서 서비스 및 문서 객체를 사용하면 뷰 모델이 뷰를 지우고 다시 작성하기 위해 청취하는 documentChanged 이벤트가 있습니다. 뷰 모델 편집에서 뷰를 지원하기 위해 문서의 속성에 대한 속성 변경이 있습니다. 서비스가 문서를 저장할 때 (변경 날짜, 마지막 사용자 등 업데이트) 작업을 많이 수행하는 경우 Ipropertychanged 이벤트를 쉽게 오버로드하고 문서를 변경하기 만하면됩니다.

그러나 INotifyPropertyChange모델에서 사용하는 경우 뷰에서 직접 구독하는 대신 뷰 모델에서 릴레이하는 것이 좋습니다. 이 경우 모델에서 이벤트가 변경되면 뷰 모델 만 변경하면 뷰는 그대로 유지됩니다.


0

내 뷰에 바인딩 된 모든 속성은 내 ViewModel에 있습니다. 따라서 INotifyPropertyChanged 인터페이스를 구현해야합니다. 따라서보기는 모든 변경 사항을 가져옵니다.

[MVVM Light 툴킷을 사용하여 ViewModelBase에서 상속하게했습니다.]

모델은 비즈니스 로직을 보유하지만 뷰와 관련이 없습니다. 따라서 INotifyPropertyChanged 인터페이스가 필요하지 않습니다.

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