2014-06-23 2 views
1

MVVM에 대해 조금 배우기 위해 약간의 프로젝트를 만들었습니다. 직장에서 집에 돌아갈 수있는 시간을 계산하는 계산기입니다.PropertyChangedEventHandler는 둘 다 null이지만 바인딩은 한 번만 작동합니다. 이유가 무엇입니까?

두 개의 텍스트 상자와 단일 레이블을 사용하여 UserControl을 간단한 "TimePicker"로 만들었습니다. 이 Usercontrol에는 하나의 Timepicker 시간을 관리하는 ViewModel (Mainwindow도 있습니다)이 있습니다. 세 개의 속성이 있습니다. TimeValue이라는 정수는시와 분의 값이고 HoursMinutes이라는 두 개의 int입니다. 내 두 개의 텍스트 상자가 그들에게 묶여 표시됩니다. Textbox를 통해 하나의 값을 설정하면 Time이 재설정되고, Property를 통해 시간을 설정하면 Hours 및 Minutes가 재설정되며이 값을 설정하면 두 텍스트 상자가 모두 업데이트됩니다.

이 작업은 정상적으로 종료됩니다. 이제 ReadOnly이라는 두 번째 속성을 추가하고 싶습니다. ReadOnly는 시간을 표시하는 TimePicker에 필요합니다. 이 시간을 수동으로 설정하는 것은 의미가 없기 때문에 두 텍스트 상자 모두를 설정할 수 있습니다. IsReadOnly 속성.

ReadOnly은 이제 UserControl의 두 번째 속성입니다. 내가 게으르 기 때문에 직접 UserControl을 통해 Property와 Textbox 두 개를 바인딩하고 UserControl에 IsReadOnly -Property 만 바인딩하려고합니다.

public partial class TimeBox : UserControl, INotifyPropertyChanged 
{ 
    private SingleTimeViewModel viewModel; 

    //... other Properties 

    public static DependencyProperty ReadOnlyProperty = DependencyProperty.Register("ReadOnly", typeof(Boolean), typeof(TimeBox), new PropertyMetadata(false)); 

    // Schnittstellen-Ereignis 
    public event PropertyChangedEventHandler PropertyChanged; 
    protected internal void OnPropertyChanged(string propertyname) 
    { 
     if (PropertyChanged != null) 
      PropertyChanged(this, new PropertyChangedEventArgs(propertyname)); 
    } 

    public TimeBox() 
    { 
     InitializeComponent(); 
     viewModel = new SingleTimeViewModel(SingleTime.CreateSingleTime()); 
     this.DataContext = viewModel; 
    } 

    //... Code of other Properties 

    private bool _ReadOnly; 
    public bool ReadOnly 
    { 
     get 
     { 
      return _ReadOnly; 
     } 
     set 
     { 
      if (_ReadOnly == value) 
       return; 
      _ReadOnly = value; 
      OnPropertyChanged("ReadOnly"); 
     } 
    } 

    //... Other Methods 
} 

이가 XAML을 통해 모두 텍스트 상자에 바인드 (뷰 모델에 Text 납 바인딩, isReadOnly의이 - 박스에 결합해야) :

내 아이디어의 코드 (UserControl을)했다

<UserControl x:Name="TimeBoxControl" x:Class="TimeCalculator.TimeBox" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     ... > 
    <WrapPanel Grid.Column="7" HorizontalAlignment="Stretch" Margin="0,0,0,0" Grid.Row="1" VerticalAlignment="Center" > 
     <TextBox x:Name="txtBxHours" ... Text="{Binding Hours}" ... IsReadOnly="{Binding ReadOnly, ElementName=TimeBoxControl}" /> 
     <Label x:Name="lblSeparator" ... /> 
     <TextBox x:Name="txtBxMinutes" ... Text="{Binding Minutes}" ... IsReadOnly="{Binding ReadOnly, ElementName=TimeBoxControl}" /> 
    </WrapPanel> 
</UserControl> 

InitializeComponent 이후에 내 프로젝트의 메인 윈도우 생성자에서 값을 읽기 전용으로 만들었습니다. 따라서 나는 다음과 같은 라인을 사용 :이 작동하지 않았다

this.TmBxMayGo.ReadOnly = true; 
this.TmBxMustGo.ReadOnly = true; 
this.TmBxTimeUntilMayGo.ReadOnly = true; 
this.TmBxTimeUntilMustGo.ReadOnly = true; 
this.TmBxCurrentOvertime.ReadOnly = true; 

를 디버깅 후 나는 PropertyChangedEventHandler PropertyChanged 항상 null 때문에 그것을하지 않았다 발견. 이 문제에 대한 해결책을 찾기 위해 많은 조사를했지만 일반적인 실수 (예 : : INotifyPropertyChanged을 잊어 버렸습니다. 문자열에 잘못된 이름이있는 경우)을 만들지 않았습니다.

나는 결국 포기하고 ViewModel을 통해 만들었습니다. 하지만 그때 내가 null ViewModel 통해 설정할 때 깨닫게되지만 텍스트 상자는 호출 후 ReadOnly했습니다.

이제 두 가지 질문은 내가 가진 :

  1. 이 이해가 하나의 UserControl에 대한 자신의 뷰 모델을 만들어 지나요?
  2. 왜 그렇습니까? PropertyChangednull이지만 두 번만 작동 할 수 있습니까?
+0

나는 왜 UserControl에서 파생 된 클래스에 INotifyPropertyChanged가 필요한지 궁금합니다. 종속성 등록 정보를 완벽하게 활용하여 제어 및 유연성을 향상시킬 수 있습니다. – pushpraj

+0

_ReadOnly를 할당하기 전에 "if (_Enabled == value)"를 선택하십시오. 그것은 디자인에 의한 것인가 아니면 "if (_ReadOnly == value)"를 확인해야할까요? :) –

+2

모든 것을 제거하십시오. 'DependencyObject'에'INotifyPropertyChanged'를 구현하지 않아도됩니다. 아이디어는 실제로 모든 속성을 "ViewModel"이라고하는 별도의 POCO 클래스에 넣음으로써 UI와 동작을 '분리'하는 것입니다. –

답변

0
  1. 예, 그것은 논리적으로 UI 구분 단일 standlone에 대한 단일 뷰 모델을 가지고 의미가 있습니다. 그것은 mainviewmodel에서 책임을 나눕니다. 따라서 모든 속성을 ViewModel에 넣으십시오.

  2. WPF는 해당 개체가 UserControl의 DataContext를 설정하기 전에 PropertyChanged가 null 인 뷰의 DataContext로 설정된 경우에만 INotifyPropertyChanged 개체의 PropertyChanged 이벤트에 처리기를 연결합니다. 그리고 바인딩을 초기화하는 동안 이러한 속성의 getter가 호출되고 사용자가 지정한 기본값으로 UI가 업데이트되므로 텍스트 상자가 계속 비활성화됩니다.

+0

하지만 처음에는 InitializeComponent()를 사용하고 두 경우 모두 속성을 설정했다. – Strohi

0

언급 수행하는 깨끗한 방법은 여기

public bool ReadOnly 
    { 
     get { return (bool)GetValue(ReadOnlyProperty); } 
     set { SetValue(ReadOnlyProperty, value); } 
    } 

    // Using a DependencyProperty as the backing store for ReadOnly. This enables animation, styling, binding, etc... 
    public static readonly DependencyProperty ReadOnlyProperty = 
     DependencyProperty.Register("ReadOnly", typeof(bool), typeof(TimeBox), new PropertyMetadata(false, null, CoerceReadOnly)); 

    private static object CoerceReadOnly(DependencyObject d, object baseValue) 
    { 
     if ((d as TimeBox)._Enabled == baseValue) 
      return DependencyProperty.UnsetValue; 
     return baseValue; 
    } 

내가 그렇지 않으면 속성 변경을 취소합니다 DependencyProperty.UnsetValue을 반환하여 있도록 상태를 확인하기 위해 강제 변환 값 콜백을 사용하고 같은 것 그것은 여기 http://msdn.microsoft.com/en-us/library/ms745795(v=vs.110).aspx#Advanced

다른 질문에 대한 강제 변환에

더 많은 정보를 진행합니다 , 나는 당신이 아마도 컨트롤 라이브러리를 배포하고 싶지 않으면 usercontrol을 만들 필요가 없다고 말할 것이다. 동일한 데이터 템플릿을 활용하십시오.

두 번째로 종속성 프레임 워크에서 작동하는 usercontrol에 바인딩하고 있으므로 일반 알림이 예상대로 작동하지 않을 수 있습니다.

관련 문제