2013-03-26 22 views
1

我有以下設置:動態設置用戶控件作爲列表框的DataTemplate體

<ListBox ItemSource="{Binding Targets}"> 
    <ListBox.ItemTemplate> 
     <DataTemplate> 
      <view:ViewName /> 
     </DataTemplate> 
    </ListBox.ItemTemplate> 
</ListBox> 

我試圖做到的是動態地決定哪些查看在運行時使用的基礎上,ListBoxDataContext中的屬性。簡單地說,我想用一個返回正確視圖的數據綁定來代替<view:ViewName>

我使用MEF爲我的應用程序提供可能需要提供自定義視圖以在適當時顯示項目的插件。在設計時我不會知道所有可能的視圖類型(它們可能是從DLL動態加載的),所以簡單的DataTemplateSelector不會。

我已經研究瞭解決方案,但已經空了。

+0

你還好嗎使用一些其他輔助類或類似的 - 只要你查看視圖模型只是一個 - 和單一屬性 - 或多個屬性在您的虛擬機中。有很多解決方案,稍後我會嘗試寫點東西 - 我只需要知道目標是什麼。例如。看到這個'flags'解決方案(解決方案2)http://stackoverflow.com/questions/15550344/genrating-views-usercontrols-using-contentcontrol/15550477#15550477 - (你可以映射這不僅僅是兩個'選擇等) - 但是我經常使用更好的方法。 – NSGaga 2013-03-26 18:59:21

+0

我沒有使用助手/轉換器/等問題。我可以使用一個解決方案,它要求我在設計時在xaml中列出所有可能的選擇,因爲那時我不會知道它們。我想最簡單的方法來演示我需要的是爲DataTemplate添加一個假設屬性,如下所示:''其中View是ListBox的DataTemplate中的一個屬性。 – 2013-03-26 19:05:59

+0

可能是一個包含視圖名稱的字符串。我認爲,我可以安排所有的觀點都在同一個命名空間,即使是動態的。而上面我的意思是「ListBox的DataContext」,但我剛用完編輯時間 – 2013-03-26 19:10:34

回答

1

使用DataTemplateManagerthis post你可以這樣做:

DataTemplateManager.RegisterDataTemplate<ViewModelType1, ViewType1>(); 
DataTemplateManager.RegisterDataTemplate<ViewModelType2, ViewType2>(); 
DataTemplateManager.RegisterDataTemplate<ViewModelType3, ViewType3>(); 

那麼你會刪除ListBox中ItemTemplate

<ListBox ItemSource="{Binding Targets}"/> 

和ListBox中的視圖模型,你可以:

public void AddTargets() 
{ 
    Targets.Add(new ViewModelType1()); 
    Targets.Add(new ViewModelType2()); 
    Targets.Add(new ViewModelType3()); 
} 

然後,每個WPF會自動使用來呈現每個對應的ViewModel。

另外請注意,您可以在顯示ListBox之前隨時調用DataTemplateManager.RegisterDataTemplate(),因此理論上可以在加載MEF零件時執行該操作。

編輯:

基於您的評論,你可以創建一個單一的DataTemplate與ContentPresenter根據視圖模型屬性顯示所選查看:

<DataTemplate DataType="{x:Type local:TargetViewModel}"> 
    <ContentPresenter x:Name="MainContentPresenter" Content="{Binding}" ContentTemplate="{Binding YourProperty, Converter=SomeConverter}"/> 

和SomeConverter你應該內使用與帖子中演示的相同的技術來動態生成DataTemplate。

+0

這真棒,如此接近我真正想做的事情。如果必須的話,我可以使用它。但我真正想要的是基於單個視圖模型中的屬性選擇我的視圖,而不是爲每個視圖分別創建視圖模型。我有一個類型爲IAction的Action屬性的TargetViewModel。實現IAction的各個具體類可以提供要顯示的視圖的名稱。因此,在理想的世界中,ListBox將使用TargetViewModel.Action.View來確定要顯示的視圖。 – 2013-03-26 18:54:36

+0

這很好。我只需要意識到我需要爲每個Action分別創建視圖模型。無論如何,我正在試圖通過IAction參考嘗試與特定的Action類一起工作。通過這種方式,我有一個具有正確類型的具體操作成員的視圖模型,以便我的視圖可以獲取所需的信息。 Action的提供者現在需要證明一個視圖模型,但我將大部分工作抽象爲一個基類。它效果很好,比我最初尋找的解決方案更好。謝謝! – 2013-03-27 13:59:51

2

既然你要根據綁定的值更改模板,你可以使用一個DataTrigger確定的ListBoxItem

<Style TargetType="{x:Type ListBoxItem}"> 
    <Setter Property="ContentTemplate" Value="{StaticResource DefaultTemplate}"/> 
    <Style.Triggers> 
     <DataTrigger Property="{Binding SomeProperty}" Value="A"> 
      <Setter Property="ContentTemplate" Value="{StaticResource TemplateA}"/> 
     </DataTrigger> 
    </Style.Triggers> 
</Style> 

我找到ContentTemplate這比使用DataTemplateSelector,因爲它得到重新評估,如果更好綁定屬性會發生變化,而DataTemplateSelector不會。

如果要根據對象類型更改模板,可以使用隱式DataTemplates。這些是DataTemplates,它們定義了DataType,但沒有x:Key,它們將在WPF嘗試繪製指定類型的對象時隨時使用。

例如,如果您曾在定義這個模板您<X.Resources>地方

<DataTemplate DataType="{x:Type models:ActionA}"> 
    <views:ActionAView /> 
</DataTemplate> 

,那麼你可以直接插入你的模型對象到用戶界面和WPF將使用指定

<ContentControl Content="{Binding SomeIActionObject}" /> 

<ItemsControl ItemsSource="{Binding CollectionOfIActionObjects}" /> 
模板繪製

更新

您提到您將允許用戶創建與開始使用MEF導入其他模板模塊,所以在這種情況下,你可能會更好使用的IValueConverter是查找中Application.Resources

例如匹配的模板,如果綁定的值等於"A",那麼轉換器可能搜索Application.Resources名爲"TemplateA"模板,並將其返回結合

<Style TargetType="{x:Type ListBoxItem}"> 
    <Setter Property="ContentTemplate" 
      Value="{Binding SomeProperty, 
       Converter={StaticResource MyTemplateConverter}}"/> 
</Style> 
+0

這實際上工作得很好,除了我在設計時不知道可能的值集合來創建靜態資源。 – 2013-03-26 19:17:36

+0

@ user1394408那麼你必須事先創建你的'Templates'嗎?你不能只寫「如果Property = Z然後使用TemplateZ」,並沒有TemplateZ定義的地方。我想你可以使用'Converter'來代替DataTrigger,它會查看綁定的屬性,然後在Application.Resources中搜索匹配該屬性的模板並返回它。 – Rachel 2013-03-26 19:19:50

+0

@Rachel在說些什麼很有意義 - 你需要在某個時候修正某些問題 - 或者你打算怎麼做 – NSGaga 2013-03-26 19:23:50

相關問題