In the constructor of XamPropertyGrid, it looks like there is a call to add an event handler to a static event (TypeDescriptor.Refreshed).
IE. I can put a breakpoint in the debugger and I see this method call:
System.ComponentModel.TypeDescriptor.add_Refreshed
There is never an equivalent call to release/unsubscribe from that event handler.
The result is that my app has a very rapid leak. Below is an image of the path to the rooted reference. I suppose I may have to do manual cleanup to remove the XamPropertyGrid control from my ProductDetailsControl as a workaround. But even then it will still have a leak of the XamPropertyGrid instances themselves...
Can anyone suggest any easy workarounds?
Hello David,
It appears that this forum thread is essentially a duplicate to a private support case that you submitted that I have very recently answered and logged a development issue for. I will post a summary transcript of the answer I posted to the support case below:
I have been investigating into the sample project you have provided, and I have reproduced this issue. The workaround to this would normally be to either derive a custom XamPropertyGrid and use reflection to get the event handler for TypeDescriptor.Refreshed to unhook it when the XamPropertyGrid is unloading, but this unfortunately won't work, and I cannot recommend a known workaround for this. The reason it will not work is because of the way this event is hooked in our source code – it is using an anonymous lambda expression event handler, and so I cannot get it using reflection. It is hooked like so:
TypeDescriptor.Refreshed += (e) => { this.PropertyDescriptorCollectionCache.Clear(); };
This is unexpected behavior, and as such, I have asked our engineering staff to examine it further. To ensure that it will receive attention, I have logged this behavior in our internal tracking system with a Development ID of 262191. The next step will be for a developer to review my investigation and confirm my findings or to offer a fix, or other resolution.
It is also worth noting that version 2017.2 has had its final service release, and so this issue will not be fixed in 2017.2. Actually, the earliest version that this will be fixed in will actually be 2018.2, as the final 2018.1 service release has been finalized as of yesterday and is now undergoing testing. You can see this from the product lifecycle page, here: https://es.infragistics.com/support/product-lifecycle.
Please let me know if you have any other questions or concerns on this matter.
Yes, thanks Andrew. I wanted to also post the problem (and eventual resolution) in the open forum. I didn't find any mention of it yet, and this issue would presumably affect every WPF customer using the XamPropertyGrid.
I always like to see problems being solved out in the open. If a google search can give a quick answer to a problem like this one, then it is easy to save some other developer a lot of time (days/weeks) that they might otherwise be interacting with tech support.
... I know there have been many times that I've been able to benefit from public information about well-known bugs (whether in third-party forums or KB's or blogs or whatever).
I tried to mitigate the leak by changing the custom code to remove the XamPropertyGrid from the parent control (ProductDetailsControl). That would happen whenever the ProductDetailsControl was being destroyed. That went to production this weekend. But it only releases the rooted path in certain scenarios. I'm not sure what the pattern is between the scenarios where my ProductDetailsControls are GC'ed and the scenarios where they are not. Out of 800 rooted XamPropertyGrids, I can get 600 related PropertyDetailsControls to be GC'ed by removing the XamPropertyGrid from the ProductDetailsControl. But in the case of the remaining 200, there is no GC and I still have a rooted reference.
In the case of the 600, the system allows the GC to collect the ProductDetailsControls because the paths to root always/only look like the one I had shown earlier.
But in the case of the 200 remainint, the GC is still not able to collect the ProductDetailsControls. For these ones, the paths to root are formatted a bit differently. Please see the following image. It has a different path to root whereby the ProductDetailsControl is referenced via a XamPropertyGridAutomationPeer (whatever that is).
Can someone tell me how I can access the XamPropertyGridAutomationPeer and cause it to release the references to the ProductDetailsControl?
Here is the code I have created so far (ProductDetailsControl code-behind) that was intended to detach from XamPropertyGrid and cause the ProductDetailsControl to be GC'ed (even if the XamPropertyGrid cannot).
public void OnNavigatedFrom(NavigationContext p_NavigationContext) { if(!(m_PropertyGrid.Parent is Grid)) { return; } if(!object.ReferenceEquals(m_PropertyGrid.Parent, m_ThisControlGrid)) { return; } // Clear out the properties; // Make life easy for GC. m_PropertyGrid.SelectedObject = null; m_PropertyGrid.RegenerateProperties(); m_PropertyGrid.UpdateLayout(); // Remove the XamPropertyGrid from it's parent. m_ThisControlGrid.Children.Remove(m_PropertyGrid); // Null things out; and make life easy for GC. m_PropertyGrid.SelectedObject = null; m_PropertyGrid.Resources = null; m_PropertyGrid = null; }
Please let me know how to remove the XamPropertyGridAutomationPeer from by path to root. Any help would be greatly appreciated. Note that this is all being done as a workaround and I expect that the "right" fix will be done within the XamPropertyGrid so that it doesn't permanently get rooted by subscribing to the "TypeDescriptor.Refreshed" event.
For anyone else that encounters this bug, it appears to be fixed.
The rooting of the XamPropertyGrid is not happening in Infragistics WPF 2018 Vol. 2 - Service Release 20182.281.
Thank you for your update on this matter.
I do not personally have much experience with the Citrix environment myself, and so I’m not sure I would really be able to provide much information on how the actual UI Automation works there. That said, I was able to reproduce this is a simple WPF-application without the Citrix environment, and so I would expect that this particular issue is related to that and not Citrix, specifically.
Regarding the bug, I don’t think there is much of a doubt that this rooting is a bug, as the issue seems to be that there is an event handler that is never unhooked. As far as an ETA, though, I do not currently have one, as the bug is not yet assigned to a developer and is in an “In Review” state. At the time of writing this, the upcoming (and final) service release for version 2018.1 is finalized and we are in a “code-frozen” state so that we can accurately perform our automated testing, but if you would like, I can see about getting this issue escalated to an upcoming bi-weekly build or the following service release?
Please let me know how you would like to proceed.
Thanks for the tip about the automation peers. I should probably know more about this stuff. Unfortunately I never enable it (accessibility) on my desktop.
I should point out that I don't enable it in Citrix either ... but it seems to be auto-enabled as a component of some funky Citrix monitoring agent. At least that is what I've been able to gather. The frustration I have with Citrix is that the members of those community forums rarely understand how their stuff works internally, and you can never get answers to questions that are technical. In order to get a WPF application to work properly in Citrix, it simply involves endless "trial-and-error". That's not how I'd prefer to spend my software development hours.
Since you were speaking with Infragistics development, have they acknowledged that the rooting of this control is a bug? Is there any approximate ETA yet on a fix?
It is interesting that the PropertyGridFilterAreaControl is still hanging on to the XamPropertyGrid in this case, but I think you are right that this could be coming from the underlying ControlTemplate of the XamPropertyGrid, as the PropertyGridFilterAreaControl is certainly a part of that template.
You can get at the PropertyGridFilterAreaControl from the XamPropertyGrid by using the Infragistics.Windows.Utilities class and its GetDescendantFromName method, like so, where “propGrid” is your local XamPropertyGrid:
var filterAreaControl = Infragistics.Windows.Utilities.GetDescendantFromName(propGrid, “PART_PropertyGridFilterAreaControl”);
This PropertyGridFilterAreaControl has a parent Grid element, and perhaps removing it from its Grid.Children could help to release it?
As a side note, I have received a comment from someone on our development team here regarding the automation peers. Rather than returning null from the OnCreateAutomationPeer element, they have recommended to create a new automation peer derived from FrameworkElementAutomationPeer and return it. In your new automation peer, you can override the GetChildrenCore method and return an empty list, as this would explicitly tell it to return no children.
I'm following your lead, and I'm setting a variety of private member fields to null on the XamPropertyGrid. It seems that UI automation is causing my ProductDetailsControl to be rooted via *all* of the following private fields on XamPropertyGrid:
_scrollBarInfoMediator_propertyGridFilterAreaControl_columnResizeThumb_itemLayoutPanel_flatItemList
I've set them all to null, including the field, _propertyGridFilterAreaControl. However, that particular one is still appearing in my paths to root on ProductDetailsControl. I think it is because of a control template or something like that. See image below. Notice that there are a few levels of indirection between the XamPropertyGrid and the PropertyGridFilterAreaControl.
This is starting to feel a little hopeless. It is too difficult to tear this XamPropertyGrid out of the visual tree!