2016-12-27 6 views
0

ViewModel에서 속성을 업데이트하는 올바른 방법 나는 WPF 꽤 초심자입니다. 모델에서 데이터가 변경되면 뷰 모델에이를 알리고 뷰는 뷰 모델에서 속성과 사물에 모두 바인딩됩니다. 이 올바른지? 나는 모델이모델에서

public class LoginModel : INotifyPropertyChanged 
{ 

    public event PropertyChangedEventHandler PropertyChanged; 

    public void NotifyPropertyChanged(string propName) 
    { 
     PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName)); 
    } 

    public bool Authenticated { get; set; } 
} 

같은 내 뷰 모델에 뭔가를 INotifyPropertyChanged을 구현하고 보이는 것을 읽어 봤는데 그렇다면, 나는 "모델 속성에서 업데이트를 받아야하는, 속성"AuthResult "가 인증 됨 "

public partial class view1 : UserControl, INotifyPropertyChanged{ 
public bool AuthResult 
    { 
     get 
     { 
      return _authVal; 
     } 
     set 
     { 
      _authVal = value; 
      NotifyPropertyChanged("AuthResult"); 
     } 
    } 

public event PropertyChangedEventHandler PropertyChanged; 

    public void NotifyPropertyChanged(string propName) 
    { 
     PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName)); 
    } 
} 

이 현재 구현이 잘못되었다는 것을 알고 있습니다. 나는 그렇게처럼 내 모델에서하여 PropertyChanged 알림에 가입해야 함을 발견했습니다은 "AuthResult"속성을 업데이트해야합니다 어디 표시되지 않습니다

LoginModel.PropertyChanged += new System.ComponentModel.PropertyChangedEventHandler(LoginModel_PropertyChanged); 

void LoginModel_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) 
{ 
    if(e.PropertyName == "Authenticated") 
    { 
     //do something 
    } 
} 

. If 문에서 AuthResult = _model.Authenticated; 같은 것을할까요?

편집 :

내 생성자에?

LoginModel _model; 

     public view1(LoginModel model) 
     { 
      _model = model; 
      InitializeComponent();   
     } 

답변

1

모델을 사용하면 뷰에서 직접 바인딩 할 수 있습니다에서 INotifyPropertyChanged 인터페이스를 구현하는 경우 :

<Button Content="Button" IsEnabled="{Binding Authenticated}" /> 

참고 LoginModel 클래스는 인증 된 속성이 새로 설정 될 때마다하여 PropertyChanged 이벤트를 발생해야 값. 이런 식으로

public class ViewModel 
{ 
    public ViewModel(LoginModel model) 
    { 
     Model = model; 
    } 

    public LoginModel Model { get; } 
} 

... 그리고 바인딩 :

또한 뷰 모델 클래스를 통해 전체 모델의 엔티티에 노출 될 수

<Button Content="Button" IsEnabled="{Binding Model.Authenticated}" /> 

을 그것은 여전히해야 모델 클래스 INotifyPropertyChanged 인터페이스를 구현하고 변경 알림을 발생시킵니다.

또 다른 옵션은 뷰 모델이 뷰에서 바인딩 할 수있는 모델 클래스의 모든 속성을 래핑하는 것입니다. 그런 다음 다시이 같은 모델 클래스 무언가의 속성을 래핑 뷰 모델 클래스의 속성에 바인딩 :

public class ViewModel 
{ 
    private readonly LoginModel _model; 
    public ViewModel(LoginModel model) 
    { 
     _model = model; 
    } 

    public bool AuthResult 
    { 
     get 
     { 
      return _model.Authenticated; 
     } 
     set 
     { 
      _model.Authenticated = value; 
      NotifyPropertyChanged("AuthResult"); 
     } 
    } 
} 

<Button Content="Button" IsEnabled="{Binding AuthResult}" /> 

이 후자의 방법을 사용하는 이점은보기는 모델 클래스에 따라 종속성이없는 것입니다.뷰 모델 클래스에만 바인드되며 이는 MVVM 디자인 패턴이 일반적으로 구현되는 방식입니다.

그러나보기 모델의 (래퍼) 속성에 바인딩하고 모델 클래스의 속성이 설정 될 때마다보기를 업데이트하려면 모델이보기 모델에 변경 사항이 있음을 통보해야합니다 또는 다른 것, ie 그것은 일종의 사건 또는 유사한 것을 올려야한다. 그리고 이것은 일반적으로 INotifyPropertyChanged 인터페이스를 구현하는 것을 의미합니다. 뷰 모델은 모델의하여 PropertyChanged 이벤트에 등록하고 모델이 업데이트 될 때마다 속성을 바인딩 데이터, 예를 들면 자체적하여 PropertyChanged 이벤트를 발생시킬 수 있습니다

public class ViewModel 
{ 
    private readonly LoginModel _model; 

    public ViewModel(LoginModel model) 
    { 
     if (model == null) 
      throw new ArgumentNullException("model"); 

     _model = model; 
     _model.PropertyChanged += OnModelChanged; 
    } 

    private void OnModelChanged(object sender, PropertyChangedEventArgs e) 
    { 
     if (e.PropertyName == "Authenticated") 
      NotifyPropertyChanged("AuthResult"); 
    } 

    public bool AuthResult 
    { 
     get 
     { 
      return _model.Authenticated; 
     } 
     set 
     { 
      _model.Authenticated = value; 
      NotifyPropertyChanged("AuthResult"); 
     } 
    } 
} 
+0

이 답변은 궁극적으로 다시 내 질문에 대답, 감사합니다 mm8. – ganjeii

+1

두 번째 옵션은 MVVM이 아니며 "Facade"입니다. – Fabio

1

그냥 그런 다음 XAML에서 당신이 당신의 ViewModel이 될 주위에 "구축"할이 방법 Model

<CheckBox IsChecked="{Binding MyModel.Authenticated}" /> 

의 특성을 결합 할 수있는 뷰 모델

public class ViewModel 
{ 
    private Model _myModel; 
    public Model MyModel 
    { 
     get { return _myModel; } 
     set 
     { 
      if (Equals(_myModel, value)) return; 
      _myModel = value; 
      NotifyPropertyChanged(nameof(MyModel)); 
     } 
    } 
} 

에 회원으로 모델을 사용하여 모델.
그 모델이 앞의 예제와 같은 방식으로 "Facade"클래스를 만드는 것보다 INotifyPropertyChanged을 구현하는 것을 원하지 않는 경우에 사용하십시오.

public class ModelFacade : INotifyPropertyChanged 
{ 
    private Model _myModel; 

    public bool Authenticated 
    { 
     get { return _myModel.Authenticated; } 
     set 
     { 
      _myModel.Authenticated = value; 
      NotifyPropertyChanged(nameof(Authenticated)); 
     } 
    } 
} 

public class ViewModel 
{ 
    private ModelFacade _myModel; 
    public ModelFacade MyModel 
    { 
     get { return _myModel; } 
     set 
     { 
      if (Equals(_myModel, value)) return; 
      _myModel = value; 
      NotifyPropertyChanged(nameof(MyModel)); 
     } 
    } 
} 
+0

좋아, 그럼 그냥에서 컨트롤에서 MyModel 속성에 바인딩 보기? 그리고 NotifyPropertyChanged()를 완성하지 않았다고 가정하고,'NotifyPropertyChanged ("MyModel")'을 수동으로 읽어야합니다. – ganjeii

+0

또한 모델에서 특정 "인증 된"속성을 얻으려고합니다. 응답이 불완전한 것처럼 보입니다. 그러나 나는 당신이 어디에서 왔는지 이해합니다. – ganjeii

+1

뷰에서 'MyModel.Authenticated'를 바인딩하거나 뷰 모델에서 래퍼 프로퍼티를 생성 할 수 있습니다 :'public bool AuthResult {get {return MyModel.Authenticated; }'. 후자의 경우, NotifyPropertyChanged ("AuthResult")를 MyModel 속성의 설정자에 추가해야한다. – mechanic