2010-08-07 2 views
0

다음 작업을 올바르게 수행하려고합니다. 나는 UserControl (ProgramView)있다. 뷰 모델 (ProgramViewViewModel)이 있습니다. ProgramView는 Window (ProgramWindow) 내에서 자식 컨트롤로 사용됩니다. ProgramWindow에는 공용 속성 ProgramId가 있으므로 창 사용자는 원하는 프로그램 (데이터 엔터티)을 지정할 수 있습니다. ProgramView에는이 데이터를 표시하는 것이 주된 업무이므로 ProgramId 속성이 있습니다. ProgramWindow는이 사용자 정의 컨트롤의 래퍼 창에 불과합니다.WPF : 자식 UserControl (MVVM) 창이있는 적절한 구성

ProgramViewViewModel에는 ProgramId 속성도 있습니다. 이 속성을 변경하면 다른 모델 (ProgramView가 바인딩 할 수 있음)을 사용하여 뷰 모델 외부에 나타나는 뷰 모델의 작업이 중단됩니다.

ViewView의 작업을 ProgramView 및 ProgramWindow 소비자에게 숨기려고합니다.

이 프로그램 ID는이 모든 계층을 통해 바인딩되어야합니다. ProgramWindow.ProgramId의 변경 사항은 ProgramView.ProgramId로 이동 한 다음 ProgramViewViewModel.ProgramId로 이동해야합니다. 나는 이것을 올바르게 구현하는 방법을 알 수 없다.

현재 나의 세 가지 방법은 세 가지 클래스 모두에서 ProgramId를 DP로 표시하는 것입니다. Window 내에서 Programview가 인스턴스화 된 것을 상상해보십시오 :

<local:ProgramView ProgramId="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:ProgramWindow}}, Path=ProgramId}" /> 

이 부분은 실제로 작동하는 것 같습니다. ProgramView 내에서 속성에 대해 변경된 이벤트를 가져오고 올바른 값을 가진 것으로 보입니다. FindAncestor가 제대로 작동하는 것 같습니다.

그런데 어떻게 ProgramViewViewModel.ProgramId 속성을 동기화해야합니까? 나는 두 가지 방법을 본다. 한 가지 방법은 FindAncestor를 사용하고 ProgramViewViewModel에서 ProgramId를 찾으려면 ProgramViewViewModel 인스턴스 자체에 바인딩을 설정하는 것입니다. 두 가지 단점이 있습니다. ProgramViewViewModel을 사용하여 ProgramId를 종속성 속성으로 표시해야합니다. 나는 이것을 피하고 싶지만 받아 들여질 수 있습니다. 어쨌든, 나는 XAML에서 그것을 성취 할 수 없다.

<local:View.DataContext> 
    <local:ProgramViewViewModel 
     ProgramId="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:ProgramView}}, Path=ProgramId}" /> 
</local:View.DataContext> 

이것은 작동하지 않습니다. 인스턴스의 인스턴스화 내에서 바인딩 표현식을 도입 할 수없는 것으로 보입니다. FindAncestor는 ProgramView를 찾을 수 없다고보고합니다. 내 이론은 인스턴스가 논리적 인 트리의 외부에 있으므로 부모로 트래버스 할 수 없다는 것입니다.

두 번째 옵션은 ProgramView.ProgramId 속성을 "ProgramId"(DataContext)에 바인딩하는 것입니다. 코드 숨김에 정의 된 속성에 바인딩 식을 지정하는 방법을 알 수 없기 때문에이 작업을 수행 할 수 없습니다. XAML에 필요하지만 실제로 ProgramId가 존재하는 유형입니다. 이 속성을 지정하는 방법을 알 수 없습니다.

수동으로 (ProgramView의 코드 숨김으로) Binding 인스턴스를 만들고 SetBinding (ProgramIdProperty, binding)을 호출하면 값이 더 이상 View 자체로 유입되지 않습니다. 나는 이것이 ProgramWindow에 의해 이전에 설정된 ProgramView.ProgramId의 바인딩을 대체했기 때문에 이것이라고 생각한다. 하나의 속성마다 하나의 바인딩?

나머지 아이디어는 두 개의 ProgramId 속성을 ProgramView에 제공하는 것입니다. 하나는 DataContext에 바인딩되고 다른 하나는 소비자 (ProgramWindow)에 바인딩되도록 공개적으로 사용할 수 있으며, 둘 중 하나를 동기화하는 OnValueChanged 처리기를 작성할 수 있습니다. 이것은 해킹처럼 느껴집니다. 다른 하나는 ProgramView의 코드 숨김 내에서 ProgramView.ProgramId 및 ProgramView.DataContext의 변경 사항을 수동으로 감시하고 직접 값을 전파하는 것입니다. 이 아이디어들 중 어떤 것도 이상적이지 않습니다.

다른 제안 사항을 찾고 있습니다.

+0

두 번째 ProgramIdProxy 속성을 사용하면 작동합니다. 나는 단지 그것을 좋아하지 않는다. – wasabi

답변

0

설명이 상세하게 보이지만 왜이 디자인을 구현해야하는지 이해하는 데 문제가 있습니다. 나는 DRY를 도울 수는 없지만 생각할 수는 없다.

이와 관련된 두 가지보기 모델에서 종속성 속성을 노출해야하는 경우 하위보기 모델 (사용자 컨트롤보기의 경우)을 첫 번째 (프로그램 창보기의) 속성으로 지정하는 것이 좋습니다. 같은 뭔가 :

public class MainViewModel : ViewModelBase 
{ 
    public ProgramViewModel ChildViewModel { get; private set; } 

} 

public class ProgramViewModel : ViewModelBase 
{ 
    private int _ProgramId; 

    public int ProgramId 
    { 
     get { return _ProgramId; } 
     set 
     { 
     if (value != _ProgramId) 
     { 
      // set and raise propery changed notification 
     } 
     } 
    } 
} 

MAINVIEW는 ChildViewModel.ProgramId (MainViewModel로 설정 데이터 컨텍스트)를 사용하여 속성을 얻을 수 있습니다. ProgramView는 ProgramId (데이터 컨텍스트가 MainViewModel.ChildViewModel로 설정 됨)를 사용하여 ProgramView에 액세스합니다.