如何在C#中的TreeView中捕获选定的列索引

时间:2014-09-20 13:19:15

标签: c# treeview gtk

我正在使用Mono和Gtk开发一个C#api,并且我在尝试使我的treeView单元格可编辑时遇到了麻烦。我在此找到了几个代码片段,但问题是所提供的解决方案都不允许编辑所有列。

这是我的功能

public void cellEdited (object o, Gtk.EditedArgs args)
    {
        TreePath path = new TreePath (args.Path);
        TreeIter iter;

        listStore.GetIter (out iter, path);
        int numberOfSelectedRow_ = path.Indices[0];
        listStore.SetValue (iter, COLUMN_NUMBER, args.NewText);
    }

问题是我无法弄清楚如何捕获所选单元格的列号。 我读过this article说我们应该使用gtk.TreeView.get_path_at_pos,但我真的不明白究竟是怎么回事。任何代码片段都会非常感激!!!谢谢大家 !

1 个答案:

答案 0 :(得分:0)

我遇到同样的问题,但找到了一个解决方案(以及其他一些问题)。 首先,我们必须对编辑发送者对象进行排队,因为取消编辑过程是不同的视图。第二个方法是无法获得有关单个单元格或列的任何信息,但您可以将needet信息存储在派生类中。

using System;
using Gtk;
using System.Windows.Forms;
using System.Xml.Linq;
using System.Xml;
using System.Collections.Generic;
using System.Collections;
using System.Data.Linq;
using System.Linq;

namespace TestWinForms
{
    /// <summary>
    /// New cell renterer text. derived from Gtk.CellRendererText
    /// this was neccessary to host the column Index and a Name
    /// ( in this sample  the Attribute name, you can also define 
    ///   an oibject a dataRow or a XElement ... to use it directly.)
    /// </summary>
    public class NewCellRentererText : CellRendererText
    {
        public int ColumnIndex{ get; set;}
        public string XmlAttributeName{ get; set;}
    }
    /// <summary>
    /// Main class.
    /// </summary>
    public class MainClass
    {
        /// <summary>Loaded XElement to show, edit and store </summary>
        private XElement MainXMLElement ;
        /// <summary>TreeStore used in several methodes</summary>
        private Gtk.TreeStore musicListStore;
        /// <summary>
        /// The editing queue.to find the correct Row that have been edited this is neccessary
        /// because the c# Integration of Gtk2 seems to be not thread safe
        /// </summary>
        private Queue<object> EditingQueue = new Queue<object>();

        /// <summary>
        /// The X element indexer.
        /// host for all editable XElements in the Tree
        /// using UserData results in an horrible Mix from managed and unmanaged code
        /// this way is clean safe.
        /// 
        /// An other solution will be to store the datareferences in an additional
        /// Property of NewCellRentererText 
        /// 
        /// </summary>
        public Dictionary<TreeIter,XElement> XElementIndexer = new Dictionary<TreeIter, XElement> ();

        /// <summary>
        /// Gets or sets the dynamic tree filter reg ex.
        /// for filtering , this was only experimental, but it works fine. 
        /// So if it is needed ....
        /// </summary>
        /// <value>The dynamic tree filter reg ex.</value>
        public System.Text.RegularExpressions.Regex DynamicTreeFilterRegEx { get; set;} 
        /// <summary>
        /// Gets or sets the dynamic tree filter column.
        /// for filtering , this was only experimental, but it works fine. 
        /// So if it is needed ....
        /// </summary>
        /// <value>The dynamic tree filter column.</value>
        public Int32 DynamicTreeFilterColumn { get; set; }

        /// <summary>
        /// The entry point of the program, where the program control starts and ends.
        /// </summary>
        /// <param name="args">The command-line arguments.</param>
        public static void Main (string[] args)
        {
            Gtk.Application.Init ();
            new MainClass ();
            Gtk.Application.Run ();

        }
        /// <summary>
        /// Handles the window destroyed_callback event.
        /// safe my work :-)
        /// </summary>
        /// <param name="o">O.</param>
        /// <param name="args">Arguments.</param>
        public void On_WindowDestroyed_callback(object o, EventArgs args)
        {
            MainXMLElement.Save(System.IO.Path.Combine("Properties","ProcessOut.xml"));
        }
        /// <summary>
        /// Handles the editing canceled_callback event.
        /// </summary>
        /// <param name="o">O.</param>
        /// <param name="args">Arguments.</param>
        public void On_EditingCanceled_callback(object o, EventArgs args)
        {
            EditingQueue.Dequeue();
        }

        /// <summary>
        /// Handles the editing started_callback event.
        /// </summary>
        /// <param name="o">O.</param>
        /// <param name="args">Arguments.</param>
        public void On_EditingStarted_callback(object o, EditingStartedArgs args)
        {
            EditingQueue.Enqueue (o);
        }

        /// <summary>
        /// Handles the edited_callback event.
        /// </summary>
        /// <param name="o">O.</param>
        /// <param name="args">Arguments.</param>
        public void On_Edited_callback(object o, EditedArgs args)
        {
            object quedObject = EditingQueue.Dequeue ();
            NewCellRentererText ncrt = quedObject as NewCellRentererText;
            if (null == ncrt)
                return;

            TreeIter iter;
            TreePath path = new TreePath (args.Path);
            if (!musicListStore.GetIter (out iter, path))
                return;

            XElement dummy = XElementIndexer [iter];  
            if (dummy.Attribute (ncrt.XmlAttributeName) != null)
                dummy.SetAttributeValue (ncrt.XmlAttributeName, args.NewText);
            else
                foreach (string attrKvp in args.NewText.Split(";".ToCharArray())) {
                    String[] attribute = attrKvp.Split (":".ToCharArray ());
                    if (attribute.Length > 1) // && dummy.Attribute (attribute [0].Trim ()) != null)
                        dummy.SetAttributeValue (attribute [0].Trim (), attribute [1].Trim ());
                }
            musicListStore.SetValue (iter, ncrt.ColumnIndex, args.NewText);
            ((NewCellRentererText)o).Text = args.NewText;
        }

        /// <summary>
        /// Creates the new column.
        /// set/reset the editable property
        /// ans set name and Column Index in a new instance
        /// of the new derived CellRendererText class 
        /// </summary>
        /// <returns>The new column.</returns>
        /// <param name="index">Index.</param>
        /// <param name="name">Name.</param>
        /// <param name="editable">If set to <c>true</c> editable.</param>
        private Gtk.TreeViewColumn CreateNewColumn(int index, string name, bool editable)
        {
            NewCellRentererText renderer = new NewCellRentererText ();
            renderer.ColumnIndex =index ;
            renderer.XmlAttributeName=name;
            renderer.Editable = editable;
            if (editable) {
                renderer.Edited += On_Edited_callback;
                renderer.EditingStarted += On_EditingStarted_callback;
                renderer.EditingCanceled += On_EditingCanceled_callback;
            }
            Gtk.TreeViewColumn ret = new Gtk.TreeViewColumn (renderer.XmlAttributeName, renderer);
            ret.AddAttribute (ret.CellRenderers [0], "text", index);
            return ret;
        }
        /// <summary>
        /// Initializes a new instance of the <see cref="TestWinForms.MainClass"/> class.
        /// </summary>
        public MainClass ()
        {
            // using Styles ( OPTIONAL EXPERIMENTAL BUT WORKING ) 
            Gtk.Rc.Parse (System.IO.Path.Combine("Properties","ProcessOut.xml"));

            // Normal stuff to create a tree view
            Gtk.Window window = new Gtk.Window ("TreeView Example");
            window.SetSizeRequest (800, 600);
            window.Destroyed += On_WindowDestroyed_callback;

            Gtk.TreeView tree = new Gtk.TreeView ();
            window.Add (tree);

            // one Part of the Solution to host column index
            tree.AppendColumn (CreateNewColumn(0, "name", false));
            tree.AppendColumn (CreateNewColumn(1, "id", false));
            tree.AppendColumn (CreateNewColumn(2, "type", true));
            tree.AppendColumn (CreateNewColumn(3, "class", true));
            tree.AppendColumn (CreateNewColumn(4, "parameter", true));
            tree.AppendColumn (CreateNewColumn(5, "others", true));
            Type[] TypeList = Enumerable.Repeat (typeof(string), tree.Columns.Length).ToArray();
                musicListStore = new Gtk.TreeStore (TypeList);

            // some XML stuff to make something usefull
            MainXMLElement = XElement.Load ("Properties/Process.xml",LoadOptions.PreserveWhitespace);
            XElement y = MainXMLElement.Element ("processes");
            XAttribute title = y.Attribute ("name");
            TreeIter iter =  musicListStore.AppendValues(title == null ? y.Name.ToString() : title.Value);
            XElementIndexer.Add (iter, y);

            walkThroughXml (y, musicListStore, iter);

            // using row filter  ( OPTIONAL EXPERIMENTAL BUT WORKING ) 
            Gtk.TreeModelFilter filter = new Gtk.TreeModelFilter (musicListStore, null);
            filter.VisibleFunc = new Gtk.TreeModelFilterVisibleFunc (FilterTree);

            tree.Model = filter;

            // Now let us see
            window.ShowAll ();
        }
        /// <summary>
        /// Walks the through xml.
        /// recursive TreView filling based on an XML Element
        /// </summary>
        /// <param name="xe">Xe.</param>
        /// <param name="ts">Ts.</param>
        /// <param name="ti">Ti.</param>
        public void walkThroughXml(XElement xe, Gtk.TreeStore ts, Gtk.TreeIter ti )
        {
            if (!xe.HasElements)
                return;
            IEnumerable<XElement> elements = xe.Elements ();
            foreach ( XElement element in elements )
            {
                // this part could be more generic, but it works for my requirements
                String Xid = "";
                String Xtype = "";
                String Xclass = "";
                String Xparameter = "";

                System.Text.StringBuilder dataExpression = new System.Text.StringBuilder();
                XAttribute title = element.Attribute ("name");
                foreach (XAttribute data in element.Attributes()) {
                    switch (data.Name.ToString ()) {
                    case "name":
                        break;
                    case "id":
                        Xid = data.Value;
                        break;
                    case "type":
                        Xtype = data.Value;
                        break;
                    case "class":
                        Xclass = data.Value;
                        break;
                    case "parameter":
                        Xparameter = data.Value;
                        break;
                    default:
                        dataExpression.AppendFormat ("{0}: {1} ; ", data.Name.ToString (), data.Value);
                        break;
                    }
                }
                TreeIter iter = (TreeIter)ts.AppendValues (ti, title == null ? element.Name.ToString () : title.Value, Xid,Xtype,Xclass,Xparameter, dataExpression.ToString ());
                walkThroughXml (element, ts, iter);
                XElementIndexer.Add (iter,element);
            }
        }
        /// <summary>
        /// Filters the tree.       
        ///
        /// for filtering , this was only experimental, but it works fine. 
        /// So if it is needed ....
        ///
        /// </summary>
        /// <returns><c>true</c>, if tree was filtered, <c>false</c> otherwise.</returns>
        /// <param name="model">Model.</param>
        /// <param name="iter">Iter.</param>
        private bool FilterTree (Gtk.TreeModel model, Gtk.TreeIter iter)
        {
            if (DynamicTreeFilterRegEx == null)
                return true;
            string searchName = model.GetValue (iter, DynamicTreeFilterColumn).ToString ();
            return DynamicTreeFilterRegEx.IsMatch (searchName);
        }

    }
}

这里是测试XML文件

<?xml version="1.0" encoding="UTF-8" ?>
<document>
    <enums>
    </enums>
    <processes>
        <process name="main" id="p1" positionmeasurement="milliseconds" speed="4100" processlength="10000" maxitems="255" mingap="5">
            <actuators>
                <actuator name="actuator1" id="p1pa1" type="sensor" class="" parameter="" position="100" window="220" />
                <actuator name="actuator2" id="p1pa2" type="sensor" class="" parameter=""  position="1050" window="220" />
                <actuator name="actuator3" id="p1pa3" type="receiver" class="" parameter=""  position="9100" window="220" />
            </actuators>
            <processsteps>
                <processstep name="step1" id="p1ps0" type="runningstate" class="" parameter="" order="1" retriggerable="true" />                
                <processstep name="step1" id="p1ps1" type="sync" class="" parameter="" order="2" retriggerable="false" />
                <processstep name="step2" id="p1ps2" type="async" class="" parameter="" order="3" retriggerable="true" />
                <processstep name="step3" id="p1ps3" type="timed" position="25000" window="1200" class="" parameter="" order="4" retriggerable="false" />
            </processsteps>
            <triggers>
                <trigger name="trigger1" id="p1pt1" sourceid="p1pa2" sourcestate="start" targetid="p1ps2" triggertype="start" />
                <trigger name="trigger2" id="p1pt2" sourceid="p1pa2" sourcestate="error" targetid="p1ps2" triggertype="stop" />
                <trigger name="trigger3" id="p1pt3" sourceid="p1pa3" sourcestate="end" targetid="p1ps3" triggertype="start" />
            </triggers>
            <assertations>
                <assertation name="assertation1" id="p1pas1" type="itemstate" rule="text" class="" parameter="" />
                <assertation name="assertation2" id="p1pas2" type="itemstate" rule="text" class="" parameter="" />
                <assertation name="assertation3" id="p1pas3" type="itemstate" rule="text" class="" parameter="" />
            </assertations>
            <exceptions>
                <exception name="exception1" id="p1pex1" retriggerable="false">
                    <conditions logic="and">
                        <condition name="contition1" id="p1pex1c1" class="" paramter="" type="PLC" message="2001" /> 
                        <condition name="contition2" id="p1pex1c2" class="" paramter="" type="PLC" message="2005" /> 
                    </conditions>
                    <actions>
                        <action name="action1" id="p1pex1pac1" class="" parameter="" actiontype="stopfeeder" type="asynchron" order="1" />
                        <action name="action1" id="p1pex1pac1" class="" parameter="" actiontype="flushallitem" type="synchron" timeout="5000" order="2" />
                        <action name="action2" id="p1pex1pac2" class="" parameter="" actiontype="rundown" type="synchron" timeout="5000" order="3" />
                    </actions>
                </exception>
            </exceptions>
        </process>
        <process name="sub" id="p2">
        </process>
        <process name="sub2" id="p3">
            <actuators>
                <actuator name="actuator1" id="p3pa1" type="sensor" class="" parameter="" />
                <actuator name="actuator2" id="p3pa2" type="sensor" class="" parameter="" />
                <actuator name="actuator3" id="p3pa3" type="receiver" class="" parameter="" />
            </actuators>
            <processsteps>
                <processstep name="step1" id="p3ps0" type="runningstate" class="" parameter="" />               
                <processstep name="step1" id="p3ps1" type="sync" class="" parameter="" />
                <processstep name="step2" id="p3ps2" type="async" class="" parameter="" />
                <processstep name="step3" id="p3ps3" type="timed" processtime="25000" window="1200" class="" parameter="" />
            </processsteps>
            <triggers>
                <trigger name="trigger1" id="p3pt1" sourceid="p3pa2" sourcestate="start" targetid="p3ps2" triggertype="start" />
                <trigger name="trigger2" id="p3pt2" sourceid="p3pa2" sourcestate="error" targetid="p3ps2" triggertype="stop" />
                <trigger name="trigger3" id="p3pt3" sourceid="p3pa3" sourcestate="end" targetid="p3ps3" triggertype="start" />
            </triggers>
            <assertations>
                <assertation name="assertation1" id="p3pas1" type="itemstate" rule="text" class="" parameter="" />
                <assertation name="assertation2" id="p3pas2" type="itemstate" rule="text" class="" parameter="" />
                <assertation name="assertation3" id="p3pas3" type="itemstate" rule="text" class="" parameter="" />
            </assertations>
        </process>
    </processes>

</document>

将其保存在属性文件夹中并检查以复制

相关问题