Visual Studio has this very nice "solution explorer", which I assume is some form of TreeView. When you rename files, it selects the file name only and not the extension.
However, treeviews don't seem to expose methods for selecting only parts of the text. When you treeview.BeginEdit()
, it selects all of the text.
Is there a way to select just parts of the text in the node when it begins edit?
Create a custom TreeView
and intercept the notification messages that the parent window of the control sends them back to it through the WM_REFLECT + WM_NOTIFY
messages. The LParam
property holds a handle to NMHDR
structure that contains information about the notification message. We are interested here in TVN_BEGINLABELEDITW
notifications to get a handle to the edit control by sending TVM_GETEDITCONTROL
message and using the handle returned to lastly send EM_SETSEL
message to set the selection range.
[DesignerCategory("Code")]
public class TreeViewEx : TreeView
{
protected override void WndProc(ref Message m)
{
base.WndProc(ref m);
if (m.Msg == WM_REFLECT_NOTIFY)
{
var st = Marshal.PtrToStructure<NMHDR>(m.LParam);
if (st.code == TVN_BEGINLABELEDITW)
{
IntPtr editPtr = SendMessage(Handle, TVM_GETEDITCONTROL, IntPtr.Zero, IntPtr.Zero);
if (editPtr != IntPtr.Zero)
{
int selStart = 0;
int selEnd = Path.GetFileNameWithoutExtension(SelectedNode.Text).Length;
SendMessage(editPtr, EM_SETSEL, (IntPtr)selStart, (IntPtr)selEnd);
}
}
}
}
const int WM_REFLECT_NOTIFY = 0x204E;
const int TVM_GETEDITCONTROL = 0x0000110F;
const int TVN_BEGINLABELEDITW = 0 - 400 - 59;
const int EM_SETSEL = 0xB1;
[StructLayout(LayoutKind.Sequential)]
struct NMHDR
{
public IntPtr hwndFrom;
public IntPtr idFrom;
public int code;
}
[DllImport("user32.dll", CharSet = CharSet.Auto)]
static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wp, IntPtr lp);
}