Why don't you write a custom TreeModel? I have written one for
DataTables and am testing another one for DataViews(attached, to display
data tables pass the default view of the table: table.DefaultView).
Forget about storing data at two locations in the memory, this will only
cause trouble and performance issues :-)
A good tutorial is available at
http://www.mono-project.com/ImplementingGInterfaces. Hoewever,
GInterface implementation was introduced in Gtk# 2.12 so you might need
to update your installation.
So the question is... in your opinion what is the best way to save the
values from a TreeStore in a database and retrieve them again through
SQL and maintain the intended parent/child relationship.
This maybe simple and I just missed it.
Thanks for your help
Andy
_______________________________________________
Gtk-sharp-list maillist - Gtk-sharp-list@lists.ximian.com
http://lists.ximian.com/mailman/listinfo/gtk-sharp-list
// DataViewStore.cs
//
// Copyright (C) 2008 Christian Hoff
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
namespace Bestandsverwaltung.DataWidgets.DataTable
{
public class DataViewStore : GLib.Object, Gtk.TreeModelImplementor
{
public DataViewStore (System.Data.DataView DataView)
{
if (DataView == null)
throw (new System.ArgumentNullException ("DataView"));
_dataView = DataView;
_dataView.ListChanged += this.DataView_ListChanged;
// Create a random stamp for the iters
System.Random RandomStampGen = new System.Random ();
this.Stamp = RandomStampGen.Next (System.Int32.MinValue, System.Int32.MaxValue);
_adapter = new Gtk.TreeModelAdapter (this);
}
// Properties
public readonly int Stamp;
private System.Data.DataView _dataView;
public System.Data.DataView DataView
{
get {
return _dataView;
}
}
private Gtk.TreeModelAdapter _adapter;
public Gtk.TreeModelAdapter Adapter
{
get {
return _adapter;
}
}
public Gtk.TreeModelFlags Flags
{
get {
return Gtk.TreeModelFlags.ListOnly | Gtk.TreeModelFlags.ItersPersist;
}
}
public int NColumns
{
get {
return _dataView.Table.Columns.Count;
}
}
// Methods
#region Gtk.TreeIter handling
private System.Collections.Generic.List<System.Runtime.InteropServices.GCHandle> _rowHandles = new System.Collections.Generic.List<System.Runtime.InteropServices.GCHandle> ();
public override void Dispose ()
{
// Free all the GCHandles pointing to the iters since they won't be garbage collected
foreach (System.Runtime.InteropServices.GCHandle handle in _rowHandles)
handle.Free ();
base.Dispose ();
}
public Gtk.TreeIter IterFromRow (System.Data.DataRowView row)
{
Gtk.TreeIter result = Gtk.TreeIter.Zero;
IterFromRow (row, ref result);
return result;
}
private void IterFromRow (System.Data.DataRowView row, ref Gtk.TreeIter iter)
{
System.Runtime.InteropServices.GCHandle gch = System.Runtime.InteropServices.GCHandle.Alloc (row);
iter.UserData = (System.IntPtr) gch;
iter.Stamp = this.Stamp;
_rowHandles.Add (gch);
}
public System.Data.DataRowView RowFromIter (Gtk.TreeIter iter)
{
if (iter.Stamp != this.Stamp)
throw (new System.InvalidOperationException (System.String.Format ("iter belongs to a different model; it's stamp is not equal to the stamp of this model({0})", this.Stamp.ToString ())));
if (iter.UserData == System.IntPtr.Zero)
throw (new System.InvalidOperationException ("iter does not contain any row information"));
System.Runtime.InteropServices.GCHandle gch = (System.Runtime.InteropServices.GCHandle) iter.UserData;
return gch.Target as System.Data.DataRowView;
}
#endregion
#region TreePath handling
public Gtk.TreePath GetPath (Gtk.TreeIter iter)
{
return PathFromRow (RowFromIter (iter));
}
public Gtk.TreePath PathFromRow (System.Data.DataRowView row)
{
System.Int32 index = IndexFromRow (row);
if (index == -1)
return null;
Gtk.TreePath path = new Gtk.TreePath ();
path.AppendIndex (index);
return path;
}
public int IndexFromRow (System.Data.DataRowView row)
{
// Let's see how this works, but this should return the expected results
// If it does, I'm the first to find this solution(I have googled hours in the web and found nothing)
return (_dataView as System.Collections.IList).IndexOf (row);
}
public bool GetIter (out Gtk.TreeIter iter, Gtk.TreePath path)
{
iter = Gtk.TreeIter.Zero;
if (path.Indices.Length != 1)
return false;
int index = path.Indices [0];
if (index >= _dataView.Count)
return false;
IterFromRow (_dataView [index], ref iter);
return true;
}
#endregion
#region get/set model data
/* NOTE: Do not use this method from managed code. The reconversion into a System.type will fail for any non-primitive data types
* Use GetColumnSystemType instead
*/
public GLib.GType GetColumnType (int column)
{
return (GLib.GType) GetColumnSystemType (column);
}
public System.Type GetColumnSystemType (int column)
{
return _dataView.Table.Columns [column].DataType;
}
public void GetValue (Gtk.TreeIter iter, int column, ref GLib.Value val)
{
val.Init (GetColumnType (column));
val.Val = GetValue (iter, column);
}
public System.Object GetValue (Gtk.TreeIter iter, int column)
{
return RowFromIter (iter) [column];
}
public void SetValue (Gtk.TreeIter iter, int column, object val)
{
RowFromIter (iter) [column] = val;
}
#endregion
public System.Boolean GetIterFirst (out Gtk.TreeIter iter)
{
if (_dataView.Count == 0) {
iter = Gtk.TreeIter.Zero;
return false;
} else {
iter = IterFromRow (_dataView [0]);
return true;
}
}
public bool IterNext (ref Gtk.TreeIter iter)
{
int NewIndex = IndexFromRow (RowFromIter (iter)) + 1;
if (NewIndex >= _dataView.Count)
return false;
IterFromRow (_dataView [NewIndex], ref iter);
return true;
}
public int IterNChildren (Gtk.TreeIter iter)
{
// List-only model
if (iter.UserData == System.IntPtr.Zero)
return _dataView.Count;
else
return 0;
}
public bool IterHasChild (Gtk.TreeIter iter)
{
return IterNChildren (iter) != 0;
}
public bool IterNthChild (out Gtk.TreeIter child, Gtk.TreeIter parent, int index)
{
if (parent.UserData == System.IntPtr.Zero) {
child = IterFromRow (_dataView [index]);
return true;
} else {
// List-only model
child = Gtk.TreeIter.Zero;
return false;
}
}
// child: first child iter of parent
public System.Boolean IterChildren (out Gtk.TreeIter child, Gtk.TreeIter parent)
{
if (parent.UserData == System.IntPtr.Zero)
return GetIterFirst (out child);
child = Gtk.TreeIter.Zero;
return false;
}
public System.Boolean IterParent (out Gtk.TreeIter parent, Gtk.TreeIter child)
{
// List-only model
parent = Gtk.TreeIter.Zero;
return false;
}
public void RefNode (Gtk.TreeIter iter)
{
}
public void UnrefNode (Gtk.TreeIter iter)
{
}
// Event handling
private void DataView_ListChanged (System.Object o, System.ComponentModel.ListChangedEventArgs e)
{
switch (e.ListChangedType) {
case System.ComponentModel.ListChangedType.ItemAdded:
_adapter.EmitRowInserted (new Gtk.TreePath (new int[1] {e.NewIndex}), IterFromRow (_dataView [e.NewIndex]));
break;
case System.ComponentModel.ListChangedType.ItemDeleted:
_adapter.EmitRowDeleted (new Gtk.TreePath (new int[1] {e.OldIndex}));
break;
case System.ComponentModel.ListChangedType.ItemChanged:
_adapter.EmitRowChanged (new Gtk.TreePath (new int[1] {e.NewIndex}), IterFromRow (_dataView [e.NewIndex]));
break;
case System.ComponentModel.ListChangedType.ItemMoved:
// TODO: File a Gtk# bug report (why is the integer array an out param????)
_adapter.EmitRowsReordered (null, Gtk.TreeIter.Zero);
break;
case System.ComponentModel.ListChangedType.Reset:
throw (new System.NotImplementedException ());
}
}
}
}
_______________________________________________
Gtk-sharp-list maillist - Gtk-sharp-list@lists.ximian.com
http://lists.ximian.com/mailman/listinfo/gtk-sharp-list