WPF 数据绑定与以编程方式生成控件



我的底层数据结构由基于公共抽象类构建的对象层次结构组成:

public abstract class model {
public string name {get;};
public string type {get;};
}
public class A:model {
public int val1 {get; set;}; 
}
public class B:model {
public int val2 {get; set;}; 
}
public class C:B {
public Dictionary<string, int> extra_props; 
}

我的目标是创建一个UI,在选择对象时,它能够动态预览,但也能够修改对象的基础属性。

我是关于 WPF 的绝对菜鸟,所以我不知道它的全部功能是什么。现在,关于单值属性,我已经找到了使用数据绑定将属性绑定到 UI 元素的方法。它就像一个用于显示和修改值的魅力。

<GroupBox x:Name="InfoBox" Header="Object Information">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="41*"/>
<ColumnDefinition Width="200*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="20"/>
<RowDefinition Height="20"/>
<RowDefinition Height="20"/>
<RowDefinition Height="50*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<DockPanel Grid.Row="0" Grid.ColumnSpan="2" >
<TextBlock>Name:</TextBlock>
<TextBlock Text="{Binding name}" HorizontalAlignment="Right"></TextBlock>
</DockPanel>
<DockPanel Grid.Row="1" Grid.ColumnSpan="2" >
<TextBlock>Type:</TextBlock>
<TextBlock Text="{Binding type}" HorizontalAlignment="Right"></TextBlock>
</DockPanel>
<DockPanel Grid.Row="2" Grid.ColumnSpan="2" >
<TextBlock>Material Name:</TextBlock>
<TextBlock Text="{Binding val1}" HorizontalAlignment="Right"></TextBlock>
</DockPanel>
</Grid>
</GroupBox>

问题 1:当绑定类型B的对象时,属性val1不存在,我在调试输出中收到一些绑定错误。这些在执行过程中根本不会导致问题,但我发现没有办法捕获它们并返回默认值或其他东西。

我想到的解决此问题的唯一方法是在抽象类中添加所有所需的属性,以便它们都存在于所有具有一些 null 值或其他内容的派生类上,但这感觉根本不对。

问题2:对于像C这样更复杂的类,我想根据类的属性集/列表动态生成UI。目前,我完全不知道如何使用数据绑定来做到这一点,除了在 XML 中逐个添加它们并解决问题 1 的问题。

我想到的最可行的解决方案是以编程方式生成一个控件并将其添加到主窗口中,其中包含我需要的类属性的文本框和输入,并再次以编程方式希望能够将对象绑定到控件,以便正确读取/设置值。显然,此方法也可以解决问题1。

我什至不确定这个解决方案是否可行,但无论如何,我需要建议和建议,主要是关于是否有办法解决我的数据绑定问题,或者我是否应该以编程方式更新 UI(如果可能)。

对于菜鸟来说,到目前为止你做得很好:)实际上,这两个问题都有一个非常简单的解决方案:数据模板。您可以在微软网站上阅读有关它们的所有信息。

在您的情况下,您希望为尝试显示的每种类型声明一个单独的模板:

<DataTemplate DataType="{x:Type local:A}">
<TextBlock Text="This object is type A">
</DataTemplate>
<DataTemplate DataType="{x:Type local:B}">
<TextBlock Text="This object is type B">
</DataTemplate>

。等等。这通常在出现此代码的任何窗口/用户控件的"资源"块中完成,尽管也可以在 App.xaml 资源块等中声明。

数据模板由能够以某种方式绑定到数据的任何 WPF 控件使用。以Button为例。按钮的整体外观,包括边框以及鼠标悬停等的行为方式由其控件模板决定(当然,您也可以覆盖自己)。但是在 XAML 中的某个时刻,它必须呈现你分配给其"Content"属性的实际数据,如果你要查看按钮的控件模板,你会发现里面埋藏着这样的东西:

<ContentPresenter />

这有效地说"好的,这是我的实际数据应该呈现的地方,但我希望你引用对象的相应 DataTemplate,而不是在这里专门声明它"。通过这种方式,您可以使用单个控件模板创建顶级按钮样式,但随后可以为要在其中呈现的每种类型的事物指定多个 DataTemplates。

许多控件都使用DataTemplate,包括ListBox等控件,其中列表中的每个元素都可以根据其类型提供不同的图形表示形式。回到你自己的具体问题,如果你只想渲染数据本身,没有任何花里胡哨等,那么只需使用ContentControl

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

因此,MyModel应该是视图模型层(或已将 DataContext 设置为的任何其他内容)中的model类型的属性。将该属性指定为类型 A、B 或 C 的实例将导致 ContentControl 填充您在 DataTemplate 中声明的任何内容的实例。

最新更新