Telerik:RadPropertyGrid 似乎无法在集合 Editor/Picker 中呈现嵌套 类
Telerik: RadPropertyGrid does not seem to render nested classes in Collection Editor/Picker
我的问题是二级集合不呈现内部(嵌套)classes 的成员。
二级意味着在 Collections Add/Remove 编辑器中(CollectionEditorPicker)。
我希望在图 2 中显示 class 'powerVoltageDefinition' 的所有内部成员,就像我们在图 1.
有什么诀窍?我如何在这个默认的 Collection Add/Remove 编辑器中显示这样的内部 classes(所谓的 'CollectionEditorPicker')?
图 1 - 正确呈现的嵌套 class 成员
图 2 - 未呈现嵌套 class 成员
XAML 此 RadPropertyGrid 的片段
<telerik:RadPropertyGrid x:Name="SelectedProperty"
AutoGenerateBindingPaths="True"
AutoGeneratePropertyDefinitions ="True"
AutoGeneratingPropertyDefinition="RadPropertyGrid_AutoGeneratingPropertyDefinition"
CanUserResizeDescriptionPanel="True"
NestedPropertiesVisibility="Visible"
DescriptionPanelVisibility="Visible"
SearchInNestedProperties="True"
PropertySetMode="Union"
RenderMode="Hierarchical"
EditMode="Default"
EditEnded="CellEditEnded"
ToolTip="ToDo: Tool Tips">
</telerik:RadPropertyGrid>
我已经调查过:
2. And this solution does not cover my nested class powerVoltageDefinition
我的解决方案会导致这些吗?:
由于 Telerik 似乎不支持将其原生 CollectionEditor/Picker
附加到 RadPropertyGrid
的情况,我们的第二个最佳选择是(恕我直言)创建自己的 WPF 控件。
这是我对这种 "generic" 控制的建议:
UniCollectionPropertyGrid.XAML:
<UserControl x:Class="TrackDataEditor.XAML.UniCollectionPropertyGrid"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:TrackDataEditor.XAML"
xmlns:telerik="http://schemas.telerik.com/2008/xaml/presentation"
xmlns:telerikDocking="clr-namespace:Telerik.Windows.Controls;assembly=Telerik.Windows.Controls.Docking"
mc:Ignorable="d"
d:DesignHeight="400" d:DesignWidth="700">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<!-- The Items Pane -->
<!-- <telerikDocking:RadPane x:Name="TemplatesPane" Header="Templates"> -->
<Grid Grid.Column="0" Grid.Row="0">
<!-- Icons to control template instances-->
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!-- #### +/- Buttons #### -->
<DockPanel x:Name="Buttons" Grid.Row="0" HorizontalAlignment="Stretch">
<Button x:Name="AddItemButton" Foreground="Green" HorizontalAlignment="Stretch" VerticalAlignment="Top" Width="30" ToolTip="Add an element" Click="AddItem">{+}</Button>
<Button x:Name="RemoveItemButton" Foreground="Red" HorizontalAlignment="Left" VerticalAlignment="Top" Width="30" ToolTip="Remove the selected element" Click="RemoveItem">{-}</Button>
<Button x:Name="RedrawPropGridButton" HorizontalAlignment="Left" VerticalAlignment="Top" Width="30" ToolTip="Redraw actualy selected element" Click="RedrawPropGrid">{R}</Button>
</DockPanel>
<!-- #### Lister of items #### -->
<telerik:RadGridView Grid.Row="1"
x:Name="TheListOfItems" ItemsSource="{Binding}" CanUserReorderColumns="True"
SelectionChanged="ListOfItems_SelectionChanged"
Loaded="ListOfItems_Loaded"
CanUserInsertRows="True" CanUserDeleteRows="True"
AutoGenerateColumns="True"
RowIndicatorVisibility="Collapsed"
ShowGroupPanel="False">
</telerik:RadGridView>
</Grid>
<!-- #### Properties of selected item #### -->
<telerik:RadPropertyGrid Grid.Column="1" Grid.Row="1"
x:Name="ThePropertyGrid"
AutoGenerateBindingPaths="True"
AutoGeneratePropertyDefinitions ="True"
AutoGeneratingPropertyDefinition="PropertyGrid_AutoGeneratingPropertyDefinition"
DescriptionPanelVisibility="Collapsed"
CanUserResizeDescriptionPanel="True"
OverridesDefaultStyle="True"
SearchBoxVisibility="Collapsed"
SearchInNestedProperties="True"
NestedPropertiesVisibility="Visible"
RenderMode="Hierarchical"
PropertySetMode="Intersection"
EditMode="Default"
EditEnded="PropertyGrid_CellEditEnded"
SelectionChanged="PropertyGrid_SelectionChanged"
FieldIndicatorVisibility ="Collapsed"
EnableEditorCaching ="True"
EnableCustomFiltering ="False"
ToolTip="ToDo: Tool Tips">
</telerik:RadPropertyGrid>
<!-- EditEnded="CellEditEnded" -->
</Grid>
背后的C#代码:
UniCollectionPropertyGrid.XAML.cs
/// <summary>
/// Interaction logic for UniCollectionPropertyGrid.xaml
/// </summary>
public partial class UniCollectionPropertyGrid : UserControl
{
private static Logger logger = LogManager.GetCurrentClassLogger();
// C-tor
public UniCollectionPropertyGrid()
{
InitializeComponent();
}
/// <summary>
/// Called when user clicks add item button: {+}
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void AddItem(object sender, RoutedEventArgs e)
{
if (this.DataContext is SomeDataContextClass)
{
SomeDataContextClass dataCtx = (this.DataContext as SomeDataContextClass);
dynamic newItem = null;
// What is being currenlty edited (this was unfortunatelly "impossible?" to pass dynamically.
// (Why ? Because by this time, Telerik & WPF neither seem to provide no mechanism to distinguish generic controls like this one, generated by editor template (factory) ...)
switch (MainWindow.EditedPropertyName)
{
case "Property1":
newItem = new Property1Type();
dataCtx.Property1_List.Add(newItem as Property1Type);
TheListOfItems.ItemsSource = dataCtx.Property1_List;
break;
case "Property2":
newItem = new Property2Type();
dataCtx.Property2_List.Add(newItem as Property2Type);
TheListOfItems.ItemsSource = dataCtx.Property2_List;
break;
}
// Set the newly added item as selected
TheListOfItems.SelectedItem = newItem;
// SetBinding it to property grid to be rendered
ThePropertyGrid.Item = newItem;
}
}
/// <summary>
/// Called when user clicks remove item button: {-}
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void RemoveItem(object sender, RoutedEventArgs e)
{
// Leave right away if no item is selected
if (TheListOfItems.SelectedItem == null) return;
if (this.DataContext is SomeDataContextClass)
{
SomeDataContextClass dataCtx = (this.DataContext as SomeDataContextClass);
switch (MainWindow.EditedPropertyName)
{
case "Property1":
dataCtx.Property1_List.Remove(TheListOfItems.SelectedItem as Property1Type);
break;
case "Property2":
dataCtx.Property2_List.Remove(TheListOfItems.SelectedItem as Property2Type);
break;
}
}
// Nothing to show on property grid
ThePropertyGrid.Item = null;
}
/// <summary>
/// Called when user clicks Redraw property grid button: {R}
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void RedrawPropGrid(object sender, RoutedEventArgs e)
{
// This redraws, however closes all opened elements in property grid
ThePropertyGrid.Item = null;
ThePropertyGrid.Item = TheListOfItems.SelectedItem;
}
// ------------------------------------------------------------------------------------------------
#region LIST_OF_ITEMS_EVENT_HANDLERS
/// <summary>
/// Fired, when user clicks on any item of the ListOfItems table (RadGridView).
/// Is used to set selected item to the property grid
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void ListOfItems_SelectionChanged(object sender, Telerik.Windows.Controls.SelectionChangeEventArgs e)
{
// Try to redraw - wonder if this works
// this.Arrange(new Rect(RenderSize));
// this.UpdateLayout();
ThePropertyGrid.Item = this.TheListOfItems.SelectedItem;
// Prevent further traveling down the GUI hierarchy
e.Handled = true;
}
/// <summary>
/// Fired, when ListOfItem is started (loaded)
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void ListOfItems_Loaded(object sender, RoutedEventArgs e)
{
if (this.DataContext is SomeDataContextClass)
{
SomeDataContextClass dataCtx = (this.DataContext as SomeDataContextClass);
switch (MainWindow.EditedPropertyName)
{
case "Property1":
TheListOfItems.ItemsSource = dataCtx.Property1_List;
break;
case "Property2":
TheListOfItems.ItemsSource = dataCtx.Property2_List;
break;
}
}
}
#endregion LIST_OF_ITEMS_EVENT_HANDLERS
// ------------------------------------------------------------------------------------------------
#region PROPERTY_GRID_EVENT_HANDLERS
/// <summary>
/// Here you can hide whatever is unwanted, or otherwise control look of properties
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void PropertyGrid_AutoGeneratingPropertyDefinition(object sender, Telerik.Windows.Controls.Data.PropertyGrid.AutoGeneratingPropertyDefinitionEventArgs e)
{
try
{
string dispName = e.PropertyDefinition.DisplayName;
dynamic parentValue = e.PropertyDefinition.ParentProperty?.Value;
// Unfortunatelly e.PropertyDefinition.Value is null, so we can't switch by object type
switch (dispName)
{
case "Item":
case "ItemElementName":
e.PropertyDefinition.Visibility = Visibility.Collapsed; // Filter out Item
break;
case "SomeOtherProperty":
e.PropertyDefinition.Visibility = ((parentValue?.RangeType as ItemChoiceType?) == ItemChoiceType.choiceOne) ? Visibility.Visible : Visibility.Collapsed;
break;
}
}
catch (Exception ex)
{
logger.Error("Problem occured when generating properties of the parent value: {1} \nReason: {2}", e.PropertyDefinition.ParentProperty?.Value, ex.Message);
}
}
/// <summary>
/// Fired, when user clicks on any RadPropertyGrid element.
/// Is used to define specific actions based on which property is selected
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void PropertyGrid_SelectionChanged(object sender, Telerik.Windows.Controls.SelectionChangeEventArgs e)
{
// Do something, like RedrawWholeControl();
// Prevent further traveling down the GUI hierarchy
e.Handled = true;
}
/// <summary>
/// Event handler when (Segment, Template, or Node) Rad Property Grid cell was edited and just commited to be stored in element property.
/// Enables different handling of various edited elements (cells)
/// So far as example a segment length cell is filtered and handled (invoked setting of graphical rail widget length)
/// This can be used to perform validation of input values (for example)
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void PropertyGrid_CellEditEnded(object sender, Telerik.Windows.Controls.Data.PropertyGrid.PropertyGridEditEndedEventArgs e)
{
string editedPropertyName = null;
if (sender is Telerik.Windows.Controls.RadPropertyGrid)
{
// Find out what property was actually edited
Telerik.Windows.Controls.RadPropertyGrid rpg = (sender as Telerik.Windows.Controls.RadPropertyGrid);
editedPropertyName = rpg.SelectedPropertyDefinition.DisplayName;
// Prevent further traveling down the GUI hierarchy
e.Handled = true;
}
// This redraws, however closes all opened elements in property grid
ThePropertyGrid.Item = null;
ThePropertyGrid.Item = TheListOfItems.SelectedItem;
}
#endregion PROPERTY_GRID_EVENT_HANDLERS
}
那你就用这个uni-control作为客户端定义的数据模板class XAML:
<!-- Universal template for rendering any sort of nested class structure -->
<DataTemplate x:Key="UniversalTemplatePropertyGrid">
<local:UniCollectionPropertyGrid DataContext="{Binding}"/>
</DataTemplate>
并且在后面的客户端 class 代码中,您指定在部署指定名称的 collection 时打开此控件:
private void RadPropertyGrid_AutoGeneratingPropertyDefinition(object sender, Telerik.Windows.Controls.Data.PropertyGrid.AutoGeneratingPropertyDefinitionEventArgs e)
{
string dispName = e.PropertyDefinition.DisplayName;
// Unfortunatelly e.PropertyDefinition.Value is null, so we can't switch by object type
switch (dispName)
{
case "Property1_List":
case "Property2_List":
e.PropertyDefinition.EditorTemplate = this.Resources["UniversalTemplatePropertyGrid"] as DataTemplate;
break;
default:
break;
}
}
下面是这种通用控件的外观 (powerVoltageChangesList):
优点:
1.这样的控件不局限于复杂(嵌套)classes里面
collection.
你可以完全控制这个 class,因为你有源代码。
作为奖励,在递归模式的情况下:嵌套 Collection->ComplexClass->Collection->ComplexClass->Collection-> .. .. 您可以通过重复调用完全相同的模板来解决问题:您刚刚创建的 UniversalTemplatePropertyGrid(即 UniCollectionPropertyGrid class)。
我的问题是二级集合不呈现内部(嵌套)classes 的成员。
二级意味着在 Collections Add/Remove 编辑器中(CollectionEditorPicker)。
我希望在图 2 中显示 class 'powerVoltageDefinition' 的所有内部成员,就像我们在图 1.
有什么诀窍?我如何在这个默认的 Collection Add/Remove 编辑器中显示这样的内部 classes(所谓的 'CollectionEditorPicker')?
图 1 - 正确呈现的嵌套 class 成员
图 2 - 未呈现嵌套 class 成员
XAML 此 RadPropertyGrid 的片段
<telerik:RadPropertyGrid x:Name="SelectedProperty"
AutoGenerateBindingPaths="True"
AutoGeneratePropertyDefinitions ="True"
AutoGeneratingPropertyDefinition="RadPropertyGrid_AutoGeneratingPropertyDefinition"
CanUserResizeDescriptionPanel="True"
NestedPropertiesVisibility="Visible"
DescriptionPanelVisibility="Visible"
SearchInNestedProperties="True"
PropertySetMode="Union"
RenderMode="Hierarchical"
EditMode="Default"
EditEnded="CellEditEnded"
ToolTip="ToDo: Tool Tips">
</telerik:RadPropertyGrid>
我已经调查过:
2. And this solution does not cover my nested class powerVoltageDefinition
我的解决方案会导致这些吗?:
由于 Telerik 似乎不支持将其原生 CollectionEditor/Picker
附加到 RadPropertyGrid
的情况,我们的第二个最佳选择是(恕我直言)创建自己的 WPF 控件。
这是我对这种 "generic" 控制的建议:
UniCollectionPropertyGrid.XAML:
<UserControl x:Class="TrackDataEditor.XAML.UniCollectionPropertyGrid"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:TrackDataEditor.XAML"
xmlns:telerik="http://schemas.telerik.com/2008/xaml/presentation"
xmlns:telerikDocking="clr-namespace:Telerik.Windows.Controls;assembly=Telerik.Windows.Controls.Docking"
mc:Ignorable="d"
d:DesignHeight="400" d:DesignWidth="700">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<!-- The Items Pane -->
<!-- <telerikDocking:RadPane x:Name="TemplatesPane" Header="Templates"> -->
<Grid Grid.Column="0" Grid.Row="0">
<!-- Icons to control template instances-->
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!-- #### +/- Buttons #### -->
<DockPanel x:Name="Buttons" Grid.Row="0" HorizontalAlignment="Stretch">
<Button x:Name="AddItemButton" Foreground="Green" HorizontalAlignment="Stretch" VerticalAlignment="Top" Width="30" ToolTip="Add an element" Click="AddItem">{+}</Button>
<Button x:Name="RemoveItemButton" Foreground="Red" HorizontalAlignment="Left" VerticalAlignment="Top" Width="30" ToolTip="Remove the selected element" Click="RemoveItem">{-}</Button>
<Button x:Name="RedrawPropGridButton" HorizontalAlignment="Left" VerticalAlignment="Top" Width="30" ToolTip="Redraw actualy selected element" Click="RedrawPropGrid">{R}</Button>
</DockPanel>
<!-- #### Lister of items #### -->
<telerik:RadGridView Grid.Row="1"
x:Name="TheListOfItems" ItemsSource="{Binding}" CanUserReorderColumns="True"
SelectionChanged="ListOfItems_SelectionChanged"
Loaded="ListOfItems_Loaded"
CanUserInsertRows="True" CanUserDeleteRows="True"
AutoGenerateColumns="True"
RowIndicatorVisibility="Collapsed"
ShowGroupPanel="False">
</telerik:RadGridView>
</Grid>
<!-- #### Properties of selected item #### -->
<telerik:RadPropertyGrid Grid.Column="1" Grid.Row="1"
x:Name="ThePropertyGrid"
AutoGenerateBindingPaths="True"
AutoGeneratePropertyDefinitions ="True"
AutoGeneratingPropertyDefinition="PropertyGrid_AutoGeneratingPropertyDefinition"
DescriptionPanelVisibility="Collapsed"
CanUserResizeDescriptionPanel="True"
OverridesDefaultStyle="True"
SearchBoxVisibility="Collapsed"
SearchInNestedProperties="True"
NestedPropertiesVisibility="Visible"
RenderMode="Hierarchical"
PropertySetMode="Intersection"
EditMode="Default"
EditEnded="PropertyGrid_CellEditEnded"
SelectionChanged="PropertyGrid_SelectionChanged"
FieldIndicatorVisibility ="Collapsed"
EnableEditorCaching ="True"
EnableCustomFiltering ="False"
ToolTip="ToDo: Tool Tips">
</telerik:RadPropertyGrid>
<!-- EditEnded="CellEditEnded" -->
</Grid>
背后的C#代码: UniCollectionPropertyGrid.XAML.cs
/// <summary>
/// Interaction logic for UniCollectionPropertyGrid.xaml
/// </summary>
public partial class UniCollectionPropertyGrid : UserControl
{
private static Logger logger = LogManager.GetCurrentClassLogger();
// C-tor
public UniCollectionPropertyGrid()
{
InitializeComponent();
}
/// <summary>
/// Called when user clicks add item button: {+}
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void AddItem(object sender, RoutedEventArgs e)
{
if (this.DataContext is SomeDataContextClass)
{
SomeDataContextClass dataCtx = (this.DataContext as SomeDataContextClass);
dynamic newItem = null;
// What is being currenlty edited (this was unfortunatelly "impossible?" to pass dynamically.
// (Why ? Because by this time, Telerik & WPF neither seem to provide no mechanism to distinguish generic controls like this one, generated by editor template (factory) ...)
switch (MainWindow.EditedPropertyName)
{
case "Property1":
newItem = new Property1Type();
dataCtx.Property1_List.Add(newItem as Property1Type);
TheListOfItems.ItemsSource = dataCtx.Property1_List;
break;
case "Property2":
newItem = new Property2Type();
dataCtx.Property2_List.Add(newItem as Property2Type);
TheListOfItems.ItemsSource = dataCtx.Property2_List;
break;
}
// Set the newly added item as selected
TheListOfItems.SelectedItem = newItem;
// SetBinding it to property grid to be rendered
ThePropertyGrid.Item = newItem;
}
}
/// <summary>
/// Called when user clicks remove item button: {-}
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void RemoveItem(object sender, RoutedEventArgs e)
{
// Leave right away if no item is selected
if (TheListOfItems.SelectedItem == null) return;
if (this.DataContext is SomeDataContextClass)
{
SomeDataContextClass dataCtx = (this.DataContext as SomeDataContextClass);
switch (MainWindow.EditedPropertyName)
{
case "Property1":
dataCtx.Property1_List.Remove(TheListOfItems.SelectedItem as Property1Type);
break;
case "Property2":
dataCtx.Property2_List.Remove(TheListOfItems.SelectedItem as Property2Type);
break;
}
}
// Nothing to show on property grid
ThePropertyGrid.Item = null;
}
/// <summary>
/// Called when user clicks Redraw property grid button: {R}
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void RedrawPropGrid(object sender, RoutedEventArgs e)
{
// This redraws, however closes all opened elements in property grid
ThePropertyGrid.Item = null;
ThePropertyGrid.Item = TheListOfItems.SelectedItem;
}
// ------------------------------------------------------------------------------------------------
#region LIST_OF_ITEMS_EVENT_HANDLERS
/// <summary>
/// Fired, when user clicks on any item of the ListOfItems table (RadGridView).
/// Is used to set selected item to the property grid
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void ListOfItems_SelectionChanged(object sender, Telerik.Windows.Controls.SelectionChangeEventArgs e)
{
// Try to redraw - wonder if this works
// this.Arrange(new Rect(RenderSize));
// this.UpdateLayout();
ThePropertyGrid.Item = this.TheListOfItems.SelectedItem;
// Prevent further traveling down the GUI hierarchy
e.Handled = true;
}
/// <summary>
/// Fired, when ListOfItem is started (loaded)
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void ListOfItems_Loaded(object sender, RoutedEventArgs e)
{
if (this.DataContext is SomeDataContextClass)
{
SomeDataContextClass dataCtx = (this.DataContext as SomeDataContextClass);
switch (MainWindow.EditedPropertyName)
{
case "Property1":
TheListOfItems.ItemsSource = dataCtx.Property1_List;
break;
case "Property2":
TheListOfItems.ItemsSource = dataCtx.Property2_List;
break;
}
}
}
#endregion LIST_OF_ITEMS_EVENT_HANDLERS
// ------------------------------------------------------------------------------------------------
#region PROPERTY_GRID_EVENT_HANDLERS
/// <summary>
/// Here you can hide whatever is unwanted, or otherwise control look of properties
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void PropertyGrid_AutoGeneratingPropertyDefinition(object sender, Telerik.Windows.Controls.Data.PropertyGrid.AutoGeneratingPropertyDefinitionEventArgs e)
{
try
{
string dispName = e.PropertyDefinition.DisplayName;
dynamic parentValue = e.PropertyDefinition.ParentProperty?.Value;
// Unfortunatelly e.PropertyDefinition.Value is null, so we can't switch by object type
switch (dispName)
{
case "Item":
case "ItemElementName":
e.PropertyDefinition.Visibility = Visibility.Collapsed; // Filter out Item
break;
case "SomeOtherProperty":
e.PropertyDefinition.Visibility = ((parentValue?.RangeType as ItemChoiceType?) == ItemChoiceType.choiceOne) ? Visibility.Visible : Visibility.Collapsed;
break;
}
}
catch (Exception ex)
{
logger.Error("Problem occured when generating properties of the parent value: {1} \nReason: {2}", e.PropertyDefinition.ParentProperty?.Value, ex.Message);
}
}
/// <summary>
/// Fired, when user clicks on any RadPropertyGrid element.
/// Is used to define specific actions based on which property is selected
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void PropertyGrid_SelectionChanged(object sender, Telerik.Windows.Controls.SelectionChangeEventArgs e)
{
// Do something, like RedrawWholeControl();
// Prevent further traveling down the GUI hierarchy
e.Handled = true;
}
/// <summary>
/// Event handler when (Segment, Template, or Node) Rad Property Grid cell was edited and just commited to be stored in element property.
/// Enables different handling of various edited elements (cells)
/// So far as example a segment length cell is filtered and handled (invoked setting of graphical rail widget length)
/// This can be used to perform validation of input values (for example)
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void PropertyGrid_CellEditEnded(object sender, Telerik.Windows.Controls.Data.PropertyGrid.PropertyGridEditEndedEventArgs e)
{
string editedPropertyName = null;
if (sender is Telerik.Windows.Controls.RadPropertyGrid)
{
// Find out what property was actually edited
Telerik.Windows.Controls.RadPropertyGrid rpg = (sender as Telerik.Windows.Controls.RadPropertyGrid);
editedPropertyName = rpg.SelectedPropertyDefinition.DisplayName;
// Prevent further traveling down the GUI hierarchy
e.Handled = true;
}
// This redraws, however closes all opened elements in property grid
ThePropertyGrid.Item = null;
ThePropertyGrid.Item = TheListOfItems.SelectedItem;
}
#endregion PROPERTY_GRID_EVENT_HANDLERS
}
那你就用这个uni-control作为客户端定义的数据模板class XAML:
<!-- Universal template for rendering any sort of nested class structure -->
<DataTemplate x:Key="UniversalTemplatePropertyGrid">
<local:UniCollectionPropertyGrid DataContext="{Binding}"/>
</DataTemplate>
并且在后面的客户端 class 代码中,您指定在部署指定名称的 collection 时打开此控件:
private void RadPropertyGrid_AutoGeneratingPropertyDefinition(object sender, Telerik.Windows.Controls.Data.PropertyGrid.AutoGeneratingPropertyDefinitionEventArgs e)
{
string dispName = e.PropertyDefinition.DisplayName;
// Unfortunatelly e.PropertyDefinition.Value is null, so we can't switch by object type
switch (dispName)
{
case "Property1_List":
case "Property2_List":
e.PropertyDefinition.EditorTemplate = this.Resources["UniversalTemplatePropertyGrid"] as DataTemplate;
break;
default:
break;
}
}
下面是这种通用控件的外观 (powerVoltageChangesList):
优点: 1.这样的控件不局限于复杂(嵌套)classes里面 collection.
你可以完全控制这个 class,因为你有源代码。
作为奖励,在递归模式的情况下:嵌套 Collection->ComplexClass->Collection->ComplexClass->Collection-> .. .. 您可以通过重复调用完全相同的模板来解决问题:您刚刚创建的 UniversalTemplatePropertyGrid(即 UniCollectionPropertyGrid class)。