2013-03-12 3 views
1

내 ViewModel에서 나는 유형 문자열의 LoggedInAs 속성과 부울 유형의 EditMode 속성을 가지고 있습니다. 바인딩은 이름에 의해 자동으로 수행되도록, 내가 Caliburn.Micro을 사용하고이 DataTemplateSelector를 작동시키는 방법?

<ItemsControl Name="ReaderList" ItemTemplateSelector="{StaticResource drts}"/> 

: 나는 또한이 같은 표시 목적으로 ItemsControl에 바인딩 ReaderList라는 목록 속성이 있습니다. DataTemplateSelector를 사용하고 싶습니다. 왜냐하면 응용 프로그램이 EditMode에 있고 Person이 로그인되어 있기 때문에 근본적으로 다른 디스플레이를 원하기 때문입니다. 어떤 이유

public class DisplayReaderTemplateSelector: DataTemplateSelector { 
    public DataTemplate CurrentUserTemplate { get; set; } 
    public DataTemplate OtherUserTemplate { get; set; } 

    public string IsLoggedInAs {get; set;} 
    public bool IsEditMode { get; set; } 

    public override DataTemplate SelectTemplate(object item, DependencyObject container){ 
     var _r = item as Person; 
     if (IsEditMode && _r.Name == IsLoggedInAs) return CurrentUserTemplate; 
     else return OtherUserTemplate; 
    } 
} 

뷰 모델 인스턴스 응용 프로그램이 충돌하면서 (RESP를보기.) 그래서 여기 여기 내 자원의 선언,

<UserControl.Resources> 
    <DataTemplate x:Key="OtherPersonTemplate"> ... </DataTemplate> 
    <DataTemplate x:Key="CurrentUserIsPersonTemplate"> ... </DataTemplate> 

    <local:DisplayReaderTemplateSelector x:Key="drts" 
      IsLoggedInAs="{Binding LoggedInAs}" 
      IsEditMode="{Binding EditMode}" 
      CurrentUserTemplate="{StaticResource CurrentUserIsPersonTemplate}" 
      OtherUserTemplate="{StaticResource OtherPersonTemplate}"/> 
</UserControl.Resources> 

및 클래스의 코드입니다. 오류가 어디에 있으며 어떻게 해결할 수 있습니까?

편집 : IsLoggedInEditMode이 DependencyProperties가 아니기 때문에 충돌이 DisplayReaderTemplateSelector 구성에서 바인딩 표현식 때문이었습니다.

그럼 이제 질문입니다. 값에 바인딩 할 수없는 경우 ViewModel의 상태에 따라 달라지는 DataTemplateSelector를 어떻게 가질 수 있습니까?

+0

ViewModel의 코드는 어디에 있습니까? 오류가 무엇입니까? – Backlash

+0

ViewModel은 꽤 큽니다. 위에서 설명한이 문제의 유일한 관련 부분은 노출 된 두 속성입니다. 오류 : Mscorlib.dll에서 'System.Reflection.TargetInvocationException'유형의 예외가 발생했지만 사용자 코드에서 처리되지 않았습니다. 응용 프로그램이 실행되지만 위의 VM으로 전환하면 충돌이 발생합니다 (로그인 한 후 StartUp ViewModel이 정상적으로 작동하며 위 VM을 사용하면 충돌이 발생 함). – EluciusFTW

+0

TargetInvocationException의 InnerException을 살펴보면 유용한 정보가 종종 있습니다. –

답변

1

그 동류의 DataTemplateSelector 또는 뭔가를 사용할 수있는 동안, 아마 Caliburn.Micro의 것을 찾기 위해 당신을 놀라게하지 않습니다는 내장 View.Context의 형태로이 기능과 켜기 ViewLocator

을 가지고 당신의 VM을 사용하면 CM이 뷰를 해석하는 데 사용할 컨텍스트 문자열을 제공 할 수 있습니다. 명명 규칙을 사용하기 때문에 하위 뷰의 올바른 네임 스페이스/이름과 컨텍스트 문자열을 지정해야합니다. 대체보기

VM에서 사용자 세부 정보를 사용하여 값을 결정하는 컨텍스트 속성을 만들 수 있습니다 :

내가 볼 수있는 유일한 문제는 (아마 해결 방법을 가지고 하나) 당신이 ViewModel 내부에서보기를 확인해야 할 것입니다
public class SomeViewModel 
{ 
    public string Context 
    { 
     get 
     { 
      if (IsEditMode && _r.Name == IsLoggedInAs) return "Current"; 
      else return "Other"; 
     } 
    } 

    // ... snip other code 
} 

- 일반적으로 더 높은 최대 컨텍스트를 결정하고 해당 전달 ContentControl 및 CM은 해당 VM에 대한보기를 찾을 때이를 사용합니다.

예 :

주 VM :

- ViewModels 
| 
----- SomeSubViewModel.cs 
    | 
    - SomeSubView.xaml 
    | 
    - SomeSubView 
    | 
    ----- Alternative.xaml 

및 CM은 SomeSubView 네임 스페이스에보고 알게 될 것입니다 :

public class MainViewModel 
{ 
    public SomeSubViewModel { get; set; } // Obviously would be property changed notification and instantiation etc, I've just left it out for the example 
} 

및 관련보기

<UserControl> 
    <!-- Show the default view for this view model --> 
    <ContentControl x:Name="SomeSubViewModel" /> 
    <!-- Show an alternative view for this view model --> 
    <ContentControl x:Name="SomeSubViewModel" cal:View.Context="Alternative" /> 
</UserControl> 

다음 VM 명명 구조는 것 원래 VM 이름과 012를 기반으로 한 Alternative이라는 컨트롤속성 (SomeSubViewModel 빼기 모델 + 더하기)은 SomeSubView입니다.대안)

그래서 나는 이것을하는 표준 방법이므로 주위를 둘러 봐야 할 것입니다. 이 방법을 사용하면 하위보기 모델을 만들고 ContentControl을보기에 추가하고 View.Context 속성을 VM의 Context 속성에 바인딩하거나 Context 속성을 상위 VM (상위 VM)에 추가해야합니다).

일부 대안을 살펴 보겠습니다. 현재의 ViewModel에서 표준 CM을 사용하여 속성을 기반으로보기를 결정할 방법이 없다면 ViewLocator을 사용자 정의하고 인터페이스 (IProvideContext 또는 somesuch)를 사용할 수 있습니다. ViewLocator에 컨텍스트가 즉시 제공됩니다. (VM에서 뷰 확인 프로세스에 직접 연결할 수 없다고 생각합니다.)

다른 답변이나 대안을 곧 다시 볼 것입니다.

편집 : 좋아

이 할 수있는 가장 간단한 방법이 될 것으로 보인다.

ViewLocator.LocateForModel = (model, displayLocation, context) => 
{ 
    var viewAware = model as IViewAware; 

    // Added these 3 lines - the rest is from CM source 
    // Try cast the model to IProvideContext 
    var provideContext = model as IProvideContext; 

    // Check if the cast succeeded, and if the context wasn't already set (by attached prop), if we're ok, set the context to the models context property 
    if (provideContext != null && context == null) 
     context = provideContext.Context; 

    if (viewAware != null) 
    {      
     var view = viewAware.GetView(context) as UIElement; 
     if (view != null) 
     { 
#if !SILVERLIGHT && !WinRT 
      var windowCheck = view as Window; 
      if (windowCheck == null || (!windowCheck.IsLoaded && !(new WindowInteropHelper(windowCheck).Handle == IntPtr.Zero))) 
      { 
       LogManager.GetLog(typeof(ViewLocator)).Info("Using cached view for {0}.", model); 
       return view; 
      } 
#else 
      LogManager.GetLog(typeof(ViewLocator)).Info("Using cached view for {0}.", model); 
      return view; 
#endif 
     } 
    } 

    return ViewLocator.LocateForModelType(model.GetType(), displayLocation, context); 
}; 

: 난 그냥이 ViewLocator 구현 어떤 컨텍스트가 이미 지정되지 않은 경우 (당신이 Bootstrapper.Configure()에서이 작업을 수행 할 수 있습니다)이 사용하는 주문을 받아서 그런 다음 VM

public interface IProvideContext 
{ 
    string Context { get; } 
} 

에서 직접 Context을 제공하는 인터페이스를 생성 이것은 당신을 위해 작동해야하며 대상에 직접 컨텍스트를 설정할 수 있습니다 ViewModel - 분명히 이것은 뷰 우선 접근 방식에서만 작동합니다.

위의 그림 (올바른 네임 스페이스 등)에서 구조를 구성한 다음 IsLoggedInAsEditMode의 값을 기반으로 VM의 Context 속성을 설정하십시오.

+0

고마워요! 나가 이것을 완전히 검사 할 수있을 때까지 2 일이 소요될 것이다, 그러나 나는 def. 너에게 돌아와! – EluciusFTW

+0

샘플 프로젝트를 게시 할 예정입니다.: P도 마찬가지 일 수도 있습니다. – Charleh

+0

좋아요. 샘플을 원한다면 인터넷 보안 서버가 여기 나를 허락하지 않을 것이기 때문에 우편으로 보내 드리겠습니다 :) – Charleh

관련 문제