我有以下ViewModel:
// Top-level Policy ViewModel
class MainWindowVM {
// A collection of ViewModels, each mapping to an application role.
public List<RolePolicyVM> ComponentPolicyVMs { get; set; } = new();
}
// Contains the component policies pretaining to a specific application roles.
class RolePolicyVM {
// Role name
public String Name { get; set; }
// Component policies applying to the ADCS role.
public List<ComponentPolicyVM> ComponentPolicies { get; set; } = new();
}
// Contains the component policies pretaining to a specific agent plugin or worker
class ComponentPolicyVM {
// Plugin or worker Id. Not rendered.
public Guid Id { get; set; }
// The description of the setting to be displayed in the AgentConfig tool
public String Description { get; set; }
// The tooltip to be displayed when mousing over the Description TextBlock
public String ToolTipText { get; set; }
// The value to bind to a control
public Object Value { get; set; }
// The data type of "Value".
// This property determines what type of control to render.
public Type ValueType { get; set; }
}
我需要创建一个DataGrid或TreeView控件,它是基于AppPolicyVM.ComponentPolicyVMs
中的元素动态填充的。
- 顶层层次结构绑定到
RolePolicyVM.Name
- 第二级必须包含2列:
- 第一列绑定到
ComponentPolicyVM.Description
- 第二列绑定到
ComponentPolicyVM.Value
,但这里是它变得棘手的地方:我需要这里呈现的控件是基于ComponentPolicyVM.ValueType
的值动态的。例如,如果它是typeof(string)
,我们会看到一个TextBox。如果它是typeof(bool)
,它是一个复选框。我需要支持bool
,string
和int
。
我已经渲染了一个TreeView
,它总是渲染一个复选框:
我所坚持的(甚至不确定这是否可能)是如何添加逻辑,以动态呈现基于ComponentPolicyVM.ValueType
的适当类型的控件。
以下是我目前为止的XAML:
<Window x:Class="AppPolicyConfig.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:vm="clr-namespace:AppPolicyConfig.ViewModels"
xmlns:local="clr-namespace:AppPolicyConfig"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Window.DataContext>
<vm:MainWindowVM/>
</Window.DataContext>
<TreeView x:Name="MainTreeView"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Margin="10"
ItemsSource="{Binding ComponentPolicyVMs}">
<TreeView.ItemContainerStyle>
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="IsExpanded" Value="True" />
</Style>
</TreeView.ItemContainerStyle>
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding ComponentPolicies}" DataType="{x:Type vm:RolePolicyVM}">
<TextBlock Text="{Binding Name}"/>
<HierarchicalDataTemplate.ItemTemplate>
<DataTemplate DataType="{x:Type vm:ComponentPolicyVM}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="300" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0"
Text="{Binding Description}"/>
<CheckBox Grid.Column="1"
IsChecked="{Binding Value}"/>
</Grid>
</DataTemplate>
</HierarchicalDataTemplate.ItemTemplate>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
</Window>
2条答案
按热度按时间yacmzcpb1#
我所坚持的(并且不确定这是否可能)是如何添加逻辑,该逻辑可以基于ComponentPolicyVM.ValueType动态呈现适当的控件类型。
尝试将
TreeView
的ItemTemplateSelector
属性设置为自定义DataTemplateSelector
,该自定义DataTemplateSelector
基于ComponentPolicyVM
的ValueType
属性的值返回DataTemplate
,例如:mdfafbf12#
您可以使用
DataTemplate
来根据Type进行选择,与ContentTemplateSelector
配对,因此切换ComponentPolicyVM
的模板:DataTemplate示例:
组件选择器示例:
然后在一些资源文件中,你需要为你需要的东西定义数据模板(
ValueTypeIntTemplate
,ValueTypeStringTemplate
,ValueTypeBoolTemplate
)你的模板可以在任何地方定义,只需要确保container
可以看到它们(即导入资源),这样选择器就可以找到它们。