Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice

Rename Items in a ListView with slow double click or F2?

Discussion in 'UI Toolkit' started by PhantasmicDev, Dec 6, 2019.

  1. PhantasmicDev

    PhantasmicDev

    Joined:
    Jul 10, 2013
    Posts:
    35
    For my custom editor window I have a ListView that shows a list of scriptable objects from my assets folder. Is it possible to rename them from the list view as we would a gameobject in the hierarchy and how would I go about implementing that?
     
  2. pirho_luke

    pirho_luke

    Joined:
    Oct 24, 2017
    Posts:
    21
    When creating the element that the ListView is showing you can register for KeyDownEvent and MouseDownEvent callbacks. For the KeyDownEvent you can check if the KeyCode is F2 and then start the name change. For the MouseDownEvent there is no way to assure the click is a slow double click so you would have to do that manually by setting a timer when the item is first selected (using the ListView.selectionChanged property). Then in the MouseDownEvent callback check that a certain amount of time has passed and that the clicked item is the selected item (ListView.selectedItem or ListView.selectedIndex).

    To perform the actual name change, I would add TextField to the selected element with isDelayed set to true. Then register for a ChangeEvent<string> callback to set the name of your corresponding ScriptableObject, then remove the TextField. You would likely have to register for some other events like FocusOut to make sure the TextField is removed when no new text is entered.

    Hope all that made sense!
     
    uDamian likes this.
  3. PhantasmicDev

    PhantasmicDev

    Joined:
    Jul 10, 2013
    Posts:
    35
    Ahh I see. I ended up changing my approach. In my custom window I have a button that creates a new scriptable object and adds it to the list of the listview, I thought, I should be able to rename the scriptable object after it's created, but now I'm using
    Code (CSharp):
    1. EditorUtility.SaveFilePanelInProject()
    and it's a much nicer workflow to name new scriptable objects. So now my follow up question is, how can I refresh the ListView after I added the new item to the list? I tried
    Code (CSharp):
    1. ListView.Refresh()
    but it gives me an error that an object is destroyed and I'm trying to access it. The error points to my bindItem action. Any help is appreciated.
     
  4. uDamian

    uDamian

    Unity Technologies

    Joined:
    Dec 11, 2017
    Posts:
    1,203
    Would help to see some of your code, like the bindItem and makeItem implementations.
     
  5. PhantasmicDev

    PhantasmicDev

    Joined:
    Jul 10, 2013
    Posts:
    35
    Fair enough. I run this method when the editor window opens
    Code (CSharp):
    1. private void ListViewInitialization()
    2.     {
    3.         VisualElement makeItem() => new Label();
    4.  
    5.         Action<VisualElement, int> bindItem = (e, i) => (e as Label).text = editingSegment.data.obstacleLayouts[i].name;
    6.  
    7.         layoutsListView = editorContainer.Q<ListView>(name = "layouts-listview");
    8.  
    9.         layoutsListView.itemsSource = editingSegment.data.obstacleLayouts;
    10.         layoutsListView.makeItem = makeItem;
    11.         layoutsListView.bindItem = bindItem;
    12.  
    13.         layoutsListView.selectionType = SelectionType.Single;
    14.         layoutsListView.onItemChosen += OnLayoutSelected;
    15.     }
    "obstacleLayouts" is the list I'm displaying. And here's where I create a new item on the list (newLayout) and try to refresh the list.
    Code (CSharp):
    1. private void CreateLayout()
    2.     {
    3.         string savePath = EditorUtility.SaveFilePanelInProject("Save Layout", "NewLayout", "asset", "");
    4.  
    5.         ObstacleLayout newLayout = new ObstacleLayout();
    6.         AssetDatabase.CreateAsset(newLayout, savePath);
    7.  
    8.         editingSegment.data.obstacleLayouts.Add(newLayout);
    9.         layoutsListView.Refresh();
    10.     }
    Edit: I think it might be that "newLayout" is the instance and not the .asset file so it get's destroyed. I'll try loading the asset from with the savePath and see if things work properly

    Edit #2: That seemed to be problem, it's working correctly now!
     
    Last edited: Dec 10, 2019
    uDamian likes this.