Question

Maintaining category expand/collapse state

Posted 9 years ago by Avatar Leo Schnitzler - Rockwell Automation
When a category editor is collapsed and the selected object changes, the property grid shows the category editor expanded again. Is there a way with the property grid to maintain the expand/collapse state of category editors as a users expands/collapses them as they change the selected object?

Comments (19)

Posted 9 years ago by Actipro Software Support - Cleveland, OH, USA
Hi Leo,

We don't currently have anything built into the PropertyGrid that handles this, but it is on our TODO list. It is possible for you to implement this yourself though.

This forum post describes two possible ways. The first way, requires that you listen for Expanded/Collapse events and the other uses a custom DataFactory. Both ideas need to implement an implicit Style for PropertyGridDataAccessorItem that sets the IsExpanded property.

If the other post doesn't help or you get stuck, just let us know.

Actipro Software Support
Posted 3 months ago by Antoine Picard

Hi,

I don't know if this post is still reliable but I checked the forum post and didn't understand it.

Is it still on your TODO list ? Is it done ?

AP

Posted 3 months ago by Actipro Software Support - Cleveland, OH, USA

Hi Antoine,

We don't have a collapsed state preservation feature on the newer property grid.  Are you just looking to restore the previous collapsed state of any categories when a different data object gets assigned to the property grid?

If so, consider this scenario.  You have an object with a category Foo and you collapse it.  Assume we persist that state when you assign another data object that doesn't have category Foo.  Then this object's collapsed state is persisted as another data object with Foo is assigned.  In this scenario, the last persisted collapsed state wouldn't have any info on the Foo category and it would appear expanded.  How would you suggest handling that?


Actipro Software Support
Posted 3 months ago by Antoine Picard

Hi,

I'm not sure I understood your example but in fact, I'm not using any categories but more parent/child properties and everything is in Misc category. For example each of my object is a person with pets :

Misc
|_ Dogs
   |_ Dog1
      |_Name
      |_ Age
   |_ Dog2
      |_ Name
      |_ Age
|_ Cats

At the begining I only see Dogs and Cats property (collapsed), then i expand Dogs to see the list of dogs. If I refresh my object with the same dataObject, I want to keep my Dogs expanded. If I select another object with only Cats, nothing should be expanded. If I go back to a person with Dogs, this property should be expanded.

Is it clear enough ?

AP

Posted 3 months ago by Actipro Software Support - Cleveland, OH, USA

Hi Antoine,

Yes that's effectively what I was asking, just at a higher category level.  The design issue is that I'm not sure the best way to handle tracking what was expanded or collapsed across multiple different DataObject-examining sessions.  If you keep assigning different DataObjects, that could cause the expansion data cache to grow over time.

What would be the best way to track the expansion data?  I don't believe we could do anything like a type/property kind of tracking since there could be multiple instances of a sub-type used in nested properties.  Would it be a "path" kind of string like "Misc\Dogs"?


Actipro Software Support
Posted 3 months ago by Antoine Picard

Hi,

okay, good! However, yes, that's what I'm afraid of too... I can have 3/4 levels of nesting so the growing cache might become a problem. I think we could remove properties when ItemCollapsed event occurs but I'm not sure if it will solve our problem.

I thought about it and I think a "path" kind of string is the best way but I'm not sure if it'll be easily usable to expand sub-properties.

I also tried to apply the solution explained in this forum post but I can't make it work (I may not have understood everything).

Posted 3 months ago by Antoine Picard

Okay so I tried something like this :

I save the name of my property in a List<string> when OnItemExpand event occurs and i delete it on OnItemCollapsed event.

Then I use this function (I added something to check if property appears in my List but it's too long so i didn't pasted it)

private void PropGridOnLoaded(object sender, RoutedEventArgs e)
 {
  var items = VisualTreeHelperExtended.GetAllDescendants<PropertyGridItem>(propGrid);
  foreach (var item in items)
  {
  if(CheckIfItemIsInMyList<string>) item.IsExpanded = true;
  }
 }

 I added this function to Load and TargetUpdated (also tried SourceUpdated) events and I can properly access to the " item.IsExpanded = true " for the good item but it's still not expanded when displayed...

I tried with ItemSelecting and SelectionChanged but I had a weird behaviour, sometimes it worked, sometimes not, sometimes half...

Any idea why ?

[Modified 3 months ago]

Posted 3 months ago by Actipro Software Support - Cleveland, OH, USA

I'm not sure why it would work some times but not others.  Maybe some configuration hasn't yet occurred when you're calling this.

In general, I would probably suggest putting this kind of logic in the data factory instead.  For instance, if you create a class that inherits TypeDescriptorFactory, override GetPropertyModels and set each base method call's IPropertyModel result's IsExpanded property appropriately, then that should have the IsExpanded configured before it ever hits the property grid itself.  Set your custom data factory instance to the PropertyGrid.DataFactory property.


Actipro Software Support
Posted 3 months ago by Antoine Picard

Well,

your solution works for a one nested level but I can't access sub-properties. I tried to use VisualTreeHelperExtended.GetAllDescendants<type>(myObject) but I can't find the right type (as my object contains different types). Maybe I'm using it wrong but in your examples it's always used with SplitContainer type.

Posted 3 months ago by Actipro Software Support - Cleveland, OH, USA

Hello,

I'm not suggesting you use GetAllDescendants at all.  If you are setting IsExpanded in the data factory, you shouldn't need to be accessing UI at all, since IsExpanded can be set on the IPropertyModel itself.


Actipro Software Support
Posted 3 months ago by Antoine Picard

Hi,

If I use your dataFactory example, I have this code :

var propertyModels = new List<IPropertyModel>();
var myPropertyDescriptors = TypeDescriptor.GetProperties(myObject);
foreach (PropertyDescriptor property in myPropertyDescriptors)
 {
  var propertyModel = new PropertyDescriptorPropertyModel(myObject, myPropertyDescriptors[property.Name]);
  if (objectExpanded.Contains(property.Name))
  {
   propertyModel.IsExpanded = true;
  }
  propertyModels.Add(propertyModel);
 }
return propertyModels;

 But I can't access to child properties.

[Modified 3 months ago]

Posted 3 months ago by Actipro Software Support - Cleveland, OH, USA

Hello,

I mean more like this:

protected override IList<IPropertyModel> GetPropertyModels(object dataObject, IDataFactoryRequest request) {
	var propertyModels = base.GetPropertyModels(dataObject, request);
	foreach (var propertyModel in propertyModels) {
		if (objectExpanded.Contains(property.Name))
			propertyModel.IsExpanded = true;
	}
	return propertyModels; 
}

Let our base method do the work of getting the child models and you simply expand results appropriately.


Actipro Software Support
Posted 3 months ago by Antoine Picard

Hi !

I used your solution (I adapted it a little for my project) and it works ! Thanks a lot ! (for real)

I just still have one question. What happen if I have two childs with the same name but not with the same parent ? For example :

House1
|_Mother
   |_Dog1
      |_Age
      |_Weight
|_Father
   |_Dog1
      |_Age
      |_Weight
   |_Cat1
      |_Age
      |_Weight

If at the begining everything is folded, only House1 is displayed, I expand House1 then Mother and Dog1. If I select House2 with the exact same properties, will Mother/Dog1 be expanded (I think so) and what about Father/Dog1 ? As we only check for property name, Father/Dog1 will be expanded too ? I thought about using a "path" like name such as Mother.Dog1 but I can't access to parent of propertyModel (in your previous example).

Any thoughts ?

Posted 3 months ago by Actipro Software Support - Cleveland, OH, USA

Hi Antoine,

Yes, that is correct.  You would want to construct a full path as you described to make sure that you have the same true items.  

The request object that is passed into that GetPropertyModels method has a Parent property on it that returns the parent IDataModel, if any.  Each IDataModel also has a Parent property.  Using that, you should be able to walk up the tree to build a full path.


Actipro Software Support
Posted 2 months ago by Antoine Picard

Hi,

Yes, I saw this Parent property but it's always null. I also checked the Child property and it's also null.
I don't know why but it seems like there is no link between those objects...

Posted 2 months ago by Actipro Software Support - Cleveland, OH, USA

Hi Antoine,

It looks like we wire up the parent/child relationship in our DataFactoryBase.GetDataModels method.  That is the method that calls into GetPropertyModels.  Maybe you could override that instead, calling the base method first before applying your logic.


Actipro Software Support
Posted 2 months ago by Antoine Picard

Hi,

I don't think I understood your idea. Do you suggest me something like 

public class MyDataFactory : DataFactoryBase

 instead of 

public class MyDataFactory : TypeDescriptorFactory

Then overriding GetDataModels instead of overriding GetPropertyModels ?

[Modified 2 months ago]

Posted 2 months ago by Actipro Software Support - Cleveland, OH, USA
TypeDescriptorFactory Inherits DataFactoryBase, so you can try to override that method instead of GetPropertyModels.

Actipro Software Support
Posted 2 months ago by Antoine Picard

Hi ! 

I'm working on something else but I'll try your solution as soon as I can and give you a feedback !

Thanks

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

Add a Comment

Please log in to a validated account to post comments.