programmatically associate a Property and a PropertyEditor

Grids for WPF Forum

Posted 14 years ago by Sasha Lifshits
Version: 10.1.0523
Avatar
Is there any examples in question?
In particular for ComboBoxPropertyEditor and DialogTextBoxPropertyEditor.
Thanks,
Alex

Comments (8)

Posted 14 years ago by Actipro Software Support - Cleveland, OH, USA
Avatar
Hi Alex,

You can use the Editor attribute to assign a property item in code, but this is applied "statically" and cannot be added/removed dynamically:
[Editor(typeof(ComboBoxPropertyEditor), typeof(PropertyEditor))]
public string MyProperty { ... }
Alternatively, you can add entries into the PropertyGrid.PropertyEditors collection, like you would via XAML. So something like:
PropertyEditor propertyEditor = new PropertyEditor() {
     PropertyName = "MyProperty",
     ValueTemplateKey = BuiltinEditors.ComboBoxValueTemplateKey
};
this.propGrid.PropertyEditors.Add(propertyEditor);
Instead of PropertyName, you could also set PropertyType to match based on type or name & type. Each of the concrete property editors, like ComboBoxPropertyEditor, have a corresponding key in BuiltinEditors. In fact, ComboBoxPropertyEditor simply returns BuiltinEditors.ComboBoxValueTemplateKey from it's ValueTemplateKey property.

Finally, you could provide a custom DataTemplateSelector, which extends our ValueTemplateSelector. You'd then set the PropertyGrid.ValueTemplateSelector property to your custom version. To customize the templates, you'd override the SelectTemplate method and then add this code at the top:
IPropertyDataAccessor propertyDataAccessor = VisualTreeHelperExtended.GetCurrentOrAncestor(container, typeof(IPropertyDataAccessor)) as IPropertyDataAccessor;
if (propertyDataAccessor == null)
    return null;

// Check propertyDataAccessor.ValueName or ValueType
Then you'd return a DataTemplate to be used as the "editor".


Actipro Software Support

Posted 14 years ago by Sasha Lifshits
Avatar
1.For the first code fragment
[Editor(typeof(ComboBoxPropertyEditor), typeof(PropertyEditor))]
public string MyProperty { ... }
how do you populate the drop-down list, and subscribe for the Selection Changed event?

2.In a similar case for a DialogTextBoxPropertyEditor, how to subscribe for the Button-On-Click event, and implement the event holder.
Posted 14 years ago by Actipro Software Support - Cleveland, OH, USA
Avatar
Hi Alex,

#1. In general, the associated TypeConverter provides the list of "standard values". For example, the Boolean type uses the BooleanConverter when overrides GetStandardValues and it's associated methods. The PropertyGrid knows to call these methods and the ComboBoxPropertyEditor knows to bind to it's ComboBox this list of items.

Depending on your property and it's Type, you can either specify the TypeConverter on the property itself or the Type definition (i.e. the class). Basically, you'd create a class that derives from TypeConverter and overrides the GetStandardValues, GetStandardValuesExclusive, and GetStandardValuesSupported methods. GetStandardValues returns the list of items you'd like to show in the ComboBox. GetStandardValuesExclusive returns true if the property should be restricted to the standard values (i.e. a Boolean can only be true or false, so it's exclusive). GetStandardValuesSupported should return true, if GetStandardValues is supported. Then you'd use TypeConverterAttribute and decorate your property or type with your custom TypeConverter (i.e. "[TypeConverter(typeof(MyTypeConverter))]").

This forum post shows an example of a custom TypeConverter.

Alternatively, you could build a custom property editor that uses a ComboBox bound to a custom list. We have several examples of how to define a custom property editor in our Sample Browser, but the process is pretty simple. You'd create a DataTemplate that includes the controls you'd like to use (i.e. a ComboBox) and include it in your application resources with a known key name (i.e. x:Key="MyComboBoxEditor"). You could then bind the ComboBox.ItemsSource to anything you wanted.

Then you'd need to associated that property editor with your property. This post shows one example, but our Sample Browser has several other samples as well.

If you want to subscribe to the SelectionChanged event, you'd have to attach a class handler for the ComboBox.SelectionChangedEvent to the PropertyGrid type and look for events from a ComboBox. Normally, you don't need to subscribe to this event, as the ComboBoxPropertyEditor uses a binding to push the selected value back to the underlying property.

#2. There are samples of this in our Sample Browser in the Property Editors QuickStart under the PropertyGrid section.


Actipro Software Support

Posted 14 years ago by Sasha Lifshits
Avatar
Thanks,
I’ve overcome the ComboBoxPropertyEditor; though (just an info), if the ComboBoxPropertyEditor assigned as an attribute, it does not “push” anything “back to the underlying property” in spite of the drop-down selection.

#2. All samples that you mentioned are XAML script based, which is not what I asked for.
So, again, could you show/explain, please, how to subscribe to On Click event if a DialogTextBoxPropertyEditor assigned as an attribute.
Thanks,
Alex
Posted 14 years ago by Sasha Lifshits
Avatar
Thanks,
I’ve overcome the ComboBoxPropertyEditor; though (just an info), if the ComboBoxPropertyEditor assigned as an attribute, it does not “push” anything “back to the underlying property” in spite of the drop-down selection.

#2. All samples that you mentioned are XAML script based, which is not what I asked for.
So, again, could you show/explain, please, how to subscribe to On Click event if a DialogTextBoxPropertyEditor assigned as an attribute.
Thanks,
Alex
Posted 14 years ago by Actipro Software Support - Cleveland, OH, USA
Avatar
Hi Alex,

For #1, if you want to put together a small sample project and send it over to our support address we can take a closer look at what you have.

For #2, all the concepts are really the same. A DataTemplate is defined that includes a button with a known command, which is used for 1 or more properties. Then you'd add a handler for the known command on the PropertyGrid or one of it's ancestors in the visual tree.

In the case of the DialogTextBoxPropertyEditor, it raises the PropertyGrid.ShowPropertyDialogCommand command. The DialogTextBoxPropertyEditor uses the DataTemplate defined by "{StaticResource {x:Static propgrid:BuiltinEditors.DialogTextBoxValueTemplateKey}}", it just allows you to use the EditorAttribute to assign it to a property. So regardless of whether you use DialogTextBoxPropertyEditor or "{StaticResource {x:Static propgrid:BuiltinEditors.DialogTextBoxValueTemplateKey}}", the same DataTemplate is ultimately displayed for the given properties.

So in your case, you'd need to hook up a handler for PropertyGrid.ShowPropertyDialogCommand as shown in that sample, but then use the EditorAttribute and DialogTextBoxPropertyEditor to assign it to your properties.

When building a custom property editor that uses a button (like the "TextBox with dialog (Custom)" items in the Property Editors QuickStart), you define your own RoutedCommand and use it in your DataTemplate (by setting Button.Command). Then again, you'd add a handler as seen in the sample.

Hope that clears things up.


Actipro Software Support

Posted 14 years ago by Sasha Lifshits
Avatar
Thanks, I do appreciate your prompt responses.
But, somehow you keep answering questions that I did not ask.
Again, I am not interested in a XAML based approach.
Let us consider a very simple straightforward scenario:
At runtime, a PropertyGrid instantiated in the code (and placed into a container object), an object of a predefined type (but not known in advance) is assigned to the PropertyGrid.SelectedObject, then an object of different type assigned to the PropertyGrid.SelectedObject, then another type, and so forth. There is arbitrary number of properties with arbitrary names in the objects, some of the properties declared with attributes [Editor(typeof(DialogTextBoxPropertyEditor),typeof(PropertyEditor))] (or a derived editor). (You see, there is no XAML involved at any step.)
The question is: What to do for the editors-defined-as-attributes to work for the described scenario?
Is there an answer without XAML related references? (the same way as you finally helped me to accomplish for a ComboBoxStringPropertyEditor)
Thanks,
Alex
Posted 14 years ago by Actipro Software Support - Cleveland, OH, USA
Avatar
Hi Alex,

In your case, the key point to take away from that sample is how it hooks up a handler for the PropertyGrid.ShowPropertyDialogCommand routed command. This is done completely in the code-behind file, and is completely independent of how the PropertyGrid is populated (i.e. via SelectedObject(s) or explicitly via XAML).

The DataTemplate that is used for properties marked with "[Editor(typeof(DialogTextBoxPropertyEditor),typeof(PropertyEditor))]" is effectively defined like so (with extraneous information removed):
<DataTemplate x:Key="{x:Static propgrid:BuiltinEditors.DialogTextBoxValueTemplateKey}">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="Auto" />
        </Grid.ColumnDefinitions>
        <TextBox Text="{Binding ValueAsString, ... }" />
        <shared:PopupButton Grid.Column="1" Content="..." DisplayMode="ButtonOnly" IsTransparencyModeEnabled="True"
                Command="{x:Static propgrid:PropertyGrid.ShowPropertyDialogCommand}"
                CommandParameter="{Binding RelativeSource={RelativeSource AncestorType={x:Type propgrid:IPropertyDataAccessor}}}" />
    </Grid>
</DataTemplate>
So regardless of whether you decorate your object's properties with "[Editor(typeof(DialogTextBoxPropertyEditor),typeof(PropertyEditor))]" and use SelectedObject(s), or access that DataTemplate directly (as seen in the XAML side of the Property Editors sample), the same DataTemplate is ultimately used for the properties in question.

As you can see from the DataTemplate definition above, it raises the PropertyGrid.ShowPropertyDialogCommand when the button is pressed. So if you add a handler for that, then you'll know when it's been clicked. In addition, you can add a "CanExecute" and control when it's enabled.

So to summarize, there are effectively 2 steps:

1. Associate the DataTemplate above with 1 or more properties

You already know what to do this with EditorAttribute, but the DataTemplate can be assigned in several other ways (one of which is demonstrated in the XAML side of that sample)

2. Add handler for the PropertyGrid.ShowPropertyDialogCommand routed command

This part is shown in the code-behind of that sample.


Actipro Software Support

The latest build of this product (v24.1.1) was released 2 months ago, which was after the last post in this thread.

Add Comment

Please log in to a validated account to post comments.