C# 根据类属性具体类型(非类类型)创建WPF数据模板
我正在学习以下课程:C# 根据类属性具体类型(非类类型)创建WPF数据模板,c#,wpf,datatemplate,C#,Wpf,Datatemplate,我正在学习以下课程: public class ConcreteClassFoo { public ObservableCollection<ConcreteComponent> Components { get; set; } } public class ConcreteComponent { IAttribute Foo { get; set; } } public class ConcreteAttribute1 : IAttribute {} publi
public class ConcreteClassFoo
{
public ObservableCollection<ConcreteComponent> Components { get; set; }
}
public class ConcreteComponent
{
IAttribute Foo { get; set; }
}
public class ConcreteAttribute1 : IAttribute {}
public class ConcreteAttribute2 : IAttribute {}
但是,如何根据具体的类属性类型构建不同的模板呢
更新:
我补充了一些关于我实际问题的信息
我有一个列表视图
包含一个名为形状
的可观察集合
。对象BaseWindowShape
具有一个属性AdditionalData
(AdditionalData
是抽象的),该属性可以是DistanceAdditionalData
或TermLoaditionalData
我想根据附加数据
具体类型更改che列表视图
视图(列表视图
中的所有基本窗口形状
共享相同的具体附加数据
)
因此,如果第一个形状的AdditionalData
是DistanceAtAdditionalData
,我希望有三列
否则我只想有两列
MaxDistance
和MinAreaPercent
是DistanceAdditionalData
属性,而MaxTemperature
是TermLoadAdditionalData
属性
我尝试以以下方式实现此行为,但它不起作用
我怎样才能解决我的问题
<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>
并将其绑定为我的第一个列表视图的ItemsSource
。
作为第一个组件的数据模板
,我声明了另一个列表视图
,绑定到集合组件
,以便根据它有不同的列。
如果集合的第一个元素的属性为ConcreteAttribute1
,则会得到以下结果:
否则,请执行以下操作:
可能这不是实现此结果的最佳方法(我必须声明一个只包含一个元素的可观察集合
,以检查它),但它是有效的。由于我没有真正获得您想要的结果,我只能猜测,这就是您想要做的:
<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>
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;
}
public主窗口(){
初始化组件();
this.Components=新的ObservableCollection();
Add(new-ConcreteComponent{Foo=new-ConcreteAttribute1()});
Add(new-ConcreteComponent{Foo=new-ConcreteAttribute2()});
this.DataContext=this;
}
公共可观测集合组件{
得到;
}
结果
注意
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;
}
确保你没有打字错误。
如果它仍然不工作,可能是错误输出和/或异常的后屏幕我认为它很快就能解决我的问题。我更新了我的问题,添加了更多的信息和我的(错误的)实现,在你的回答之后,告诉我现在是否一切都清楚了,如果你能给我一些建议来解决我的问题。非常感谢@罗文迪什语更新Post@lokuskinig非常好用,谢谢!为了解决实际问题,我使用集合的第一个元素在另一个列表视图中创建了一个列表视图,以决定创建哪种列(请参阅我的第二次更新);我不认为这是解决问题的最好方法,但实际上它是有效的。如果你有一个更优雅的方式来实现同样的结果,那将是伟大的!如果您想基于类型以外的其他内容选择模板,您可能会发现它也很有用。例如,关于字符串属性的值
<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;
}
}
<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;
}