【前言】
【mono的gtk#有无法识别中文路径的bug,假如你用xamarin studio开发gtk#工程的话,我建议你将工程放到完全英文的路径下面,免却很多麻烦】
最近在搞gtk#,mono下面的一个桌面ui框架,是对gtk+的c#版本,为什么我不停去搞不同的技术呢?只因为我在找一个解决方案。
多余的不说了,
下面上代码。
【正文】
treeview的用法。
gtk#里面没有listview,没有datagridview等等控件,但是有一个近乎万能的treeview。
treeview数据的绑定:
//绑定列及单元格
listConn.AppendColumn ("数据类型", new CellRendererPixbuf (), "pixbuf", 0);
listConn.AppendColumn ("编号", new CellRendererText (), "text", 1);
listConn.AppendColumn ("连接名称", new CellRendererText (), "text", 2);
_connListStore = new ListStore (typeof(Gdk.Pixbuf),typeof(int),typeof(string));
//--获取列表
CodeGen.DAL.ConnectionDAL cdal = new CodeGen.DAL.ConnectionDAL ();
List<ConnectionModel> clist= cdal.getList ();
foreach(ConnectionModel ctmp in clist){
Gdk.Pixbuf pbuf = new Gdk.Pixbuf ("resources/database_icon.png", 24, 24);
_connListStore.AppendValues (pbuf,ctmp.id, ctmp.title);
}
listConn.Model = _connListStore;
//不要让我看见表头
listConn.HeadersVisible = false;
//隐藏“编号”列
listConn.Columns [1].Visible = false;
下面是讲解:
gtk#里面的treeview控件是根据mvc原则来确定的。则:使用treeview的时候必须指定数据源,而官方的数据源就两种 liststore及treestore---比起wpf逊色多了,wpf什么都可以绑。
liststore用于显示列表式的数据,而treestore则显示下面有节点的数据。
_connListStore = new ListStore (typeof(Gdk.Pixbuf),typeof(int),typeof(string));
这就是数据源的定义方式,里面的typeofxxx是对应于你将放进去的数据的格式,譬如上面定义了三个参数,一个是图片类型,一个是整数类型,一个是字符串类型,下面如何给数据源添加数据呢?
foreach(ConnectionModel ctmp in clist){
Gdk.Pixbuf pbuf = new Gdk.Pixbuf ("resources/database_icon.png", 24, 24);
_connListStore.AppendValues (pbuf,ctmp.id, ctmp.title);
}
没错,就是用上面这种方式了,这种方式看上去有点古老。
listConn.Model = _connListStore;
好了绑定了,但是这时候运行你是不会看到任何东西的,因为你只是绑定了数据,没有指定数据的列对应何种参数:
listConn.AppendColumn ("数据类型", new CellRendererPixbuf (), "pixbuf", 0);
ok,基本完成,每一列都定义好了,假如不希望看到表头的话,请用 headersvisible=false来设定。
【treeview的treestore及树形结构】
_treeStore_Db = new TreeStore (typeof(Gdk.Pixbuf), typeof(string));
tree_dbDetail.HeadersVisible = false;
tree_dbDetail.AppendColumn ("logo", new CellRendererPixbuf (), "pixbuf", 0);
tree_dbDetail.AppendColumn ("名称", new CellRendererText (), "text", 1);
_treeIter_tables= _treeStore_Db.AppendValues (new Gdk.Pixbuf ("resources/table3.png", 24, 24), "数据表");
_treeIter_views = _treeStore_Db.AppendValues (new Gdk.Pixbuf ("resources/view_icon.png", 24, 24), "视图");
_treeIter_procs = _treeStore_Db.AppendValues (new Gdk.Pixbuf ("resources/database_active.png", 24, 24), "存储过程");
tree_dbDetail.Model = _treeStore_Db;
treestore的绑定与liststore大同小异,不过请注意,给treestore添加相关参数后会返回当前节点,不过假如你想自由自在地控制,你可以用:
_treeStore_Db.IterChildren(out childNode)
获得根目录下面的第一个子节点,还有另一种用法
_treeStore_Db.IterChildren (out childNode,_treeIter_views);
这种用法表示_treeIter_views下面的第一个节点。
或者这样得到下一个节点:
_treeStore_Db.IterNext (out childNode,_treeIter_views);
或者:
_treeStore_Db.IterNext (out childNode);
这两种用法与上面的雷同。
【如何添加选中事件,如何清楚下属节点,如何添加下属节点?】
添加选中事件:
this.listConn.RowActivated += new global::Gtk.RowActivatedHandler (this.OnRowActivated);
然后编写相关事件:
/// <summary>
/// 当选择某个行时的操作
/// </summary>
/// <param name="o">O.</param>
/// <param name="args">Arguments.</param>
protected void OnRowActivated (object o, RowActivatedArgs args)
{/*
MessageDialog mydialog = new MessageDialog (this, DialogFlags.Modal, MessageType.Info,ButtonsType.Ok,"您好吗?");
ResponseType res1= (ResponseType)mydialog.Run ();
if (res1 == ResponseType.Ok) {
mydialog.Destroy ();
}
*/
TreeView view = (TreeView)o;
TreeIter iter;
view.Model.GetIter (out iter, args.Path);
int theRecordID= (int)view.Model.GetValue (iter, 1);
ConnectionDAL cdal = new ConnectionDAL ();
ConnectionModel cmodel= cdal.getRecord (theRecordID);
MSSQLProvider mspro = new MSSQLProvider (cmodel.serverip, cmodel.account, cmodel.pwd, cmodel.database);
List<string> tableNames= mspro.getTableNames ();
List<string> procNames = mspro.getProcNames ();
/*请空每一个节点下面的子节点*/
TreeIter childNode;
while(_treeStore_Db.IterChildren (out childNode, _treeIter_tables)==true){
_treeStore_Db.Remove (ref childNode);
}
while(_treeStore_Db.IterChildren (out childNode, _treeIter_procs)==true){
_treeStore_Db.Remove (ref childNode);
}
/*绑定*/
foreach(string tableName1 in tableNames){
_treeStore_Db.AppendValues (_treeIter_tables, new Gdk.Pixbuf ("resources/table163.png", 18, 18), tableName1);
}
foreach(string procName1 in procNames){
_treeStore_Db.AppendValues (_treeIter_procs, new Gdk.Pixbuf ("resources/database.png", 18, 18), procName1);
}
/*树形结构默认是闭合的,将三个节点全都打开。*/
tree_dbDetail.ExpandToPath (_treeStore_Db.GetPath (_treeIter_tables));
tree_dbDetail.ExpandToPath (_treeStore_Db.GetPath (_treeIter_procs));
tree_dbDetail.ExpandToPath (_treeStore_Db.GetPath (_treeIter_views));
}
有了上面的知识以后你可能会比较明白了:
TreeView view = (TreeView)o;
TreeIter iter;
view.Model.GetIter (out iter, args.Path);
首先,获得当前选中的节点,然后,将相关下属节点清楚干净再添加:
/*请空每一个节点下面的子节点*/
TreeIter childNode;
while(_treeStore_Db.IterChildren (out childNode, _treeIter_tables)==true){
_treeStore_Db.Remove (ref childNode);
}
while(_treeStore_Db.IterChildren (out childNode, _treeIter_procs)==true){
_treeStore_Db.Remove (ref childNode);
}
/*绑定*/
foreach(string tableName1 in tableNames){
_treeStore_Db.AppendValues (_treeIter_tables, new Gdk.Pixbuf ("resources/table163.png", 18, 18), tableName1);
}
foreach(string procName1 in procNames){
_treeStore_Db.AppendValues (_treeIter_procs, new Gdk.Pixbuf ("resources/database.png", 18, 18), procName1);
}
中间那一段代码是代码生成器相关代码,意思是获得相关数据库的所有表名,存储过程名称等等。
附带一张半成品: