Selecting Control Text#

Last year I wrote a post on selecting text in a textbox control in two parts.  You can find Part 1 here and Part 2 here.  Another question came up in the news groups on selecting the text of a NumericUpDown control.  Again sounds straight forward since the full .NET framework supports UpDownBase.Select.  To get this functionality requires a little bit of work but is possible. 

Basically to send a message to a control you have to PInvoke SendMessage in coredll.dll (user32.dll for the desktop).  Here is the signature for that:

[DllImport("coredll.dll", SetLastError = true)]
private static extern IntPtr SendMessage(IntPtr hWnd, int msg, int wParam, int lParam);

To tell the control to select the text, the int msg parameter should be EM_SETSEL which is defined as follows:

private const int SETSEL = 0x00B1;

Now putting all together.  Using Visual Studio 2005 we can create a class called NumericUpDownWithSelect and override the OnGotFocus method.  Here is the implementation

protected override void OnGotFocus(EventArgs e)
{
     base.OnGotFocus(e);

     if (!this.suppressOnGotFocus)
     {
          ThreadStart t = delegate()
          {
               this.Invoke(new SelectAllInvoke(SelectAll));
          };
     new Thread(t).Start();
}

You will notice we are using an anonymous method to invoke the SelectAll Method on the main thread.  Here is the delegate signature and the implementation of SelectAll() and Select():

private delegate void SelectAllInvoke();
public void SelectAll()
{
     this.SelectInternal(0, this.Value.ToString().Length);
}

public void Select(int start, int length)
{
     this.SelectInternal(start, length);
}

SelectInternal() is the code that does the actual work. 

private void SelectInternal(int start, int length)
{
     this.suppressOnGotFocus = true;
     if (!this.Focused)
          this.Focus();
     IntPtr ret = SendMessage(this.Handle, SETSEL, start, length);
     this.suppressOnGotFocus = false;
}

So putting it all together in a nice class that inherits from System.Windows.Forms.NumericUpDown you can extend the functionality of the base class.  Here is the full implementation:

public class NumericUpDownWithSelect : NumericUpDown
{
     public NumericUpDownWithSelect()
     {
     }

     [DllImport("coredll.dll", SetLastError = true)]
     private static extern IntPtr SendMessage(IntPtr hWnd, int msg, int wParam, int lParam);

     private const int GETSEL = 0x00B0;
     private const int SETSEL = 0x00B1;

     private delegate void SelectAllInvoke();

     private bool suppressOnGotFocus = false;

     protected override void OnGotFocus(EventArgs e)
     {
          base.OnGotFocus(e);
          if (!this.suppressOnGotFocus)
          {
               ThreadStart t = delegate()
               {
                    this.Invoke(new SelectAllInvoke(SelectAll));
               };
               new Thread(t).Start();
          }
     }

     public void SelectAll()
     {
          this.SelectInternal(0, this.Value.ToString().Length);
     }

     public void Select(int start, int length)
     {
          this.SelectInternal(start, length);
     }

     private void SelectInternal(int start, int length)
     {
          this.suppressOnGotFocus = true;
          if (!this.Focused)
               this.Focus();
          IntPtr ret = SendMessage(this.Handle, SETSEL, start, length);
          this.suppressOnGotFocus = false;
     }
}

Download the binaries here: NumericUpDownWithSelect_Binaries.zip (3.67 KB) 


Tuesday, January 17, 2006 12:15:32 PM (Eastern Standard Time, UTC-05:00) #    Comments [8]  | 

 

Tuesday, February 21, 2006 8:52:12 AM (Eastern Standard Time, UTC-05:00)
Thank you so much for this. You just made an unsable GUI perfect!
Peter Morris
Monday, March 13, 2006 4:48:52 AM (Eastern Daylight Time, UTC-04:00)
I find your solution a bit awkward. By explicitly importing Core.dll stuff and sending messages I think the solution isn't portable. Does it work in Mono?

Since NumericUpDown already has a Select() method, why not use that one? I've created an EnhancedNumericUpDown class that adds the SelectAll() method to NumericUpDown. This method uses Select(0,Text.length) to select all text. Then I use a simple Timer to schedule a call to SelectAll() when the EnhancedNumericUpDown receives focus. I've also added a AutoSelect property that you can use to enable/disable this AutoSelect behaviour (Borland Delphi's Edit controls also have this property).

You can download my stuff here:

http://www.wirwar.com/EnhancedNumericUpDown.zip
Tuesday, March 14, 2006 3:23:36 AM (Eastern Daylight Time, UTC-04:00)
Leon, There really is nothing awkward about the solution, it adds functionality to a Compact Framework control similar to the desktop. Select() is not supported in the .NET Compact Framework 1.0 or 2.0. This control was written for Compact Framework only and not for Full .NET Framework or Mono.
Tuesday, March 14, 2006 4:10:52 AM (Eastern Daylight Time, UTC-04:00)
Oh, I see. I didn't realise you were talking about the Compact Framework :-) I just Googled for "NumericUpDown SelectAll" and found your page.
Saturday, November 18, 2006 4:27:45 AM (Eastern Standard Time, UTC-05:00)
A workaround for this may be to simply place a textbox over the text portion of the NumericUpDown control (it vusually appears to simply be a numericupdown control). Then progmatically set the numericupdown.valuechanged event to change the value of the overlaid textbox. Also set the textbox.valuechanged event to change the value of the numericupdown.text value. Kind of a wierd way of doing it, but I had to do it because I don't know J#, just Visual Basic. I don't want to take the time to translate the above code into Visual Basic.
-Corey
Wednesday, November 22, 2006 7:37:32 AM (Eastern Standard Time, UTC-05:00)
Thanks for this code Mark. It is concise, elegant and effective. As well as solving my immediate problem, it teaches me a new way to approach this kind of issue.

Keep up the great work.

Many thanks,
StonePiano
Monday, October 22, 2007 9:49:42 AM (Eastern Daylight Time, UTC-04:00)
Great code, Thanks a lot!! :)
Fran
Wednesday, March 19, 2008 7:45:13 PM (Eastern Daylight Time, UTC-04:00)
if u need the VB .NET code here it is


Imports System.Runtime.InteropServices
Imports System.Threading

Public Class NumericUpDownWithSelect
Inherits NumericUpDown
Public Sub NumericUpDownWithSelect()

End Sub

<DllImport("coredll.dll", SetLastError:=True)> _
Private Shared Function SendMessage(ByVal hWnd As IntPtr, ByVal msg As Integer, ByVal wParam As Integer, ByVal lParam As Integer) As IntPtr
End Function

Private Const GETSEL As Integer = 176
Private Const SETSEL As Integer = 177

Private Delegate Sub SelectAllInvoke()

Private suppressOnGotFocus As Boolean = False

Private Sub SelectInternal(ByVal start As Integer, ByVal length As Integer)
Me.suppressOnGotFocus = True
If Not (Me.Focused) Then
Me.Focus()
End If
Dim ret As IntPtr = SendMessage(Me.Handle, SETSEL, start, length)
Me.suppressOnGotFocus = False
End Sub

Public Sub SelectAll()
Me.SelectInternal(0, Me.Value.ToString().Length)
End Sub

Public Sub [Select](ByVal start As Integer, ByVal length As Integer)
Me.SelectInternal(start, length)
End Sub

Protected Overloads Overrides Sub OnGotFocus(ByVal e As EventArgs)
Me.OnGotFocus(e)
If Not Me.suppressOnGotFocus Then

Dim t As New Thread(AddressOf NumericUpDownWithSelect)
Me.Invoke(New SelectAllInvoke(AddressOf SelectAll))
t.Start()
End If
End Sub
End Class
Comments are closed.
All content © 2010, Mark Arteaga
On this page
Related Sites
Archives
Sitemap
Disclaimer

Powered by: newtelligence dasBlog 1.9.7174.0

The opinions expressed herein are my own personal opinions and do not represent my employer's view in anyway.

Send mail to the author(s) E-mail

Theme design by Jelle Druyts