Telerik:RadPropertyGrid似乎不会在Collection Editor / Picker中呈现嵌套类

时间:2017-10-10 13:46:09

标签: c# wpf xaml telerik

我的问题是第二级的集合不会呈现内部(嵌套)类的成员。

第二级意味着收藏夹添加/删除编辑器( CollectionEditorPicker )。

我希望在图2中显示类'powerVoltageDefinition'的所有内部成员,就像我们在图1中看到的一样。

诀窍是什么?如何在此默认的集合添加/删除编辑器中显示此类内部类(所谓的' CollectionEditorPicker ')?

图1 - 正确呈现嵌套类成员 Figure 1 - Correctly rendered nested class members

图2 - 未呈现的嵌套类成员 Figure 2 - Not rendered nested class members

此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

我的解决方案是否会导致其中任何一种?:

1. PropertyGridIndentPresenter Class

2. PropertyGridIndentPresenter.IndentLevelProperty

1 个答案:

答案 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): enter image description here

优点:  这种控制不限于复杂(嵌套)类中 集合。

  1. 您可以完全控制此类,因为您有源代码。

  2. 作为奖励,在递归模式的情况下:嵌套Collection-&gt; ComplexClass-&gt; Collection-&gt; ComplexClass-&gt; Collection-&gt; ....你可以通过再次调用同一个模板解决问题:你刚刚创建的UniversalTemplatePropertyGrid(即UniCollectionPropertyGrid类)。