Мы используем консольное приложение AutomationUIClient для тестирования нашего приложения WPF.
Мы установили в нашем приложении WPF пользовательский класс TreeItemAutomationPeer с ISelectionProvider ad IExpandCollapseProvider
Если этот объект используется консолью приложения автоматизации, владелец (TreeItem в моем случае) сохраняется, поэтому он утечки ...
Мы добавляем последний метод GetChildrenCore (), чтобы предотвратить утечки памяти от детей.
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.
Как можно освободить владельца TreeItemAutomationPeer от ExpandCollapseProviderWrapper для предотвращения утечки?
В консольном приложении мы получаем объект AutomationElement.Есть ли список всех элементов AutomationElement, которые мы использовали, и способ их выпуска?
Большое спасибо:)
Whiletrue
EDIT:
Согласнок документации точки памяти (https://www.jetbrains.com/help/dotmemory/Analyzing_GC_Roots.html) Дескриптор RefCounts:
Корень предотвращает сборку мусора, если счетчик ссылок объекта имеет определенное значение.Если объект передается в библиотеку COM с помощью COM Interop, CLR создает дескриптор RefCounting для этого объекта.Этот корень необходим, так как COM не может выполнить сборку мусора.Вместо этого он использует подсчет ссылок.Если объект больше не нужен, COM устанавливает счетчик равным 0. Это означает, что дескриптор RefCounts больше не является корнем, и объект можно собирать.Таким образом, если вы видите дескриптор RefCounting, то, вероятно, объект передается в качестве аргумента неуправляемому коду.