2011-10-26 3 views
1

내 머리를 때리는 문제는 다음과 같습니다. 내 ViewModel에 바인딩 된 두 가지 종속성 속성을 제공하는 사용자 지정 사용자 정의 컨트롤이 있습니다. 내 ViewModel에는 사용자 정의 컨트롤뿐만 아니라 조작하는 컨트롤에 관련된 값을 나타내는 여러 속성을 보유하는 클래스의 인스턴스가 있습니다. 시각적으로 설명하기위한 약간의 샘플 코드가 있습니다. 여기에 간단한 컨트롤 샘플이 있습니다.이 슬라이더는 사용자가 슬라이더를 잠글 수있는 확인란과 결합되어 있습니다.INotifyPropertyChanged 바인딩이 예상대로 업데이트되지 않습니다.

<custom:SliderControl IsLocked="{Binding Path=CustomClass.IsLocked, Mode=TwoWay}" SliderValue="{Binding Path=CustomClass.Value, Mode=TwoWay}" /> 

IsLocked 및 SliderValue는 사용자 지정 컨트롤에 포함 된 확인란과 슬라이더를 효과적으로 조작하는 종속성 속성입니다. 모든 제어 함수는 내가 정의한 클래스에 대한 바인딩을 제외하고는 의도 한대로 작동합니다. 하나의 int 속성과 하나의 bool 속성에서와 같이 개별 속성을 만들면 바인딩이 의도 한대로 작동합니다. 그러나 나는 5 개의 슬라이더를 가지고 있으며 실제 코드의 각 슬라이더에는 5 개의 속성이 있습니다. 나는 재사용 가능한 객체에서이 속성들을 보유 할 클래스를 생성하여 코드 복제를 제거하려고 노력하면서 25 개의 속성을 5 개의 클래스 인스턴스로 줄였다.

내 CustomClass는 ObservableObject를 상속하며 각각 IsLocked 및 SliderValue라는 bool 속성 및 int 속성을가집니다. 여기에 더 시각 자료의 경우처럼 보이는 것입니다 :

public class CustomClass : ObservableObject 
    { 
     public const string SliderValuePropertyName = "SliderValue"; 
     private int _sliderValue= 0; 
     public int SliderValue 
     { 
      get 
      { 
       return _sliderValue; 
      } 

      set 
      { 
       if (_sliderValue== value) 
       { 
        return; 
       } 


       _sliderValue= value; 
       RaisePropertyChanged(SliderValuePropertyName); 
      } 
     } 

    public const string IsCheckedPropertyName = "IsChecked"; 
    private bool _isChecked = false; 
    public bool IsChecked 
    { 
     get 
     { 
      return _isChecked; 
     } 

     set 
     { 
      if (_isChecked == value) 
      { 
       return; 
      } 
      _isChecked = value; 
      RaisePropertyChanged(IsCheckedPropertyName); 
     } 
    } 

뷰 모델 속성이 매우 유사하며 다음과 같습니다, 클래스의 새로운 인스턴스가 생성 될 때 뷰 모델로드 :

public const string SliderOnePropertyName = "SliderOne"; 
    private CustomClass _sliderOne; 
    public CustomClass SliderOne 
    { 
     get 
     { 
      return _sliderOne; 
     } 

     set 
     { 
      if (_sliderOne== value) 
      { 
       return; 
      } 

      _sliderOne= value; 
      RaisePropertyChanged(SliderOnePropertyName); 
     } 
    } 

왜 클래스의 속성에 바운드 된 종속성 속성의 업데이트가 제대로 업데이트되지 않습니까? 클래스 인스턴스 속성을 올바르게 업데이트 할 수 없으며 변경이 발생할 때마다 전체 클래스 인스턴스를 업데이트해야하기 때문입니까? 아니면이 ViewModel 속성에서 세터를 추가로 사용자 정의해야합니까? 슬라이더 값이나 체크 상자를 변경하면 바운드 프로퍼티에 결코 도달하지 않으며 디버깅 할 때 오류가 발생하지 않습니다.

EDIT : 테두리에 컨트롤을 둘러싸고 Border UIElement의 DataContext를 클래스의 DataContext로 설정 한 다음 기본 사용자 지정 컨트롤에보다 간단한 경로 바인딩을 적용했습니다. 이것은 그러나 내 문제에 영향을 미치지 않았다.

저는 자국 프로그래머입니다. 따라서 코드를 함께 넣을 때 종종 놓친 것들이 있습니다. 그리고 제가 생각하기에 노력하지 않는 한 여기에 맞춰 짐을 예상합니다.

도움을 주시면 감사하겠습니다.

편집 : 그래서 사용자 지정 컨트롤의 특정 속성이 변경 될 때 알려주고 그 이벤트를 내 ViewModel에 연결하여 기존 클래스를 업데이트하는 사용자 지정 이벤트를 사용해 보았습니다. 이것은 작동하지만 여전히 코드 복제본을 생성합니다. 이제는 10 개의 이벤트, 컨트롤 당 2 개의 이벤트, 슬라이더 값이 변경 될 때 확인하는 이벤트 및 체크 박스 IsChecked 값 변경시 감지 할 이벤트가 필요합니다. 이 코드 중복은 여러 명령 매개 변수 (슬라이더가 조작되는 간단한 문자열 식별자와 코드에서 사용하려는 값)를 라우팅 할 수 없기 때문에 존재합니다. 이 제한은 ViewModel에 물리적 컨트롤을 노출하면 MVVM 패턴이 깨지기 때문에 정의 된 메서드 내에서 컨트롤이 변경되는 것을 구분하는 2 개의 이벤트를 사용할 수 없다는 것을 의미합니다. 클래스를 사용하여 사용자 정의 컨트롤에 대한 datacontext 만든 그래서 그들은 각 자신의 클래스 인스턴스가 있던대로 어떤 컨트롤을 조작 할 상관 없어. 이벤트를 사용하면 MVVM 패턴이 풀립니다. 사용자가 5 개의 컨트롤 중 어느 것을 조작하고 있는지 알 필요가 있습니다.

속성 바인딩에서 클래스를 사용하는 것은 어렵지 않습니다. 나는 치료법을 놓치고 있어야한다.

+0

출력 오류 창에서 바인딩 오류를 확인 했습니까? – s1mm0t

+0

예, 출력 창에 오류가 전혀 나타나지 않습니다. 디버깅은 전혀 문제를 반환하지 않습니다. XAML 내에서 바인딩을 사용할 때 이것이 일반적이라고 생각합니다. 바인딩이 유효하지 않은 경우 속성이 기본값으로 초기화 될 수있는 경우 문제를보고하지 않습니다. – Paolis

+0

뷰의'DataContext'는 무엇입니까? – ChrisF

답변

1

<custom:SliderControl DataContext="{Binding CustomClass}" IsLocked="{Binding IsLocked, Mode=TwoWay}" SliderValue="{Binding Value, Mode=TwoWay}" /> 전체 예입니다

public partial class MainPage : UserControl 
{ 
    public MainPage() 
    { 
     InitializeComponent(); 
     this.DataContext = new ViewModel(); 
    } 
} 


public class ViewModel 
{ 
    public SliderValues slv { get; private set; } 

    public ViewModel() 
    { 
     slv = new SliderValues(); 
    } 
} 

public class SliderValues : INotifyPropertyChanged 
{ 
    bool _isLocked = false; 

    public bool IsLocked 
    { 
     get { return _isLocked; } 
     set 
     { 
      _isLocked = value; 
      OnPropertyChanged("IsLocked"); 
     } 

    } 
    int _theValue = 5; 

    public int TheValue 
    { 
     get { return _theValue; } 
     set 
     { 
      _theValue = value; 
      OnPropertyChanged("TheValue"); 
     } 
    } 

    public event PropertyChangedEventHandler PropertyChanged; 

    private void OnPropertyChanged(string prop) 
    { 
     if (PropertyChanged != null) 
      PropertyChanged(this, new PropertyChangedEventArgs(prop)); 

    } 
} 
이제

XAML :

<UserControl x:Class="TestBindings.MainPage" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
    mc:Ignorable="d" 
    d:DesignHeight="300" d:DesignWidth="400"> 

    <Grid x:Name="LayoutRoot" Background="White"> 
     <Slider Height="23" HorizontalAlignment="Left" Margin="114,138,0,0" Name="slider1" VerticalAlignment="Top" Width="100" 
       DataContext="{Binding slv}" Value="{Binding TheValue, Mode=TwoWay}"/> 
    </Grid> 
</UserControl> 
+0

이것은 내가 지금있는 곳입니다. 내가 직접 만든 문제는 클래스를 별도의 파일로 정의했기 때문에 클래스 뷰에서 INotifyPropertyChanged를 발생시킨 클래스 인스턴스의 속성을 만들어야한다고 생각했습니다. 이렇게하면 클래스 코드에서 모든 것이 발생하고 무시됩니다. 내가 만든 속성. 따라서 클래스 속성이 변경 될 때 알 수있는 메서드를 실행하기가 어렵습니다. MVVM Light 메시징을 사용하여이 문제를 해결하고 있습니다. 이 코드 예제를 가져 주셔서 감사합니다! – Paolis

+0

개별 슬라이더 컨트롤을 조작 할 때 실행되는 메서드가있는 이유는 상호 종속성을 가지며 도달 한 값이 도달하면 최대 값을 가진 슬라이더 컨트롤에서 떨어져 나가기 시작한다는 것입니다. 이로 인해 모든 컨트롤이 조작되어 다른 모든 컨트롤을 확인하고 최대 값이 초과 된 경우 패리티를 생성해야하는 상황이 발생했습니다. – Paolis

1

구문 오류가있을 수 있습니다. 이

시도 {= 바인딩 경로를 CustomClass.IsLocked, 모드 = 양방향}

+0

그럴 수 있습니다. –

+0

죄송합니다. 입력 한 예제에는 실제로 여러 오타가 있지만 실제 코드는 아닙니다. 나는 지금 그것을 고쳤다. – Paolis

0

이 시도 ... 여기

관련 문제