【问题标题】:expand ViewTree after refresh刷新后展开 ViewTree
【发布时间】:2018-02-14 12:59:17
【问题描述】:

我有一个数据绑定到 xml 文档的视图树,当保存文档时,我在 datacontext 上调用刷新并且视图树折叠,我真的希望视图树不折叠,所以我正在尝试编写一个解包的函数再说一遍。 在这里,我尝试使用 xml 元素的 xpath 来到达 treeviewitems,但是我只能获取根对象,我怀疑这是因为 'ContainerFromItem' 要求它们明显存在而不是逻辑存在? 但我不知道该怎么做。

这是刷新数据上下文后调用的方法

private void UnpackOpened(object sender, EventArgs e)
{
    foreach (var node in nodes)
    {
        var pathStrings = node.Path.Split('/').ToList();
        pathStrings.RemoveAll(string.IsNullOrEmpty);
        for (int i = 0; i < pathStrings.Count; i++)
        {
            pathStrings[i] = pathStrings[i].Replace("{", "").Replace("}", "");
            pathStrings[i] = pathStrings[i].Replace("[", "|").Replace("]", "");
        }

        ExpandTree(OutlineWindowInstance.TreeItems.ItemContainerGenerator, pathStrings, 0);
    }
}

这是一个递归函数,它应该遍历所有以前打开的树视图项并在现在刷新的树中展开它们。

void ExpandTree(ItemContainerGenerator itemses, List<string> treeNodes, int step)
{
    var name = treeNodes[step].Split('|')[0];
    var number = int.Parse(treeNodes[step].Split('|')[1])-1;
    var selected = itemses.Items.Cast<XmlElement>().Where(x => x.LocalName == name).ToList()[number];
    var selectedItem =((TreeViewItem) 
    //this is the line that is failing to do what I had hoped it would do
    itemses.ContainerFromItem(selected)); 
    if(selectedItem == null) return;
    selectedItem.IsExpanded = true;

    step++; 
    if (treeNodes.Count > step)
    {
        ExpandTree(selectedItem.ItemContainerGenerator, treeNodes, step);
    }
}

【问题讨论】:

  • 嵌套的 ItemContainerGenerators 处理起来并不有趣...您必须使用大量 开始生成子项并等待它们完成,然后才能开始生成嵌套的子项这种方法。在我的项目中,我决定通过在我的 Viewmodel 中使用一种 ViewBag 字典来作弊,我可以在其中存储一些与视图状态相关的任意属性。
  • 你能告诉我怎么做吗?我对 WPF 真的很陌生,现在已经与这 1 个问题作斗争超过 2 周了 xD
  • 这并不容易......在我的情况下,我为每个条目都有一个专用的视图模型,而据我所知,您可以直接从某个 XML 源加载数据。您应该首先提供完整的minimal reproducible example,然后我们可以更清楚地了解我们如何为您提供帮助。
  • 您阅读并尝试过吗?:docs.microsoft.com/en-us/dotnet/framework/wpf/controls/…。它向您展示了如何实现一个虚拟化的 TreeViewItem。
  • @TheLogan,如果此问题已解决,您可以将解决方案发布为答案,并标记它。所以它可以帮助其他社区成员。

标签: c# wpf visual-studio-extensions


【解决方案1】:

所以我设法解决了这个问题。 首先,我有一个所有当前文档的列表,为此我创建了以下类,它处理与它所代表的文档的节点有关的所有事情

public class OpennedDocument
{
    public string DocName { get; set; }
    public List<string> ExpandedNodes;
    public bool IsRefreshing { get; set; }

    public void AddExpandedNode(string path)
    {
        if (IsRefreshing) return; //This stops it from registering a node during automatic expansion (after a refresh)
        ExpandedNodes.RemoveAll(path.Contains);
        ExpandedNodes.Add(path);
    }

    public void RemoveExpandedNode(string path)
    {
        var index = path.LastIndexOf("/", StringComparison.Ordinal);

        if(IsRefreshing)return;
        ExpandedNodes.RemoveAll(x => x.Contains(path));

        path = path.Remove(index);
        if(!string.IsNullOrEmpty(path))
            ExpandedNodes.Add(path);
    }
}

这些方法在总管脚本中,并确保刷新之前打开的树视图中的所有节点在之后再次打开。

private void UnpackOpened(object sender, EventArgs e)
{
    var currentDoc = Documents.SingleOrDefault(x => x.DocName == dte.ActiveDocument.FullName);
    if (currentDoc == null) return;
    currentDoc.IsRefreshing = true;

    for (var index = 0; index < currentDoc.ExpandedNodes.Count; index++)
    {
        var node = currentDoc.ExpandedNodes[index];
        var pathStrings = node.Split('/').ToList();
        pathStrings.RemoveAll(string.IsNullOrEmpty);
        for (int i = 0; i < pathStrings.Count; i++)
        {
            pathStrings[i] = pathStrings[i].Replace("{", "").Replace("}", "");
            pathStrings[i] = pathStrings[i].Replace("[", "|").Replace("]", "");
        }

        ExpandTree(OutlineWindowInstance.TreeItems.ItemContainerGenerator, pathStrings, 0,
            OutlineWindowInstance.TreeItems);
    }

    currentDoc.IsRefreshing = false;
}

void ExpandTree(ItemContainerGenerator itemses, List<string> treeNodes, int step, ItemsControl last)
{
    while (true)
    {
        last.UpdateLayout();
        var name = treeNodes[step].Split('|')[0];
        var number = int.Parse(treeNodes[step].Split('|')[1]) - 1;
        var selected = itemses.Items.Cast<XmlElement>().Where(x => x.LocalName == name).ToList()[number];
        var selectedItem = ((TreeViewItem) itemses.ContainerFromItem(selected));
        if (selectedItem == null) return;
        selectedItem.IsExpanded = true;

        step++;
        if (treeNodes.Count > step)
        {
            itemses = selectedItem.ItemContainerGenerator;
            last = selectedItem;
            continue;
        }
        break;
    }
}

【讨论】:

    猜你喜欢
    • 2020-07-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多