Completed
Last Updated: 23 Apr 2014 06:27 by ADMIN
ADMIN
Dess | Tech Support Engineer, Principal
Created on: 10 Apr 2014 12:11
Category: PropertyGrid
Type: Bug Report
0
FIX. RadPropertyGrid - NullReferenceException when changing PropertyGridItem.Visible property
To reproduce:
1. Add a RadPropertyGrid and use the following code:


public partial class NewTestWindow : Form
{
    public NewTestWindow()
    {
        InitializeComponent();


        PropertyGridData data = new PropertyGridData();
        (data as INotifyPropertyChanged).PropertyChanged += NewTestWindow_PropertyChanged;


        ppgItems.SelectedObject = data;


        Type type = ppgItems.SelectedObject.GetType();
        MemberInfo[] members = type.GetMembers();
        foreach (MemberInfo m in members)
        {
            Attribute[] attributes = Attribute.GetCustomAttributes(m);
            foreach (Attribute attr in attributes)
            {
                if (attr is BrowsableCondition)
                {
                    BrowsableCondition condition = attr as BrowsableCondition;
                    PropertyGridItem gridItem = ppgItems.Items[m.Name];


                    gridItem.Visible = false;
                }
            }
        }
    }


    private void NewTestWindow_PropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        if (ppgItems.SelectedObject != null)
        {
            PropertyInfo enableProperty = ppgItems.SelectedObject.GetType().GetProperty(e.PropertyName);
            bool? value = enableProperty.GetValue(ppgItems.SelectedObject, null) as bool?;


            if (value.HasValue)
            {
                Type type = ppgItems.SelectedObject.GetType();
                MemberInfo[] members = type.GetMembers();
                foreach (MemberInfo m in members)
                {
                    Attribute[] attributes = Attribute.GetCustomAttributes(m);
                    foreach (Attribute attr in attributes)
                    {
                        if (attr is BrowsableCondition)
                        {
                            BrowsableCondition condition = attr as BrowsableCondition;
                            PropertyGridItem gridItem = ppgItems.Items[m.Name];


                            gridItem.Visible = value.Value;
                        }
                    }
                }
            }
        }


        ppgItems.PropertyGridElement.PropertyTableElement.Update(PropertyGridTableElement.UpdateActions.Resume);
    }
}


public class PropertyGridData : INotifyPropertyChanged
{
    public string Item { get; set; }


    [Browsable(true)]
    [BrowsableCondition("Enable")]
    public bool A0 { get; set; }


    [Browsable(true)]
    [BrowsableCondition("Enable")]
    public bool A1 { get; set; }


    [Browsable(true)]
    [BrowsableCondition("Enable")]
    public bool A2 { get; set; }


    [Browsable(true)]
    [BrowsableCondition("Enable")]
    public bool A3 { get; set; }


    [Browsable(true)]
    [BrowsableCondition("Enable")]
    public bool A4 { get; set; }


    [Browsable(true)]
    [BrowsableCondition("Enable")]
    public bool A5 { get; set; }


    public string Anything { get; set; }


    private bool _enable;


    public bool Enable
    {
        get
        {
            return _enable;
        }


        set
        {
            _enable = value;
            RaisePropertyChanged("Enable");
        }
    }


    public event PropertyChangedEventHandler PropertyChanged;


    public void RaisePropertyChanged(string propertyName)
    {
        if (this.PropertyChanged != null)
            this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
}


public class BrowsableCondition : Attribute
{
    public BrowsableCondition(string propertyName)
    {
        this.PropertyName = propertyName;
    }


    public string PropertyName { get; set; }
}


2. Run the application. The RadPropertyGrid has a checkbox with Enable property.
When selected, other properties are displayed (A0, A1, A2, A3, A4, A5). When the user marks some of these checkboxes that were hidden and then uncheck the Enable property, the PropertyGridItemElement component throws a System.NullReferenceException. 
1 comment
ADMIN
Dess | Tech Support Engineer, Principal
Posted on: 10 Apr 2014 12:45
Workaround: use custom RadPropertyGrid

public class CustomRadPropertyGrid : RadPropertyGrid
{
    public override string ThemeClassName  
    { 
        get 
        { 
            return typeof(RadPropertyGrid).FullName;  
        }
    }

    protected override PropertyGridElement CreatePropertyGridElement()
    {
        return new CustomPropertyGridElement();
    }
}

public class CustomPropertyGridElement : PropertyGridElement
{
    protected override Type ThemeEffectiveType     
    { 
        get    
        { 
            return typeof(PropertyGridElement);     
        }
    }

    protected override PropertyGridSplitElement CreateSplitElement()
    {
        return new CustomPropertyGridSplitElement();
    }
}

public class CustomPropertyGridSplitElement : PropertyGridSplitElement
{
    protected override Type ThemeEffectiveType     
    { 
        get    
        { 
            return typeof(PropertyGridSplitElement);     
        }
    }

    protected override PropertyGridTableElement CreateTableElement()
    {
        return new CustomPropertyGridTableElement();
    }
}

public class CustomPropertyGridTableElement : PropertyGridTableElement
{
    protected override Type ThemeEffectiveType     
    { 
        get    
        { 
            return typeof(PropertyGridTableElement);     
        }
    }

    protected override IVirtualizedElementProvider<PropertyGridItemBase> CreateElementProvider()
    {
        return new CustomPropertyGridItemElementProvider(this);
    }
}

public class CustomPropertyGridItemElementProvider : PropertyGridItemElementProvider
{ 
    public CustomPropertyGridItemElementProvider(PropertyGridTableElement propertyGridElement) : base(propertyGridElement)
    {
    }

    public override IVirtualizedElement<PropertyGridItemBase> CreateElement(PropertyGridItemBase data, object context)
    {
        if (this.PropertyGridElement != null)
        {
            CreatePropertyGridItemElementEventArgs args = new CreatePropertyGridItemElementEventArgs(data);

            if (data is PropertyGridItem)
            {
                if ((data as PropertyGridItem).PropertyType == typeof(bool))
                {
                    args.ItemElementType = typeof(CustomPropertyGridCheckBoxItemElement);
                }
                else if ((data as PropertyGridItem).PropertyType == typeof(Color))
                {
                    args.ItemElementType = typeof(PropertyGridColorItemElement);
                }
                else
                {
                    args.ItemElementType = typeof(PropertyGridItemElement);
                }
            }

            if (data is PropertyGridGroupItem)
            {
                args.ItemElementType = typeof(PropertyGridGroupElement);
            }

            MethodInfo mi = typeof(PropertyGridTableElement).GetMethod("OnCreateItemElement", BindingFlags.Instance | BindingFlags.NonPublic);
            mi.Invoke(this.PropertyGridElement, new object[] { args });
            if (args.ItemElementType != null)
            {
                return (PropertyGridItemElementBase)Activator.CreateInstance(args.ItemElementType);
            }
        }

        return base.CreateElement(data, context);
    }
}

public class CustomPropertyGridCheckBoxItemElement : PropertyGridCheckBoxItemElement
{
    public override void Synchronize()
    {
        PropertyGridItem item = this.Data as PropertyGridItem;

        if (item == null)
        {
            return;
        }
        
        base.Synchronize();
    }
}