2013-03-12 25 views
1

在我的Viewmodel中,我有屬性類型爲LoggedInAs的字符串類型,EditMode類型爲bool。我也有我綁定到一個ItemsControl用於顯示的這樣叫ReaderList一個列表屬性:如何使這個DataTemplateSelector工作?

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

我使用Caliburn.Micro,這樣的結合是由命名自動完成。我想使用DataTemplateSelector,因爲如果應用程序處於EditMode中,並且Person是登錄的人,我想要一個根本不同的顯示。因此,這裏是我的資源的聲明,

<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> 

,並在這裏爲類代碼:

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查看)。錯誤在哪裏,和/或我該如何解決這個問題呢?

編輯:崩潰是由於在DisplayReaderTemplateSelector的構建中的綁定表達式 - 因爲IsLoggedInEditMode不是DependencyProperties。

所以現在的問題是:如果我無法綁定到值,我怎麼能有一個DataTemplateSelector取決於ViewModel的狀態?

+0

哪裏是視圖模型的代碼在你的虛擬機Context財產?什麼是錯誤? – Backlash 2013-03-12 15:45:37

+0

ViewModel相當大,上面描述的這個問題的唯一相關部分是兩個暴露的屬性。錯誤是:在mscorlib.dll中發生了類型'System.Reflection.TargetInvocationException'的異常,但未在用戶代碼中處理。應用程序運行,但當我切換到上面的VM時崩潰(啓動ViewModel工作正常,登錄後,上面的虛擬機使用它崩潰)。 – EluciusFTW 2013-03-12 15:51:51

+0

看看TargetInvocationException的InnerException,那裏通常有用的信息。 – 2013-03-12 16:00:57

回答

1

雖然你可以使用DataTemplateSelector或東西之流,它可能不會令你感到驚訝地發現,在Caliburn.Micro具有這種功能內置在View.Context形式ViewLocator

在您VM可以創建一個屬性,該屬性提供一個CM將用於解析視圖的上下文字符串 - 由於它使用命名約定,因此只需爲子視圖提供正確的名稱空間/名稱以及要查找的上下文字符串替代視圖

在您的VM中,您可以創建使用用戶詳細信息確定其值的上下文屬性:

public class SomeViewModel 
{ 
    public string Context 
    { 
     get 
     { 
      if (IsEditMode && _r.Name == IsLoggedInAs) return "Current"; 
      else return "Other"; 
     } 
    } 

    // ... snip other code 
} 

我看到的唯一的問題(一個可能有一種變通方法)是你想從一個ViewModel內確定視圖 - 通常你確定的背景下上漲,並傳遞到ContentControl和CM在爲該VM定位視圖時使用它

例如

你的主VM:

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> 

那麼你的虛擬機的命名結構將是:

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

和CM會知道在SomeSubView命名空間看對於基於原始VM名稱和012的稱爲Alternative的控件屬性(SomeSubViewModel減模型加點加Context這是SomeSubView。替代品)

所以我必須有一個遊戲,因爲這是做它的標準方式。如果要這樣做,則必須創建子視圖模型並將ContentControl添加到您的視圖中,並將View.Context屬性綁定到虛擬機上的Context屬性,或將Context屬性更高地添加到父VM )。

我會看看一些替代方案 - 如果無法讓當前ViewModel根據使用標準CM的屬性來決定其視圖,則可以自定義ViewLocator,也可以使用接口(IProvideContext或somesuch)提供ViewLocator立即上下文 - (我不認爲你不能直接掛鉤到虛擬機的視圖分辨率過程)

我會回來與另一個答案或短期!

編輯:

確定這似乎是這樣做的最直接方法。我剛剛創建,其直接從VM

public interface IProvideContext 
{ 
    string Context { get; } 
} 

提供Context然後接口I定製ViewLocator執行(你可以在​​做到這一點)來使用這個,如果已經沒有指定背景:

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); 
}; 

這應該適用於你,並允許你直接在目標上設置上下文ViewModel - 顯然這可能只適用於視圖優先的方法

所以你所需要做的就是構建你的意見,我發現上面(正確的命名空間等),然後基於的IsLoggedInAs價值和EditMode

+0

非常感謝!將需要幾天,直到我可以完全檢查出來,但我會確定。然後回到你身邊! – EluciusFTW 2013-03-13 11:34:27

+0

我會發佈一個示例項目 - 我幾乎有一個如此...:P還不如 – Charleh 2013-03-13 11:37:48

+0

好吧,如果你想要一個樣本,我會郵寄給你,因爲這裏的互聯網安全服務器不會讓我做diddly蹲:) – Charleh 2013-03-13 11:51:09