我的问题是第二级的集合不会呈现内部(嵌套)类的成员。
第二级意味着收藏夹添加/删除编辑器( CollectionEditorPicker )。
我希望在图2中显示类'powerVoltageDefinition'的所有内部成员,就像我们在图1中看到的一样。
诀窍是什么?如何在此默认的集合添加/删除编辑器中显示此类内部类(所谓的' CollectionEditorPicker ')?
此RadPropertyGrid的XAML片段
<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>
我已经调查过:
1. This does not describe problem.
2. And this solution does not cover my nested class powerVoltageDefinition
我的解决方案是否会导致其中任何一种?:
答案 0 :(得分:1)
由于Telerik似乎不支持他们的CollectionEditor/Picker
加上他们的RadPropertyGrid
这样的情况,我们的第二个最佳选择是(恕我直言)创建自己的WPF控件。
这是我对这种&#34;泛型&#34;的建议。控制:
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控件用作客户端类XAML中定义的数据模板:
<!-- Universal template for rendering any sort of nested class structure -->
<DataTemplate x:Key="UniversalTemplatePropertyGrid">
<local:UniCollectionPropertyGrid DataContext="{Binding}"/>
</DataTemplate>
在后面的客户端类代码中,指定在部署指定名称的集合时打开此控件:
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):
优点: 这种控制不限于复杂(嵌套)类中 集合。
您可以完全控制此类,因为您有源代码。
作为奖励,在递归模式的情况下:嵌套Collection-&gt; ComplexClass-&gt; Collection-&gt; ComplexClass-&gt; Collection-&gt; ....你可以通过再次调用同一个模板解决问题:你刚刚创建的UniversalTemplatePropertyGrid(即UniCollectionPropertyGrid类)。