Custom Editors and Property Attributes

Grids for WPF Forum

Posted 10 years ago by Rick Edwards - UK
Version: 9.1.0505
Avatar
Hi all,

is it possible to access a properties attributes in a custom property editor? Basically I'm attempting to change the formatting of a DoubleEditBox based upon some custom attributes associated to the property. I've created a custom editor and an associated DataTemplate and linked the two via a component resource key thus:

    public class DoubleDecimalPlaceEditor : PropertyEditorObject
    {
        private ResourceKey editorKey = new ComponentResourceKey(typeof(DoubleDecimalPlaceEditor), PropertyEditorKey.DOUBLE_DECIMAL_PLACE_EDITOR);

        public override System.Windows.ResourceKey ValueTemplateKey
        {
            get
            {
                return this.editorKey;
            }
            set
            {
                // not implemented
            }
        }

    }
and the DataTemplate:

    <DataTemplate
        x:Key="{ComponentResourceKey
        TypeInTargetAssembly={x:Type pe:DoubleDecimalPlaceEditor}, ResourceId=DoubleDecimalPlaceEditor}">
        <pe:DecimalFormatDecorator
            DataAccessor="{Binding RelativeSource={RelativeSource AncestorType={x:Type propgrid:IPropertyDataAccessor}}}">
            <editors:DoubleEditBox
                CheckBoxVisibility="Visible">
            </editors:DoubleEditBox>
        </pe:DecimalFormatDecorator>
    </DataTemplate>
Now in order to get hold of the IPropertyDataAccessor I created a custom Decorator and exposed the data accessor as a dependency property I could then bind to the ancestor. This all works fine but then I can't access the PropertyDescriptor through the IPropertyDataAccessor (clues in the name maybe!). Any ideas as to how to get to the PropertyDescriptor either through the Decorator or through the custom editor code?

Maybe there's a simpler way to change the editor formatting but unfortunately I need to access the property attributes as these are created through code generation and define certain default behaviour.

Also if I simply place a DoubleEditBox in the above DataTemplate then the property grid does not display the property value. However if I then switch the editor attribute of the property to point directly to a DouleEditBox the value shows up correctly. The property grid is definately using the correct template and calling the custom edito code ok so why no value (seems to work fine for other custom editors I've created)?

Thanks in advance.

Rick

Comments (1)

Posted 10 years ago by Actipro Software Support - Cleveland, OH, USA
Avatar
Hi Rick,

Yes, you should be able to get to the attributes of the underlying property. The controls in yoru DataTemplate will be a descendent of PropertyGridDataAccessorItem (which is akin to a TreeViewItem). The PropertyGridDataAccessorItem.DataContext will reference the IPropertyDataAccessor object created by the associated data factory. PropertyGridDataAccessorItem also implements IPropertyDataAccessor, but simply pipes those calls to the underlying IPropertyDataAccessor (stored in DataContext).

I'm not sure what you mean by "if I then switch the editor attribute of the property to point directly to a DouleEditBox the value shows up correctly". I'm assuming you mean that you use the property editor we provide in the Editors.Interop.ProperGrid assembly. Either way, you have to bind the DoubleEditBox.Value to something. It's not going to automatically hook things up for you. The default DataTemplate looks like this:
<DataTemplate x:Key="CustomDoubleValueTemplateKey">
    <editors:DoubleEditBox x:Name="editBox" Margin="0" Padding="0" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
            BorderThickness="0" Background="Transparent" CheckBoxVisibility="{Binding CheckBoxVisibility}"
            DropDownButtonVisibility="{Binding DropDownButtonVisibility}" DropDownButtonInactiveVisibility="Collapsed"
            DropDownButtonMargin="0" Format="{Binding Format}" Maximum="{Binding Maximum}" Minimum="{Binding Minimum}"
            PartValueCommitTriggers="{Binding PartValueCommitTriggers}" SpinnerVisibility="{Binding SpinnerVisibility}"
            SpinnerInactiveVisibility="Collapsed" StepValue="{Binding StepValue}"
            Value="{Binding Value, RelativeSource={RelativeSource AncestorType={x:Type propgrid:IPropertyDataAccessor}}, Mode=TwoWay, ValidatesOnExceptions=True, ValidatesOnDataErrors=True, NotifyOnValidationError=True, UpdateSourceTrigger=PropertyChanged}" />
    <DataTemplate.Triggers>
        <DataTrigger Binding="{Binding IsBoundToValueAsString}" Value="true">
            <Setter TargetName="editBox" Property="Value"
                    Value="{Binding ValueAsString, RelativeSource={RelativeSource AncestorType={x:Type propgrid:IPropertyDataAccessor}}, Mode=TwoWay, ValidatesOnExceptions=True, ValidatesOnDataErrors=True, NotifyOnValidationError=True, UpdateSourceTrigger=PropertyChanged}" />
        </DataTrigger>
        <DataTrigger
                Binding="{Binding IsReadOnly, RelativeSource={RelativeSource AncestorType={x:Type propgrid:IPropertyDataAccessor}}}"
                Value="true">
            <Setter TargetName="editBox" Property="IsEnabled" Value="false" />
        </DataTrigger>
        <DataTrigger Binding="{Binding Path=(propgrid:PropertyGrid.IsReadOnly), RelativeSource={RelativeSource Self}}"
                Value="true">
            <Setter TargetName="editBox" Property="IsEnabled" Value="false" />
        </DataTrigger>
    </DataTemplate.Triggers>
</DataTemplate>
You can see here, that we can access the IPropertyDataAccessor without the need for a Decorator.

Now, as for getting the attributes. Assuming you haven't changed the PropertyGrid.DataFactory, the underlying IPropertyDataAccessor (referenced by PropertyGridDataAccessorItem.DataContext) will actually be a type that derives from PropertyDescriptorDataAccessorBase. PropertyDescriptorDataAccessorBase exposes the .Net PropertyDescriptor, which has an Attributes collection.

You can get the PropertyDescriptor using this type of binding statement:
{Binding DataContext.PropertyDescriptor, RelativeSource={RelativeSource AncestorType={x:Type propgrid:IPropertyDataAccessor}}}
You can then use a value converter in the binding statement to take the PropertyDescriptor and look up 1 or more attributes in the Attributes collection.

Hope this helps.


Actipro Software Support

The latest build of this product (v2019.1 build 0681) was released 18 days ago, which was after the last post in this thread.

Add Comment

Please log in to a validated account to post comments.