Duplicate TreeView Schema is VS Code Extension

微笑、不失礼 提交于 2019-12-11 17:53:16

问题


I'm writing a VS Code extension that implements a custom viewsContainer. It is activated in an onView: event specified in the package JSON.

This all works great, and my view pulls in data from a static JSON file and does add each node to the view.

My JSON is strucutured like this:

{
  "name": "root",
  "children": {
    "Child1": [
      { "id": "childId1", "name": "childName1" },
      { "id": "childId2", "name": "childId2" }
    ],
    "Child2": [
        { "id": "childId1", "name": "childName1" },
        { "id": "childId2", "name": "childId2" }
    ],
    "Child3": [
        { "id": "childId1", "name": "childName1" },
        { "id": "childId2", "name": "childId2" }
    ],
    "Child4": [
        { "id": "childId1", "name": "childName1" },
        { "id": "childId2", "name": "childId2" }
    ]
  }
}

and my class that is registered as a treeviewprovider in extension.ts is:

import * as vscode from "vscode";

import * as validateMenuItems from "./validateMenuItems.json";

export class ValidateMenuProvider
  implements vscode.TreeDataProvider<ValidateMenu> {
  private _onDidChangeTreeData: vscode.EventEmitter<
    ValidateMenu | undefined
  > = new vscode.EventEmitter<ValidateMenu | undefined>();
  readonly onDidChangeTreeData: vscode.Event<ValidateMenu | undefined> = this
    ._onDidChangeTreeData.event;

  constructor() {}

  refresh(): void { 
    this._onDidChangeTreeData.fire();
  }

  getTreeItem(element: ValidateMenu): vscode.TreeItem {
    if(element) {
      console.log(`element: ${element}`);
      return element;
    }

    return element;
  }

  getChildren(element?: ValidateMenu): Thenable<ValidateMenu[]> {
    if (element) {
      return Promise.resolve([]);
    } else {
      return Promise.resolve(this.getValidateMenu());
    }
  }

  private getValidateMenu(): ValidateMenu[] {
    const toMenu = (
      menuTitle: string,
      collapsibleState: vscode.TreeItemCollapsibleState
    ): ValidateMenu => {
      return new ValidateMenu(menuTitle, collapsibleState);
    };

    let menuItems: any = []; 
    let menuHeadings: any = validateMenuItems.children;

    let j: number = 0;
    for (var i in menuHeadings) {
      // send the parent as a menu item
      if (menuHeadings[i] !== null && typeof menuHeadings[i] === "object") {
        let firstChildLabel: string = Object.keys(validateMenuItems.children)[
          j
        ];
        let parentMenuItem = toMenu(
          firstChildLabel,
          vscode.TreeItemCollapsibleState.Collapsed 
        );
        menuItems.push(parentMenuItem);

        // send each child object to the view
        for (var k = 0; k < menuHeadings[i].length; k++) {
          if (
            menuHeadings[i][k] !== null &&
            typeof menuHeadings[i][k] === "object"
          ) {
            let secondChildLabel: string = menuHeadings[i][k].name;
            let childMenuItem = toMenu(
              secondChildLabel,
              vscode.TreeItemCollapsibleState.None
            );
            menuItems.push(childMenuItem);
          } else {
            return [];
          }
        }
      } else {
        return [];
      }
      j++;
    }

    return menuItems;
  }
}

export class ValidateMenu extends vscode.TreeItem {
  constructor(
    public readonly label: string,
    public readonly collapsibleState: vscode.TreeItemCollapsibleState,
    public readonly command?: vscode.Command
  ) {
    super(label, collapsibleState);
  }
}

What this does is put every item in the JSON into the view, the first set of object under root.children as collapsed items, and their respective children as non-expandable/collapsible.

However, for each of the expandable items, if I click to expand it, the entire rest of the JSON schema is repeated underneath it.

From stepping through and watching the call stack frames it appears that the requried getChildren() method is first initially called when the provider is registered, and at each expand event.

My question is - since getChildren() requires a <Thenable>, where am I going wrong with my implementation with getValidateMenu() that will avoid duplicating the schema on the collapsed objects, and actually group it's child objects within the collapsed item?

Do the immediate root.children items need to have a command that calls some kind of onclick sort of method, that gets this and reveals its children?

Any pointers from those more familiar greatly appreciated.


回答1:


You're not implementing getChildren() correctly. It's documented like this:

Get the children of element or root if no element is passed.

What your implementation seems to do instead is "return a flat list of all tree items when no element is passed, and an empty list otherwise".

You need to actually return the children of the requested element (and only the immediate children, instead of returning the whole tree at once for the root element).

The official Tree View Sample might be worth checking out.




回答2:


Even I struggled with this for quite a while, found the github repo shared by the OP in another question. I think it's worthwhile mentioning it here so that others are benefited.

https://github.com/trebleCode/dxdevcheck/blob/master/src/validateMenu.ts

The key for me was to add children field to my TreeItem subclass as mentioned by @Gama11 in the comments.



来源:https://stackoverflow.com/questions/55418551/duplicate-treeview-schema-is-vs-code-extension

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!