2016-07-25 94 views
1

我有以下類工作:創建WPF DataTemplate中取決於類屬性具體類型(不是類類型)

public class ConcreteClassFoo 
{ 
    public ObservableCollection<ConcreteComponent> Components { get; set; } 
} 

public class ConcreteComponent 
{ 
    IAttribute Foo { get; set; } 
} 

public class ConcreteAttribute1 : IAttribute {} 
public class ConcreteAttribute2 : IAttribute {} 

在我的XAML映射:

<ListView ItemsSource={Bindings Components} /> 

正如你所看到的,我的ListBoxComponents屬性綁定爲ItemsSource

Components屬性是ConcreteComponentHAS-A抽象類型IAttribute屬性Foo的集合。

我想更改ListView模板,具體取決於我的屬性Foo的具體類別。

隨着DataTemplate有可能取決於類具體類型構建不同的模板,例如:

<DataTemplate DataType="{x:Type ConcreteComponent1}" /> 
<DataTemplate DataType="{x:Type ConcreteComponent2}" /> 

但怎麼可能取決於具體類屬性類型建立不同的模板?

UPDATE

添加對我的實際問題一些相關信息。

我有一個ListView包含一個ObservableCollection<BaseWindowShape>Shapes。對象有一個屬性AdditionalDataAdditionalData是抽象的),可以是DistanceAdditionalDataTermoAdditionalData

我想這取決於AdditionalData具體類型(在ListView共享所有相同的混凝土AdditionalData)改變澈ListView視圖。

因此,如果第一形狀的AdditionalData,例如,是DistanceAtdditionalData我想有三列

DistanceAdditionalData

否則,我想只有兩個列

TermoAdditionalData

MaxDistance and MinAreaPercent are DistanceAdditionalData attributes,while MaxTemperature is a TermoAdditionalData屬性。

我嘗試以下列方式實現此行爲,但它不起作用。

我該如何解決我的問題?

<ListView ItemsSource="{Binding Shapes}"> 
    <ListView.Resources> 
     <DataTemplate DataType="{x:Type additionalData:TridimensionalAdditionalData}"> 
      <ListView> 
       <ListView.View> 
        <GridView> 
         <GridViewColumn Header="Level"> 
          <GridViewColumn.CellTemplate> 
           <DataTemplate> 
            <wpfControls:DigitInput Value="{Binding Level, Mode=TwoWay}" /> 
           </DataTemplate> 
          </GridViewColumn.CellTemplate> 
         </GridViewColumn> 
         <GridViewColumn Header="Max Distance"> 
          <GridViewColumn.CellTemplate> 
           <DataTemplate> 
            <StackPanel> 
             <xctk:DoubleUpDown Value="{Binding MaxDistance}"/> 
             <TextBlock Text="mm"> 
            </StackPanel> 
           </DataTemplate> 
          </GridViewColumn.CellTemplate> 
         </GridViewColumn> 
         <GridViewColumn Header="Min Area"> 
          <GridViewColumn.CellTemplate> 
           <DataTemplate> 
            <xctk:DoubleUpDown Value="{Binding MinAreaPercent}" /> 
           </DataTemplate> 
          </GridViewColumn.CellTemplate> 
         </GridViewColumn> 
         </GridView> 
       </ListView.View> 
      </ListView> 
     </DataTemplate> 
     <DataTemplate DataType="{x:Type additionalData:ThermalAdditionalData}"> 
      <ListView> 
       <ListView.View> 
        <GridView> 
         <GridViewColumn Header="Level"> 
          <GridViewColumn.CellTemplate> 
           <DataTemplate> 
            <wpfControls:DigitInput Value="{Binding Level, Mode=TwoWay}" /> 
           </DataTemplate> 
          </GridViewColumn.CellTemplate> 
         </GridViewColumn> 
         <GridViewColumn Header="Max Temperature"> 
          <GridViewColumn.CellTemplate> 
           <DataTemplate> 
            <StackPanel> 
             <xctk:DoubleUpDown Value="{Binding MaxTemperature}"/> 
             <TextBlock Text=" °F"/> 
            </StackPanel> 
           </DataTemplate> 
          </GridViewColumn.CellTemplate> 
         </GridViewColumn> 
        </GridView> 
       </ListView.View> 
      </ListView> 
     </DataTemplate> 
    </ListView.Resources> 
    <ListView.ItemTemplate> 
     <DataTemplate> 
      <ContentControl Content="{Binding AdditionalData}" /> 
     </DataTemplate> 
    </ListView.ItemTemplate> 
</ListView> 

更新2: 我使用lokusking答案更新我的實現,那就是:

<ListView ItemsSource="{Binding FirstComponent}"> 
<ListView.Resources> 
    <DataTemplate DataType="{x:Type local:ConcreteAttribute1}"> 
     <ListView ItemsSource="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=Components}"> 
      <ListView.View> 
       <GridView> 
        <GridViewColumn Header="1 column"> 
         <GridViewColumn.CellTemplate> 
          <DataTemplate> 
            <TextBlock Text="{Binding Foo.Name, Mode=OneWay}" /> 
          </DataTemplate> 
         </GridViewColumn.CellTemplate> 
        </GridViewColumn> 
        <GridViewColumn Header="2 column"> 
         <GridViewColumn.CellTemplate> 
          <DataTemplate> 
           <TextBox Text="{Binding Foo.Number, Mode=OneWay}"/> 
          </DataTemplate> 
         </GridViewColumn.CellTemplate> 
        </GridViewColumn> 
       </GridView> 
      </ListView.View> 
     </ListView> 
    </DataTemplate> 
    <DataTemplate DataType="{x:Type local:ConcreteAttribute2}"> 
     <ListView ItemsSource="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=Components}"> 
      <ListView.View> 
       <GridView> 
        <GridViewColumn Header="3 column"> 
         <GridViewColumn.CellTemplate> 
          <DataTemplate> 
           <TextBlock Text="{Binding Foo.Name, Mode=OneWay}"/> 
          </DataTemplate> 
         </GridViewColumn.CellTemplate> 
        </GridViewColumn> 
        <GridViewColumn Header="4 column"> 
         <GridViewColumn.CellTemplate> 
          <DataTemplate> 
           <CheckBox IsChecked="{Binding Foo.B, Mode=OneWay}" /> 
          </DataTemplate> 
         </GridViewColumn.CellTemplate> 
        </GridViewColumn> 
       </GridView> 
      </ListView.View> 
     </ListView> 
    </DataTemplate> 
</ListView.Resources> 
<ListView.ItemTemplate> 
    <DataTemplate> 
     <ContentControl Content="{Binding Foo}" /> 
    </DataTemplate> 
</ListView.ItemTemplate> 
</ListView> 

我加宣佈了一個名爲FirstComponent屬性爲:

public ObservableCollection<ConcreteComponent> FirstComponent { get; } = new ObservableCollection<ConcreteComponent> { Components.First() }; 

並將其綁定爲我的第一個0123的。 作爲DataTemplateFirstComponent我宣佈另一個ListView,綁定到集合Components爲了有不同的列取決於它。 如果我收藏的第一個元素的ConcreteAttribute1我有以下結果的屬性:下一個

enter image description here

否則:

enter image description here

也許它不是最好的辦法實現這個結果(我必須聲明一個ObservableCollection只有一個元素才能檢查它),但它的工作原理。

回答

2

因爲我真的不得到你想要達到的,我只能猜測,這是你想要做什麼什麼:

<ListView ItemsSource="{Binding Components}"> 
      <ListView.Resources> 
       <DataTemplate DataType="{x:Type ConcreteAttribute1}"> 
        <TextBlock Text="Con1"></TextBlock> 
       </DataTemplate> 
       <DataTemplate DataType="{x:Type ConcreteAttribute2}"> 
        <TextBlock Text="Con2"></TextBlock> 
       </DataTemplate> 
      </ListView.Resources> 
      <ListView.ItemTemplate> 
       <DataTemplate> 
        <ContentControl Content="{Binding Foo}"></ContentControl> 
       </DataTemplate> 
      </ListView.ItemTemplate> 
     </ListView> 

如果這不能解決你的問題,請解釋自己一點更

編輯

這裏我演示,執行和結果:

public class ConcreteComponent { 
    public IAttribute Foo { 
     get; set; 
    } 
    } 

    public class ConcreteAttribute1 : IAttribute { 
    public string Name => "ConAtt 1"; 
    public int Number => 999; 

    } 
    public class ConcreteAttribute2 : IAttribute { 
    public string Name => "ConAtt 2"; 
    public bool B => true; 

    } 

    public interface IAttribute { 
    string Name { 
     get; 
    } 
    } 

XAML

<ListView ItemsSource="{Binding Components}"> 
    <ListView.Resources> 
     <DataTemplate DataType="{x:Type ConcreteAttribute1}"> 
      <StackPanel> 
       <TextBlock Text="{Binding Name, Mode=OneWay}"/> 
       <TextBox Text="{Binding Number, Mode=OneWay}"></TextBox> 
      </StackPanel> 
     </DataTemplate> 
     <DataTemplate DataType="{x:Type ConcreteAttribute2}"> 
      <StackPanel> 
       <TextBlock Text="{Binding Name, Mode=OneWay}"/> 
       <CheckBox IsChecked="{Binding B, Mode=OneWay}"></CheckBox> 
      </StackPanel> 
     </DataTemplate> 
    </ListView.Resources> 
    <ListView.ItemTemplate> 
     <DataTemplate> 
      <ContentControl Content="{Binding Foo}" /> 
     </DataTemplate> 
    </ListView.ItemTemplate> 
</ListView> 

使用

public MainWindow() { 
     InitializeComponent(); 
     this.Components = new ObservableCollection<ConcreteComponent>(); 
     this.Components.Add(new ConcreteComponent { Foo = new ConcreteAttribute1() }); 

     this.Components.Add(new ConcreteComponent { Foo = new ConcreteAttribute2() }); 


     this.DataContext = this; 
    } 

    public ObservableCollection<ConcreteComponent> Components { 
     get; 
    } 

結果

ExampleResult

注意

確保你不要有錯別字。 如果它仍然沒有工作,也許後錯誤的輸出和/或異常屏幕

+0

我認爲這是非常接近解決我的問題。我更新了我的問題,在答案後添加了更多信息和我的(錯誤)實現,告訴我是否現在一切都清楚了,如果你能給我一些建議,那麼解決我的問題。非常感謝! – Rowandish

+0

@Rowandish更新後發佈 – lokusking

+0

@lokuskinig它完美的工作,謝謝!爲了解決我的實際問題,我使用集合的第一個元素創建了一個ListView,以決定創建哪種列(參見我的第二個更新);我不認爲這是解決問題的最好方法,但實際上它是有效的。如果你有一個更優雅的方式來達到相同的結果,那就太棒了! – Rowandish