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).
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;
}
}