[Gtk-sharp-list] DataGrid control, data binding, ObjectViews, Swf, Gtk

Daniel Morgan monodanmorg at yahoo.com
Sat Nov 19 11:47:40 EST 2005


Skipped content of type multipart/alternative-------------- next part --------------
// DataGrid.cs
namespace Mono.Data.GtkSharp
{
	// notice System.Data is not references here

	using System;
	using System.Collections;
	using System.ComponentModel;
	using System.Reflection;
	using System.Runtime.InteropServices;
	using System.Text;
	
	using GLib;
	using Gtk;

	public class DataGridColumn 
	{
		private string columnName = "";
		private TreeViewColumn treeViewColumn = null;
		public CellRendererText Renderer = null; // should be internal

		public string ColumnName {
			get {
				return columnName;
			}
			set {
				columnName = value;
			}
		}

		public TreeViewColumn TreeViewColumn {
			get {
				return treeViewColumn;
			}
			set {
				treeViewColumn = value;
			}
		}
	}

	public class DataGrid : VBox {
		private ListStore store;
		private TreeView treeView;

		public ArrayList gridColumns; // TODO: make Columns a collection

		public DataGrid () : base(false, 4) {		
			ScrolledWindow sw = new ScrolledWindow ();
			this.PackStart (sw, true, true, 0);

			treeView = new TreeView (store);
			treeView.HeadersVisible = true;
			//treeView.ModifyFont (Pango.FontDescription.FromString ("courier new"));

			gridColumns = new ArrayList(0);

			sw.Add (treeView);

			store = new ListStore (GLib.GType.String);

			treeView.EnableSearch = true;
			treeView.HeadersClickable = true;
			dataMember = "";
			dataSource = null;
			
			
		}

		ArrayList bindrows = null;
		object resolvedDataSource = null;

		private bool editable = true;

		private object dataSource;

		private string dataMember;

		public int SelectedRow { 
			get {
				TreeIter iter;
				TreeModel model;
				TreeSelection selection = treeView.Selection;
				if (selection.GetSelected (out model, out iter)) {
					TreePath[] path = selection.GetSelectedRows (out model);
					return path[0].Indices[0]; // return selected row 
				}
				else
					return -1; // not selected
			}
		}

		public TreeIter SelectedIter {
			get {
				TreeIter iter;
				TreeModel model;
				TreeSelection selection = treeView.Selection;
				if (selection.GetSelected (out model, out iter))
					return iter; // return seelcted iter
				else
					return TreeIter.Zero; // not selected
			}

		}

		public TreeView View 
		{
			get 
			{
				return treeView;
			}
		}

		public object DataSource 
		{
			get 
			{
				return dataSource;
			}
			set 
			{
				dataSource = value;
			}
		}

		public string DataMember 
		{
			get 
			{
				return dataMember;
			}
			set 
			{
				dataMember = value;
			}
		}

		public ListStore Store 
		{
			get 
			{
				return store;
			}
		}

		public ArrayList Columns 
		{
			get 
			{
				return gridColumns;
			}
		}

		public bool Editable {
			get {
				return editable; // not a good way to see if its editable or not 
				// because various columns could be editable and others non-editable
			}

			set {
				editable = value;
				if (value == true) {
					for(int c = 0; c < gridColumns.Count; c++) {
						DataGridColumn col = (DataGridColumn) gridColumns[c];
						col.TreeViewColumn.Clickable = true;
						col.Renderer.Mode = CellRendererMode.Editable;
						col.Renderer.Editable = true;
					}
					treeView.RulesHint = true;
					treeView.Selection.Mode = SelectionMode.Single;
				}
				else {
					for(int c = 0; c < gridColumns.Count; c++) {
						DataGridColumn col = (DataGridColumn) gridColumns[c];
						col.TreeViewColumn.Clickable = false;
						col.Renderer.Mode = CellRendererMode.Inert;
						col.Renderer.Editable = false;
					}
					treeView.RulesHint = false;
					treeView.Selection.Mode = SelectionMode.Single;
				}
			}
		}

		public int AddNew() 
		{
			// TODO: need to check if resolved data source is not null

			IBindingList b = (IBindingList) resolvedDataSource;

			if (b.AllowNew) {
				object obj = b.AddNew();
				if (obj == null) {
					//Console.Error.WriteLine("obj is null");
				}
				else {
					//Console.Error.WriteLine("Type: " + obj.GetType().ToString());
					bindrows.Add(obj);

					TreeIter iter = NewRow();			
					for(int i = 0; i < gridColumns.Count; i++)
						SetColumnValue (iter, i, String.Empty);

					return bindrows.Count - 1;
				}
			}

			return -1;
		}

		public int DeleteRow(int row) 
		{
			if (row < 0)
				return -1; // should throw an exception - out of range

			TreeIter iter = TreeIter.Zero;
			if (store.IterNthChild(out iter, row) == false)
				return -1;

			IBindingList b = (IBindingList) resolvedDataSource;
			if (b.AllowRemove) {
				IList list = (IList) resolvedDataSource;
				bindrows.RemoveAt(row);
				store.Remove (ref iter);
				list.RemoveAt (row);

				return row;
			}

			return -1;
		}

		// sets the column count.  beware, it clears
		// use this if you are going to load each column and row yourself
		// instead of using DataBind() or DataLoad()
		public void SetColumnCount (int columnCount) 
		{
			Clear ();
			dataMember = "";
			dataSource = null;

			GLib.GType[] theTypes = new GLib.GType[columnCount];
			gridColumns = new ArrayList ();
			for (int col = 0; col < columnCount; col++) 
			{
				theTypes[col] = GLib.GType.String;
				gridColumns.Add (new DataGridColumn ());
			}
			store.ColumnTypes = theTypes;
		}

		// load data from a data table or data set
		public long DataBind () 
		{
			long rowsRetrieved = 0;

			Clear ();

			System.Object o = null;
			o = GetResolvedDataSource (DataSource, DataMember);
			resolvedDataSource = o;
			IEnumerable ie = (IEnumerable) o;
			ITypedList tlist = (ITypedList) o;
			TreeIter iter = new TreeIter ();
									
			PropertyDescriptorCollection pdc = tlist.GetItemProperties (new PropertyDescriptor[0]);
			gridColumns = new ArrayList(pdc.Count);

			// define the columns in the treeview store
			// based on the schema of the result
			GLib.GType[] theTypes = new GLib.GType[pdc.Count];
			for (int col = 0; col < pdc.Count; col++) {
				theTypes[col] = GLib.GType.String;
			}
			store.ColumnTypes = theTypes;

			bindrows = new ArrayList();

			int colndx = -1;
			foreach (PropertyDescriptor pd in pdc) {

				colndx ++;

				DataGridColumn gridCol = new DataGridColumn ();
				gridCol.ColumnName = pd.Name;		
				gridColumns.Add (gridCol);
			}

			bindrows = new ArrayList();

			foreach (System.Object obj in ie) {
				ICustomTypeDescriptor custom = (ICustomTypeDescriptor) obj;
				PropertyDescriptorCollection properties = custom.GetProperties ();

				bindrows.Add(obj);
				
				rowsRetrieved ++;
				iter = NewRow ();
				int cv = 0;
				foreach (PropertyDescriptor property in properties) {
					object oPropValue = property.GetValue (obj);
					string sPropValue = "";
					if (oPropValue.GetType ().ToString ().Equals("System.Byte[]"))  {
						//sPropValue = SqlSharpGtk.GetHexString ((byte[]) oPropValue);
						Console.Error.WriteLine("Byte[]  value");
					}
					else
						sPropValue = oPropValue.ToString ();
										
					SetColumnValue (iter, cv, sPropValue);
					cv++;			
				}
			}

			treeView.Model = store;
			AutoCreateTreeViewColumns ();
			return rowsRetrieved;
		}

		// borrowed from Mono's System.Web implementation
		protected IEnumerable GetResolvedDataSource(object source, string member) 
		{
			if (source != null && source is IListSource) {
				IListSource src = (IListSource) source;
				IList list = src.GetList ();
				if (!src.ContainsListCollection) {
					return list;
				}
				if (list != null && list is ITypedList) {

					ITypedList tlist = (ITypedList) list;
					PropertyDescriptorCollection pdc = tlist.GetItemProperties (new PropertyDescriptor[0]);
					if (pdc != null && pdc.Count > 0) {
						PropertyDescriptor pd = null;
						if (member != null && member.Length > 0) {
							pd = pdc.Find (member, true);
						} else {
							pd = pdc[0];
						}
						if (pd != null) {
							object rv = pd.GetValue (list[0]);
							if (rv != null && rv is IEnumerable) {
								return (IEnumerable)rv;
							}
						}
						throw new Exception ("ListSource_Missing_DataMember");
					}
					throw new Exception ("ListSource_Without_DataMembers");
				}
			}
			if (source is IEnumerable) {
				return (IEnumerable)source;
			}
			return null;
		}

		public void Clear () 
		{
			if (store != null) 
			{
				store.Clear ();
				store = null;
				store = new ListStore (GLib.GType.String);
			}
			else
				store = new ListStore (GLib.GType.String);

			if (gridColumns != null) 
			{
				for (int c = 0; c < gridColumns.Count; c++) 
				{
					DataGridColumn gridCol = (DataGridColumn) gridColumns[c];
					if (gridCol.TreeViewColumn != null) 
					{
						treeView.RemoveColumn (gridCol.TreeViewColumn);
						gridCol.TreeViewColumn = null;
					}
				}
				gridColumns.Clear ();
				gridColumns = null;
			}
		}

		public TreeIter NewRow () 
		{ 
			return store.Append();
		}

		public void AddRow (object[] columnValues) 
		{	
			TreeIter iter = NewRow ();			
			for(int col = 0; col < columnValues.Length; col++) {
				string cellValue = columnValues[col].ToString ();
				SetColumnValue (iter, col, cellValue);
			}
		}

		public void SetColumnValue (TreeIter iter, int column, string value) 
		{
			GLib.Value cell = new GLib.Value (value);
			store.SetValue (iter, column, cell);	
		}

		public void SetColumnValue (TreeIter iter, int column, byte[] value) 
		{
			//string svalue = SqlSharpGtk.GetHexString (value);
			//SetColumnValue (iter, column, svalue);
		}

		private void AutoCreateTreeViewColumns () 
		{
			for(int col = 0; col < gridColumns.Count; col++) {
				// escape underscore _ because it is used
				// as the underline in menus and labels
				StringBuilder name = new StringBuilder ();
				foreach (char ch in ((DataGridColumn) gridColumns[col]).ColumnName) {
					if (ch == '_')
						name.Append ("__");
					else
						name.Append (ch);
				}
				TreeViewColumn tvc = CreateColumn (col, name.ToString ());
				AppendColumn (tvc);
			}
		}

		public int AppendColumn(TreeViewColumn tvc) 
		{
			return treeView.AppendColumn (tvc);
		}

		private void TextCellEdited (object o, EditedArgs args) 
		{
			IBindingList b = (IBindingList) resolvedDataSource;
			if (b.AllowEdit) {
				// ITypedList may help you figure out how to convert
				// between different data types
				// such as, how to display numbers, dates, etc...

				TreePath path = new TreePath (args.Path);
				TreeIter iter;
				store.GetIter (out iter, path);
				int i = path.Indices[0];
			
				TreePath cpath;
				string cellValue = args.NewText;

				TreeViewColumn tvcolumn;
				treeView.GetCursor (out cpath, out tvcolumn);
				int c = 0;
				for(c = 0; c < gridColumns.Count; c++) {
					TreeViewColumn tvc = ((DataGridColumn) gridColumns[c]).TreeViewColumn;
					if (tvcolumn == tvc) {
						Console.Error.WriteLine("Column clicked:  Column Name: " + tvcolumn.Title);
						Console.Error.WriteLine("     Ordinal: " + c.ToString());
						break;
					}
				}

				if (c >= gridColumns.Count)
					Console.Error.WriteLine("tv col not found");

				ICustomTypeDescriptor custom = (ICustomTypeDescriptor) bindrows[i];
				PropertyDescriptorCollection properties = custom.GetProperties ();
				PropertyDescriptor pd = properties[c];
				pd.SetValue(bindrows[i], cellValue);
			
				Console.Error.WriteLine("    Row number: " + path.Indices[0].ToString());
				Console.Error.WriteLine("    Cell Value: " + cellValue);
			
				((IEditableObject) bindrows[i]).BeginEdit();
				SetColumnValue(iter, c, cellValue);
				((IEditableObject) bindrows[i]).EndEdit();
			}
		}

		public TreeViewColumn CreateColumn (int columnNum, string columnName) 
		{
			TreeViewColumn treeViewCol = new TreeViewColumn ();		 
			CellRendererText renderer = new CellRendererText ();
			treeViewCol.Clickable = true;
			treeView.RulesHint = true;
			
			treeView.Selection.Mode = SelectionMode.Single;
			//treeView.Selection.Mode = SelectionMode.Multiple;

			// Editable, Activatable, Inert
			renderer.Mode = CellRendererMode.Editable;
			//renderer.Family = "courier new";
			renderer.Editable = true;
			renderer.Edited += new EditedHandler (TextCellEdited);
			treeViewCol.Title = columnName;
			treeViewCol.PackStart (renderer, true);
			treeViewCol.AddAttribute (renderer, "text", columnNum);

			DataGridColumn gridCol = (DataGridColumn) gridColumns[columnNum];
			gridCol.Renderer = renderer;
			gridCol.TreeViewColumn = treeViewCol;
			
			return treeViewCol;
		}
	}
}

-------------- next part --------------
// $ mcs /out:TestDataGrid.exe TestDataGrid.cs DataGrid.cs -pkg:gtk-sharp-2.0 /r:System.Data.dll
// TestDataGrid.cs
namespace Mono.Data.GtkSharp 
{
	using System;
	using System.Collections;
	using System.Collections.Specialized;
	using System.Configuration;
	using System.Data;
	using System.Data.Common;
	using System.Data.SqlTypes;
	using System.Text;
	using System.IO;
	using System.Reflection;
	using System.Runtime.Remoting;
	using System.Runtime.InteropServices;
	using System.Diagnostics;

	using Gdk;
	using Gtk;

	public class TestDataGrid 
	{
		private DataTable table;
		private Gtk.Window win;
		private DataGrid grid;
		//private TextView textView;

		public static readonly string ApplicationName = "Gtk# DataGrid Test";	

		public TestDataGrid () 
		{
			CreateGui ();
		}

		public DataGrid Grid {
			get {
				return grid;
			}
		}

		public void Show () 
		{
			win.ShowAll ();
		}

		public void CreateGui () 
		{
			win = new Gtk.Window (ApplicationName);
			win.DeleteEvent += new Gtk.DeleteEventHandler (OnWindow_Delete);
			win.BorderWidth = 4;
			win.SetDefaultSize (600, 500);
			
			VBox vbox = new VBox (false, 4);
			win.Add (vbox);

			MenuBar mb = CreateMenuBar ();
			vbox.PackStart (mb, false, false, 0);
			
			VPaned vpaned = new VPaned ();
			vbox.PackStart (vpaned, true, true, 0);
			grid = CreateOutputResultsDataGrid();
			vpaned.Add1 (grid);
		}

		DataGrid CreateOutputResultsDataGrid () 
		{
			DataGrid grid = new DataGrid ();

			//grid.View.ButtonReleaseEvent +=
			//	new Gtk.ButtonReleaseEventHandler (OnDataGridButtonRelease);
			//grid.Editable = false;

			return grid;
		}

		void OnWindow_Delete (object o, Gtk.DeleteEventArgs args) 
		{
			QuitApplication();
		}

		void QuitApplication () 
		{
			Application.Quit ();
		}

		public static void DoEvents () 
		{
			while (Application.EventsPending ()) 
				Application.RunIteration ();
		}

		public DataTable BuildDataTableSample() 
		{
			table = new DataTable();

			int maxColumns = 5;
			int maxRows = 3;

			for(int i = 0; i < maxColumns; i++) {
				string columnName = String.Format("Column{0}", i);
				table.Columns.Add(columnName);
			}
			
			for(int r = 0; r < maxRows; r++) {
				DataRow row = table.NewRow();
				for(int c = 0; c < table.Columns.Count; c++) {
					string cellValue = String.Format("(Row{0},Column{1})", r, c);
					row[c] = cellValue;
				}
				table.Rows.Add(row);
			}

			return table;
		}

		void OnMenu_DumpTable (object o, EventArgs args) 
		{
			Console.Error.WriteLine("__===========  T a b l e     D u m p  =========__");
			Console.Error.WriteLine("Row Count: " + table.Rows.Count.ToString());
			for(int r = 0; r < table.Rows.Count; r++) {
				DataRow row = table.Rows[r];
				StringBuilder sb = new StringBuilder();
				for(int c = 0; c < table.Columns.Count; c++) {
					string s = row[c].ToString();
					sb.Append(s);
					sb.Append(" ");
				}
				Console.Error.WriteLine(sb.ToString());
			}
			Console.Error.WriteLine("=-----------------------------------------------=");
		}

		void OnMenu_Editable (object o, EventArgs args) 
		{
			grid.Editable = !grid.Editable;
		}

		void OnMenu_AddNew (object o, EventArgs args) 
		{
			AddNew();
		}

		void OnMenu_DeleteSelectedRow (object o, EventArgs args) 
		{
			int selectedRow = 0;
			selectedRow = grid.SelectedRow;
			if (selectedRow >= 0)
				grid.DeleteRow (selectedRow);
		}

		void AddNew() 
		{
			grid.AddNew();
		}

		public MenuBar CreateMenuBar () {
			MenuBar menuBar = new MenuBar ();
			Menu menu;
			MenuItem item;
			MenuItem barItem;

			menu = new Menu ();

			item = new MenuItem ("Add Row");
			item.Activated += new EventHandler (OnMenu_AddNew);
			menu.Append (item);

			item = new MenuItem ("Dump Table");
			item.Activated += new EventHandler (OnMenu_DumpTable);
			menu.Append (item);

			item = new MenuItem ("Editable");
			item.Activated += new EventHandler (OnMenu_Editable);
			menu.Append (item);

			item = new MenuItem ("Delete Selected Row");
			item.Activated += new EventHandler (OnMenu_DeleteSelectedRow);
			menu.Append (item);

			barItem = new MenuItem ("Test");
			barItem.Submenu = menu;
			menuBar.Append (barItem);

			return menuBar;
		}

		public static int Main (string[] args) 
		{
			Application.Init ();
			TestDataGrid test = new TestDataGrid ();
			DataTable sampleTable = test.BuildDataTableSample();
			test.Grid.DataSource = sampleTable;
			test.Grid.DataBind();
			test.Show ();
			DoEvents ();
			//test.Grid.Editable = false;
			Application.Run ();
			return 0;
		}
	}
}



More information about the Gtk-sharp-list mailing list