根据类属性具体类型(不是类类型)创建WPF DataTemplate

时间:2016-07-25 08:47:42

标签: c# 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属性是抽象类型ConcreteComponent HAS-A 属性Foo的{​​{1}}集合。

我想根据属性IAttribute的具体类更改ListView模板。

使用Foo,可以根据类具体类型构建不同的模板,例如:

DataTemplate

但是如何根据具体类属性类型构建不同的模板呢?

更新

我为实际问题增加了一些信息。

我的<DataTemplate DataType="{x:Type ConcreteComponent1}" /> <DataTemplate DataType="{x:Type ConcreteComponent2}" /> 包含名为ListView的{​​{1}}。对象ObservableCollection<BaseWindowShape>的属性ShapesBaseWindowShape是抽象的)可以是AdditionalDataAdditionalData

我希望根据DistanceAdditionalData具体类型更改che TermoAdditionalData视图(ListView中的所有AdditionalData共享相同的具体{{1} }})。

因此,如果第一个形状的BaseWindowShapeListView,我希望有三列

DistanceAdditionalData

否则,我希望只有两列

TermoAdditionalData

AdditionalDataAdditionalData属于DistanceAtdditionalData个属性,而MaxDistance属于MinAreaPercent属性。

我尝试以下列方式实现此行为,但它不起作用。

我怎么能解决我的问题?

DistanceAdditionalData

更新2 : 我使用 lokusking 回答来更新我的实现,这里是:

MaxTemperature

我添加了一个名为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>

并将其绑定为我的第一个<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> 的{​​{1}}。 正如FirstComponent public ObservableCollection<ConcreteComponent> FirstComponent { get; } = new ObservableCollection<ConcreteComponent> { Components.First() }; 我宣布了另一个ItemsSource,绑定到集合ListView,以便具有不同的列,具体取决于它。 如果我的集合的第一个元素的属性为DataTemplate,我会得到以下结果:

enter image description here

否则以下一个:

enter image description here

可能这不是实现此结果的最佳方式(我必须声明只有一个元素的FirstComponent才能检查它)但是它可以工作。

1 个答案:

答案 0 :(得分: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

注意

确保你没有错别字。 如果它仍然不起作用,可能会发布错误输出和/或异常的屏幕