Using ComboBoxPropertyEditor with a nullable enum

Grids for WPF Forum

Posted 14 years ago by Craig - Varigence, Inc.
Version: 10.1.0521
Avatar
For an application I'm working on, I want the property grid to display a nullable enum as a ComboBox and allow me to alter its style so I can provide some customizations.

For a regular enumeration, I do the following:

                <appropgrid:ComboBoxPropertyEditor
                    PropertyType="{x:Type System:Enum}" 
                    >
                    <appropgrid:ComboBoxPropertyEditor.ValueStyles>
                        <appropgrid:PropertyEditorStyle
                            Key="{x:Type ComboBox}"
                            Style="{StaticResource validationEnumStyle}"
                            />
                    </appropgrid:ComboBoxPropertyEditor.ValueStyles>  
                </appropgrid:ComboBoxPropertyEditor>
However, the style I'm setting with the Enum property type seems to be ignored for my nullable enum. I assume that the PropertyType would need to be Nullable or something similar, although I only want the ComboBox for nullable enums, not all Nullables. What's the best way to apply a style customization in this case? Would I be better off skipping the ComboBoxPropertyEditor altogether and just using a PropertyEditor?

Thanks very much,

-Craig

[Modified at 05/04/2010 02:25 AM]

Comments (8)

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

It depends on what properties you are trying to set in your Style. Several properties are set explicitly on the ComboBox, so your Style would not be able to override those. Assuming that is your issue, then you would need to define a new property editor (i.e. a new DataTemplate). You could copy the default one though, and then tweak it to your needs.

The following properties are set explicitly:

Background
BorderThickness
HorizontalAlignment
HorizontalContentAlignment
IsEditable
IsReadOnly
ItemsSource
Margin
Padding
SelectedItem
Text
VerticalAlignment
VerticalContentAlignment


Actipro Software Support

Posted 14 years ago by Craig - Varigence, Inc.
Avatar
Well, my main desire is to display a red border when the nullable enum's value is null (so treating null as an error case). Thus, I was providing a Style based on the ComboBox type where I provided an error template, along with a MultiBinding converter that triggers the template when the enum's value is null. However, when debugging, I can see the converter never fires for my nullable enum, hence the question of whether I need to provide a different type in the ComboBoxPropertyEditor XAML, to associate it with my nullable enum.

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

You would need to build a custom property editor to accomplish that, since you can't set a binding on ComboBox.SelectedItem or ComboBox.Text. You can use the ComboBoxPropertyEditor and it's associated DataTemplate as a basis if you want, and tweak the bindings as you need.

The DataTemplate is available with the default Styles for the PropertyGrid. And the code for ComboBoxPropertyEditor is effectively:
public class ComboBoxPropertyEditor : PropertyEditor {
    public override object ValueTemplateKey {
        get { return BuiltinEditors.ComboBoxValueTemplateKey; }
    }
}


Actipro Software Support

Posted 14 years ago by Craig - Varigence, Inc.
Avatar
What would be the best way to control when my custom property editor is used? For example, ComboBox's are used with enum types and CheckBox's are used with bool types. How can I tie the custom property editor to a nullable enum type? Use a data template selector? Can it be done in XAML? If so, could you give me an example of setting a nullable enum type in XAML?

Thanks again,

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

You should be able to "set" the PropertyEditor.PropertyType to typeof(Enum?). You can use our NullableExtension class to generate this type via XAML. So something like "{shared:Nullable {x:Type system:Enum}}". Alternatively, you could set the PropertyEditor.PropertyType in the constructor of your custom PropertyEditor.


Actipro Software Support

Posted 14 years ago by Craig - Varigence, Inc.
Avatar
1. Regarding your suggestion on checking for the nullable enum type, it unfortunately didn't work. However, I think I understand the problem.

Let's say I have a property like:

    public enum TableSortOrder
    {
        Asc,
        Desc,
    }

    public TableSortOrder? SortOrder
    {
        get;
        set;
    }
I imagine the appropriate XAML for that property's type would actually be {shared:Nullable {x:Type TableSortOrder}} since the SortOrder's type is 'TableSortOrder?'.

As to {shared:Nullable {x:Type system:Enum}}, I don't see how it would work considering SortOrder's type is not 'Enum?'. Additionally, there's another problem with it since when I tried it...

                    <PropertyGrid:ComboBoxNullableEnumPropertyEditor
                        PropertyType="{apshared:Nullable {x:Type System:Enum}}"
                        >
... an exception was thrown:

  InnerException: System.ArgumentException
       Message=GenericArguments[0], 'System.Enum', on 'System.Nullable`1[T]' violates the constraint of type 'T'.
       Source=mscorlib
       StackTrace:
            at System.RuntimeType.ValidateGenericArguments(MemberInfo definition, RuntimeType[] genericArguments, Exception e)
            at System.RuntimeType.MakeGenericType(Type[] instantiation)
            at ActiproSoftware.Windows.Data.NullableExtension.ProvideValue(IServiceProvider serviceProvider)
            at MS.Internal.Xaml.Runtime.ClrObjectRuntime.CallProvideValue(MarkupExtension me, IServiceProvider serviceProvider)
       InnerException: System.TypeLoadException
            Message=GenericArguments[0], 'System.Enum', on 'System.Nullable`1[T]' violates the constraint of type parameter 'T'.
            Source=mscorlib
            TypeName=""
            StackTrace:
                 at System.RuntimeTypeHandle.Instantiate(RuntimeTypeHandle handle, IntPtr* pInst, Int32 numGenericArgs, ObjectHandleOnStack type)
                 at System.RuntimeTypeHandle.Instantiate(Type[] inst)
                 at System.RuntimeType.MakeGenericType(Type[] instantiation)
            InnerException: 
Are there other ways for the property type to account for all nullable enums?

Also note that typeof(Enum?) will not compile in code-behind (the error is "The type 'System.Enum' must be a non-nullable value type in order to use it as parameter 'T' in the generic type or method 'System.Nullable<T>'")

Note that I have tried using the Editor attribute on the property declaration and that does work (but would mean that I'm stuck applying the attribute in loads of places, hence why I was hoping for a central solution).

2. In the context of this discussion, here's a related question on custom property editors. With the custom property editor I'm using for this, what's the appropriate way to add a Style to its ValueStyles collection? Normally I'd do it in XAML but it appears you're constructing the editor on the fly as you detect the property's Editor attribute. I've tried the following:

            propertyEditorStyle.Key = typeof(ComboBox);
            propertyEditorStyle.Style = ...;
            ValueStyles.Add(propertyEditorStyle);
but the style is ignored and I see a warning that there's a virtual member call in the constructor. Is there a different way I should be doing this?

Thanks again,

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

1. Ok, looks like you can't create a "catch-all" nullable Enum type. Currently, you'd need to make an entry for every nullable enumeration type you will be displaying. We've made a change for the next maintenance release (due out this week) that will allow you to bypass the PropertyType, and use your own logic.

Specifically, we made the PropertyEditor.GetMatchOrder virtual. This method is passed a properties name and type, and expects a "priority code", which is just an integer, to be returned. The propertye editor with the lowest number wins for the given property.

So you could override that method, check for Nullable<T>, see if it wraps an enumeration, and if it does then return 0. That would force the PropertyGrid to use your property editor.

2. That Style should be applied, assuming the property editor is used. The Style is merged into the resources of the container element, just above where the DataTemplate is presented. You get that warning because you are calling ValueStyles, which is virtual. So you can either ignore the warning or override ValueStyles and return a "preconstructed" collection. Something like:
private PropertyEditorStyleCollection valueStyles;

public override PropertyEditorStyleCollection ValueStyles {
    get {
        if (null == this.valueStyles) {
            this.valueStyles = new PropertyEditorStyleCollection();
            this.valueStyles.Add(...);
        }
        return this.valueStyles;
    }
}
If that doesn't help, then please put together a small sample project (sans any executable files) and email it over to our support address.


Actipro Software Support

Posted 14 years ago by Craig - Varigence, Inc.
Avatar
Just wanted to say that GetMatchOrder is working great and solves my problem. Thanks for adding it.

-Craig
The latest build of this product (v24.1.1) was released 1 month ago, which was after the last post in this thread.

Add Comment

Please log in to a validated account to post comments.