Хотя принятый ответ будет работать большую часть времени. Это может не сработать, поскольку объект создается в другом потоке, который вообще не контролируется диспетчером.
Как упоминалось ранее, проблема заключается в том, что TreeViewItem создается в другом потоке, отличном от диспетчерского.
Я лично считаю, что правильное решение является более сложным. Я знаю, что плохо слышать, но я действительно думаю, что это так. Мой код должен работать при виртуализации или нет. Также вы можете удалить любую ссылку, которая не нужна (я не проверял).
Мое решение основано на модели данных, в которой каждый узел наследует один и тот же корень: объект MultiSimBase, но это не является обязательным требованием.
Все начинается с SetSelectedTreeViewItem (), который активирует (+ устанавливает фокус и отображает) вновь добавленный элемент.
Надеюсь, это могло бы помочь или вдохновить ... Счастливое кодирование !!!
Код формы:
// ******************************************************************
private List<MultiSimBase> SetPathListFromRootToNode(MultiSimBase multiSimBase, List<MultiSimBase> listTopToNode = null)
{
if (listTopToNode == null)
{
listTopToNode = new List<MultiSimBase>();
}
listTopToNode.Insert(0, multiSimBase);
if (multiSimBase.Parent != null)
{
SetPathListFromRootToNode(multiSimBase.Parent, listTopToNode);
}
return listTopToNode;
}
// ******************************************************************
private void SetSelectedTreeViewItem(MultiSimBase multiSimBase)
{
List<MultiSimBase> listOfMultiSimBasePathFromRootToNode = SetPathListFromRootToNode(multiSimBase);
TreeViewStudy.SetItemHierarchyVisible(listOfMultiSimBasePathFromRootToNode, (tvi) =>
{
tvi.IsSelected = true;
tvi.Focus();
tvi.BringIntoView();
});
}
А теперь общий код:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Threading;
namespace HQ.Util.Wpf.WpfUtil
{
public static class TreeViewExtensions
{
public delegate void OnTreeViewVisible(TreeViewItem tvi);
private static void SetItemHierarchyVisible(ItemContainerGenerator icg, IList listOfRootToNodePath, OnTreeViewVisible onTreeViewVisible = null)
{
Debug.Assert(icg != null);
if (icg != null)
{
if (listOfRootToNodePath.Count == 0) // nothing to do
return;
TreeViewItem tvi = icg.ContainerFromItem(listOfRootToNodePath[0]) as TreeViewItem;
if (tvi != null) // Due to threading, always better to verify
{
listOfRootToNodePath.RemoveAt(0);
if (listOfRootToNodePath.Count == 0)
{
if (onTreeViewVisible != null)
onTreeViewVisible(tvi);
}
else
{
if (!tvi.IsExpanded)
tvi.IsExpanded = true;
SetItemHierarchyVisible(tvi.ItemContainerGenerator, listOfRootToNodePath, onTreeViewVisible);
}
}
else
{
ActionHolder actionHolder = new ActionHolder();
EventHandler itemCreated = delegate(object sender, EventArgs eventArgs)
{
var icgSender = sender as ItemContainerGenerator;
tvi = icgSender.ContainerFromItem(listOfRootToNodePath[0]) as TreeViewItem;
if (tvi != null) // Due to threading, it is always better to verify
{
SetItemHierarchyVisible(icg, listOfRootToNodePath, onTreeViewVisible);
actionHolder.Execute();
}
};
actionHolder.Action = new Action(() => icg.StatusChanged -= itemCreated);
icg.StatusChanged += itemCreated;
return;
}
}
}
// ******************************************************************
/// <summary>
/// You cannot rely on this method to be synchronous. If you have any action that depend on the TreeViewItem
/// (last item of collectionOfRootToNodePath) to be visible, you should set it in the 'onTreeViewItemVisible' method.
/// This method should work for Virtualized and non virtualized tree.
/// </summary>
/// <param name="treeView">TreeView where an item has to be set visible</param>
/// <param name="collectionOfRootToNodePath">Any of collection that implement ICollection like a generic List.
/// The collection should have every objet of the path to the targeted item from the top to the target.
/// For example for an apple tree: AppleTree (index 0), Branch4, SubBranch3, Leaf2 (index 3)</param>
/// <param name="onTreeViewVisible">Optionnal</param>
public static void SetItemHierarchyVisible(this TreeView treeView, IList listOfRootToNodePath, OnTreeViewVisible onTreeViewVisible = null)
{
ItemContainerGenerator icg = treeView.ItemContainerGenerator;
if (icg == null)
return; // Is tree loaded and initialized ???
SetItemHierarchyVisible(icg, listOfRootToNodePath, onTreeViewVisible);
}
И
using System;
namespace HQ.Util.Wpf.WpfUtil
{
// Requested to unsubscribe into an anonymous method that is a delegate used for a one time execution
// http://social.msdn.microsoft.com/Forums/en-US/csharplanguage/thread/df2773eb-0cc1-4f3a-a674-e32f2ef2c3f1/
public class ActionHolder
{
public void Execute()
{
if (Action != null)
{
Action();
}
}
public Action Action { get; set; }
}
}