我们使用 AutomationUIClient 控制台应用程序来测试我们的 WPF 应用程序。
我们在 WPF 应用程序中设置了一个自定义类 TreeItemAutomationPeer 与 ISelectionProvider 和 IExpandCollapseProvider
如果此对象由自动化应用程序控制台使用,则所有者(在我的情况下为 TreeItem)被保留,因此它会泄漏......
我们添加最后一个方法 GetChildrenCore() 以防止来自 Children 的内存泄漏。
public class TreeItemAutomationPeer : FrameworkElementAutomationPeer, ISelectionItemProvider, IExpandCollapseProvider
{
private readonly TreeItem _treeItem;
public TreeItemAutomationPeer(TreeItem treeItem)
: base(treeItem)
{
_treeItem = treeItem;
}
public override object GetPattern(PatternInterface patternInterface)
{
if (patternInterface == PatternInterface.SelectionItem ||
patternInterface == PatternInterface.ExpandCollapse)
return this;
return base.GetPattern(patternInterface);
}
protected override string GetClassNameCore()
{
return "TreeItem";
}
protected override AutomationControlType GetAutomationControlTypeCore()
{
//return AutomationControlType.Tree;
return AutomationControlType.Custom;
}
#region ISelectionItemProvider
public IRawElementProviderSimple SelectionContainer
{
get { return _treeItem.SelectionContainer; }
}
public bool IsSelected { get { return _treeItem.Item.IsSelected; } }
public void AddToSelection()
{
_treeItem.Item.IsSelected = true;
ItemHelper.SelectItem(_treeItem, _treeItem.Item);
}
public void RemoveFromSelection()
{
_treeItem.Item.IsSelected = false;
}
public void Select()
{
if (_treeItem.Item.IsSelected)
RemoveFromSelection();
else AddToSelection();
}
#endregion
#region IExpandCollapseProvider
public ExpandCollapseState ExpandCollapseState
{
get
{
return _treeItem.Item.IsExpanded
? ExpandCollapseState.Expanded
: ExpandCollapseState.Collapsed;
}
}
public void Expand()
{
_treeItem.Item.IsExpanded = true;
}
public void Collapse()
{
_treeItem.Item.IsExpanded = false;
}
#endregion
protected override List<AutomationPeer> GetChildrenCore()
{
return null;
}
}
TreeItem 类实现 IRawElementProviderSimple
#region Automation
private TreeItemAutomationPeer _itemAutomationPeer;
protected override AutomationPeer OnCreateAutomationPeer()
{
_itemAutomationPeer = new TreeItemAutomationPeer(this);
return _itemAutomationPeer;
}
public IRawElementProviderSimple SelectionContainer
{
get { return _container; }
}
#endregion
#region IRawElementProviderSimple
protected IntPtr GetWindowHandle() { return IntPtr.Zero; }
protected string GetName() { return Name; }
protected void AddAutomationProperty(int propertyId, object value) { }
public object GetPatternProvider(int patternId) { return null; }
public object GetPropertyValue(int propertyId)
{
return propertyId == AutomationElementIdentifiers.NameProperty.Id ? GetName() : null;
}
public IRawElementProviderSimple HostRawElementProvider { get { return null; } }
public ProviderOptions ProviderOptions
{
get { return ProviderOptions.ServerSideProvider; }
}
#endregion
这是 DotMemory 的泄漏:
当我拍摄快照时,控制台应用程序仍附加到 WPF 应用程序。
如何从 ExpandCollapseProviderWrapper 释放 TreeItemAutomationPeer 的所有者以防止泄漏?
在控制台应用程序中,我们获得了 AutomationElement 对象。是否有我们使用的所有 AutomationElement 的列表以及释放它们的方法?
非常感谢 :)
虽然真实
编辑 :
根据 dotmemory 文档 ( https://www.jetbrains.com/help/dotmemory/Analyzing_GC_Roots.html ) RefCounted 句柄是:
如果对象的引用计数是某个值,则根会阻止垃圾收集。如果使用 COM Interop 将对象传递给 COM 库,CLR 会为此对象创建一个 RefCounted 句柄。由于 COM 无法执行垃圾回收,因此需要此根。相反,它使用引用计数。如果不再需要该对象,COM 将计数设置为 0。这意味着 RefCounted 句柄不再是根,可以收集该对象。因此,如果您看到 RefCounted 句柄,那么很可能该对象作为参数传递给非托管代码。