Search code examples
monogtk#visual-studio-mac

GTK# Nodeview Nodestore always gets null reference


I've created a GTK# Nodeview + NodeStore following the code in the GTK# Mono tutorial page! My changes were adding a button to Add new entries to the NodeView and trying to make it interactable. My problem is the NodeView Selection Changed event is crashing the application.

using System;
using Gtk;

public partial class MainWindow : Window
{
    Button button;
    NodeView nodeview;
    NodeStore nodestore;

    [TreeNode(ListOnly = true)]
    public class MyTreeNode : TreeNode
    {
        public MyTreeNode(string artist)
        {
            Artist = artist;
        }

        [TreeNodeValue(Column = 0)]
        public string Artist;
    }


    public MainWindow() : base(WindowType.Toplevel)
    {
        Build();

        var vbox = new VBox();
        nodeview = new NodeView();
        // Create a column with title Artist and bind its renderer to model column 0
        nodeview.AppendColumn("Artist", new CellRendererText(), "text", 0);

        nodestore = new NodeStore(typeof(MyTreeNode));
        nodestore.AddNode(new MyTreeNode("temp"));
        nodeview.NodeStore = nodestore;

        nodeview.Selection.Changed += Selection_Changed;

        button = new Button("Add New!!");
        button.Clicked += Button_Clicked;

        vbox.PackStart(nodeview, true, true, 0);
        vbox.PackStart(button, false, true, 0);

        Add(vbox);
        ShowAll();
    }

    void Button_Clicked(object sender, EventArgs e)
    {
        nodestore.AddNode(new MyTreeNode("temp"));
    }

    void Selection_Changed(object sender, EventArgs e)
    {
        NodeSelection selection = (NodeSelection)sender;
        if (selection != null)
        {
            MyTreeNode node = (MyTreeNode)selection.SelectedNode;
            var a = node.Artist;
        }
    }

    protected void OnDeleteEvent(object sender, DeleteEventArgs a)
    {
        Application.Quit();
        a.RetVal = true;


    }
}

When I select a node in the NodeView the application crashs without any notice. Then with some debugging I realized that when entering NodeSelection_Changed the NodeStore variable in the Nodeview is always null. Even though it is adding nodes to it.. (they are being rendered to the nodeview).


Solution

  • This seems to be a bug in GTK# which has been fixed but not in the version that ships with Mono 5.8 and older.

    A workaround is to set the 'store' field in the NodeView class using reflection.

    typeof (NodeView).GetField ("store", BindingFlags.Instance | BindingFlags.NonPublic).SetValue (nodeview, nodestore);
    

    If you add the line above just after the line that sets the nodestore on the NodeView then this fixes the NodeView.NodeStore being null.

    nodeview.NodeStore = nodestore;
    typeof (NodeView).GetField ("store", BindingFlags.Instance | BindingFlags.NonPublic).SetValue (nodeview, nodestore);
    

    Also note that the code you have in the Selection_Changed event is failing because the sender is a Gtk.TreeSelection not a Gtk.NodeSelection. I changed the Selection_Changed method to be the following which works:

    void Selection_Changed(object sender, EventArgs e)
    {
        NodeSelection selection = nodeview.NodeSelection;
        if (selection != null)
        {
            MyTreeNode node = (MyTreeNode)selection.SelectedNode;
            var a = node.Artist;
        }
    }