Download CustomTreeViewLabelEdit.zip, last updated 28/10/2013 (16.32 KB)

Download
  • md5: 80ba715b3ff9cc64851d7914f54af397
using System;
using System.ComponentModel;
using System.Windows.Forms;

namespace CustomTreeViewLabelEdit
{
  internal class TreeViewExNotify : TreeView
  {
    // Specifying custom text when using the LabelEdit functionality of a TreeView
    // http://cyotek.com/blog/specifying-custom-text-when-using-the-labeledit-functionality-of-a-treeview

    #region Events

    [Category("Behavior")]
    public event EventHandler<NodeRequestTextEventArgs> RequestEditText;

    #endregion

    #region Overridden Members

    protected override void WndProc(ref Message m)
    {
      /*
       * Technically, the WM_NOTIFY message for the treeview is sent to the 
       * window that owns the treeview. My first test was using a custom 
       * NativeWindow class bound to the parent window using OnParentChanged. 
       * However, then I discovered that a solution called Message Reflection 
       * was introduced with Windows 95 which forwarded these messages to the 
       * destination window as well by combining the WM_REFLECT message with 
       * the original message. This was a lot simpler to use than having a 
       * subclassed NativeWindow and so far it seems to work, so I went with 
       * that. However, as this is a MFC  library I'm not really sure if it 
       * will work in all situations.
       * 
       * More information on message reflection: 
       * http://msdn.microsoft.com/en-us/library/eeah46xd.aspx
       */
      if (m.Msg == (NativeMethods.WM_REFLECT + NativeMethods.WM_NOTIFY))
      {
        NativeMethods.NMHDR notifyMessageHeader;

        notifyMessageHeader = (NativeMethods.NMHDR)m.GetLParam(typeof(NativeMethods.NMHDR)); // The NMHDR contains details on the notification event

        if (notifyMessageHeader.hwndFrom == this.Handle) // Sanity check just in case we get a WM_NOTIFY message for some other window
        {
          switch (notifyMessageHeader.code)
          {
            case NativeMethods.TVN_BEGINLABELEDIT: // The TreeView is about to begin a label edit operation. You can still use OnBeforeLabelEdit to cancel the edit even after we initialize the edit field here
              TreeNode treeNode;
              IntPtr editHandle;
              NodeRequestTextEventArgs e;

              treeNode = this.SelectedNode;
              editHandle = NativeMethods.SendMessage(this.Handle, NativeMethods.TVM_GETEDITCONTROL, IntPtr.Zero, IntPtr.Zero); // Get the handle of the EDIT control
              e = new NodeRequestTextEventArgs(treeNode, treeNode.Text);

              this.OnRequestEditText(e);

              NativeMethods.SendMessage(editHandle, NativeMethods.WM_SETTEXT, IntPtr.Zero, e.Label); // And apply the text. Simples.

              break;
          }
        }
      }

      base.WndProc(ref m);
    }

    #endregion

    #region Members

    protected virtual void OnRequestEditText(NodeRequestTextEventArgs e)
    {
      EventHandler<NodeRequestTextEventArgs> handler;

      handler = this.RequestEditText;

      if (handler != null)
        handler(this, e);
    }

    #endregion
  }
}

Donate

Donate