Connecting Tech Pros Worldwide Forums | Help | Site Map

C# - WinForms: Extended TextBox won't undo after paste

Newbie
 
Join Date: Jun 2009
Posts: 3
#1: Jun 12 '09
I am using: C#, .Net, Windows Forms

I have created a derived class from the System.Windows.Forms.TextBox class that only allows hexadecimal characters to be entered, whether typed or pasted. (pasting just strips out all non-hex characters). It works fine except for the fact that I can't undo after pasting into the box. I feel this must have something to do with the fact that I took over WindProc for the WM_PASTE message, but I'm not sure what I'm supposed to insure that undo works with my altered paste.

Expand|Select|Wrap|Line Numbers
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Windows.Forms;
  6. using System.Text.RegularExpressions;
  7.  
  8. class HexTextBox : TextBox {[indent]
  9.     private const int WM_PASTE = 0x302;
  10.  
  11.     public HexTextBox()
  12.         base() {
  13.         this.KeyPress += new KeyPressEventHandler(KeyPressHandler);
  14.     }
  15.  
  16.     protected override void WndProc(ref Message m) {
  17.         switch (m.Msg) {
  18.         case WM_PASTE:
  19.                 OnPaste();
  20.                 break;
  21.             default:
  22.                 base.WndProc(ref m);
  23.                 break;
  24.         }
  25.     }
  26.  
  27.     protected virtual void OnPaste() {
  28.         string text = Clipboard.GetText();
  29.         if (text != null) {
  30.             text = StripNonHex(text);
  31.             InsertText(text);
  32.         }
  33.     }
  34.  
  35.     protected virtual string StripNonHex(string text) {
  36.         return Regex.Replace(text, @"[^0-9a-fA-F]+", "").ToUpper();
  37.     }
  38.  
  39.     protected virtual void InsertText(string newtext) {
  40.         int start = this.SelectionStart;
  41.         string oldtext = this.Text;
  42.  
  43.         int end = start + this.SelectionLength;
  44.         int caretpos = start + newtext.Length;
  45.  
  46.         this.Text = oldtext.Substring(0, start) + newtext + oldtext.Substring(end, oldtext.Length - end);
  47.  
  48.         this.SelectionStart = caretpos;
  49.     }
  50.  
  51.     protected void KeyPressHandler(object sender, KeyPressEventArgs e) {
  52.         int key = (int) char.ToUpper(e.KeyChar);
  53.         if (char.IsDigit(e.KeyChar) || char.IsControl(e.KeyChar)) {
  54.             e.Handled = false;
  55.         } else if ((key > 64) && (key < 71)) { // A(65) to F(70)
  56.             e.KeyChar = (char) key;
  57.             e.Handled = false;
  58.         } else {
  59.             e.Handled = true;
  60.         }
  61.     }
  62. }

Any help would be appreciated as I'd like to make a good robust hex-editing textbox with more features for my project, but undo is a must.

tlhintoq's Avatar
Moderator
 
Join Date: Mar 2008
Location: Arizona, USA
Posts: 2,307
#2: Jun 13 '09

re: C# - WinForms: Extended TextBox won't undo after paste


I commend how much time you must have spent formatting that inside a set of [quote] tags, using a bunch of[indent] tags and all but... If you just copy/paste from Visual Studio and wrap it with [code] tags it will save you a lot of work.

TIP: When you are writing your question, there is a button on the tool bar that wraps the [code] tags around your copy/pasted code. It helps a bunch. Its the button with a '#' on it. More on tags. They're cool. Check'em out.
tlhintoq's Avatar
Moderator
 
Join Date: Mar 2008
Location: Arizona, USA
Posts: 2,307
#3: Jun 13 '09

re: C# - WinForms: Extended TextBox won't undo after paste


Quote:
I feel this must have something to do with the fact that I took over WindProc for the WM_PASTE message,
If you think that is what broke it... don't do it that way. As anyone who has read my cookbook can tell you: There is more than one way to skin a cat.

Is there a reason you can't just use the TextChanged event instead of the more elaborate scheme of taking over windows messaging? When the text is changed (any press or paste) parse the text.
Newbie
 
Join Date: Jun 2009
Posts: 3
#4: Jun 15 '09

re: C# - WinForms: Extended TextBox won't undo after paste


Quote:

Originally Posted by tlhintoq View Post

Is there a reason you can't just use the TextChanged event instead of the more elaborate scheme of taking over windows messaging?

Because I'm an idiot :P
But anyways, I tried it with the TextChanged event and I'm still hitting the same problem: If I change the .Text property, undo doesn't work, although it functions just fine if user only tries to insert valid characters, but that's the whole point of this control.

Expand|Select|Wrap|Line Numbers
  1. class HexTextBox : TextBox {
  2.  
  3.     private static Regex nonhex = new Regex(@"[^0-9a-fA-F]+");
  4.  
  5.     public HexTextBox()
  6.         : base() {
  7.         this.TextChanged += new EventHandler(TextChangedHandler);
  8.     }
  9.  
  10.     protected void TextChangedHandler(object sender, EventArgs e) {
  11.         int caret = this.SelectionStart - this.Text.Length;
  12.         this.Text = nonhex.Replace(this.Text, "").ToUpper();
  13.         this.SelectionStart = caret + this.Text.Length;
  14.     }
  15. }
  16.  
Also, Thanks!
tlhintoq's Avatar
Moderator
 
Join Date: Mar 2008
Location: Arizona, USA
Posts: 2,307
#5: Jun 16 '09

re: C# - WinForms: Extended TextBox won't undo after paste


Here's what I did to test this..
  • New windows form project
  • Drag a text box
  • Gave it a handler for text change from the properties pallet | Events tab
  • Pasted in your event handler code
  • Adjusted the variable name references to match my project, but logic remains the same.
Expand|Select|Wrap|Line Numbers
  1. using System;
  2. using System.Collections.Generic;
  3. using System.ComponentModel;
  4. using System.Data;
  5. using System.Drawing;
  6. using System.Linq;
  7. using System.Text;
  8. using System.Windows.Forms;
  9. using System.Text.RegularExpressions;
  10.  
  11. namespace Testing
  12. {
  13.     public partial class Form1 : Form
  14.     {
  15.         private static Regex nonhex = new Regex(@"[^0-9a-fA-F]+");
  16.         public Form1()
  17.         {
  18.             InitializeComponent();
  19.         }
  20.  
  21.         private void textBox1_TextChanged(object sender, EventArgs e)
  22.         {
  23.             int caret = ((TextBox)sender).SelectionStart - ((TextBox)sender).Text.Length;
  24.             ((TextBox)sender).Text = nonhex.Replace(((TextBox)sender).Text, "").ToUpper();
  25.             ((TextBox)sender).SelectionStart = caret + ((TextBox)sender).Text.Length;
  26.         }
  27.     }
  28.  
  29. }
I can cut/copy/paste/undo just fine.

So then I made a new class derived from TextBox and put in your logic.
Expand|Select|Wrap|Line Numbers
  1.         class HexBox : TextBox
  2.         {
  3.             public HexBox()
  4.             {
  5.                 this.TextChanged += new EventHandler(HexBox_TextChanged);
  6.             }
  7.  
  8.             void HexBox_TextChanged(object sender, EventArgs e)
  9.             {
  10.                 int caret = ((TextBox)sender).SelectionStart - ((TextBox)sender).Text.Length;
  11.                 ((TextBox)sender).Text = nonhex.Replace(((TextBox)sender).Text, "").ToUpper();
  12.                 ((TextBox)sender).SelectionStart = caret + ((TextBox)sender).Text.Length;
  13.  
  14.             }
  15.         }
  16.  
Then added a new HexBox to the form
Expand|Select|Wrap|Line Numbers
  1.         public Form1()
  2.         {
  3.             InitializeComponent();
  4.  
  5.             HexBox Yogi = new HexBox();
  6.             Yogi.Location = new Point(50,50);
  7.             this.Controls.Add(Yogi);
  8.         }
  9.  
Yep that works too.

Recapping that makes the final project with a TextBox and a HexBox look like this.
Expand|Select|Wrap|Line Numbers
  1. using System;
  2. using System.Collections.Generic;
  3. using System.ComponentModel;
  4. using System.Data;
  5. using System.Drawing;
  6. using System.Linq;
  7. using System.Text;
  8. using System.Windows.Forms;
  9. using System.Text.RegularExpressions;
  10.  
  11. namespace Testing
  12. {
  13.     public partial class Form1 : Form
  14.     {
  15.         private static Regex nonhex = new Regex(@"[^0-9a-fA-F]+");
  16.         public Form1()
  17.         {
  18.             InitializeComponent();
  19.  
  20.             HexBox Yogi = new HexBox();
  21.             Yogi.Location = new Point(50,50);
  22.             this.Controls.Add(Yogi);
  23.         }
  24.  
  25.         private void textBox1_TextChanged(object sender, EventArgs e)
  26.         {
  27.             int caret = ((TextBox)sender).SelectionStart - ((TextBox)sender).Text.Length;
  28.             ((TextBox)sender).Text = nonhex.Replace(((TextBox)sender).Text, "").ToUpper();
  29.             ((TextBox)sender).SelectionStart = caret + ((TextBox)sender).Text.Length;
  30.         }
  31.  
  32.  
  33.  
  34.         class HexBox : TextBox
  35.         {
  36.             public HexBox()
  37.             {
  38.                 this.TextChanged += new EventHandler(HexBox_TextChanged);
  39.             }
  40.  
  41.             void HexBox_TextChanged(object sender, EventArgs e)
  42.             {
  43.                 int caret = ((TextBox)sender).SelectionStart - ((TextBox)sender).Text.Length;
  44.                 ((TextBox)sender).Text = nonhex.Replace(((TextBox)sender).Text, "").ToUpper();
  45.                 ((TextBox)sender).SelectionStart = caret + ((TextBox)sender).Text.Length;
  46.             }
  47.         }
  48.     }
  49. }
  50.  
Hope it helps ya.
Newbie
 
Join Date: Jun 2009
Posts: 3
#6: Jun 16 '09

re: C# - WinForms: Extended TextBox won't undo after paste


First off, thanks for the help.

Ok, so the changes here are that instead of going through the textbox directly (ie, this.Text) we're going through the sender object (ie, ((TextBox)sender).Text), right? I don't see any other changes.

This works fine when I am only typing 0-9 & A-F but if I type an 'H' (which properly doesn't show up) or an 'a' (which properly becomes capitalized) undo breaks. If I paste 'BADDAD' undo works fine, but breaks on 'baddad' or 'Bad your dad is' (which both properly show up as 'BADDAD').

Are you not getting the same results? This might all be too big of a problem to waste time on since text boxes only do simple 'current value or last value' swapping instead of a real undo stack, but I'd like the box to function like normal except for what happens to its text input.

If you're seriously still not having any trouble with it, then I'm not sure what to do, because the behavior is definitely real on my machine, so please let me know if it's functioning the same on your machine or if undo really does work.

(Don't know if I should have mentioned it, I'm using: VisualStudio 2008, targeting .Net 3.5, on 64-bit Vista)

Thanks again, and I appreciate the help! :)
tlhintoq's Avatar
Moderator
 
Join Date: Mar 2008
Location: Arizona, USA
Posts: 2,307
#7: Jun 16 '09

re: C# - WinForms: Extended TextBox won't undo after paste


Quote:
Ok, so the changes here are that instead of going through the textbox directly (ie, this.Text) we're going through the sender object (ie, ((TextBox)sender).Text), right?
Right. This takes the sending control object named 'sender' and casts it from type object back to type TextBox. This way instead of making a specific new control (HexBox) we just process any TextBox for hex input.

Quote:
Are you not getting the same results?
I can't say I tried to beat it up and make sure it was bullet-proof. I typed a little, I cut, I pasted, I undo'd. It may not be so much that it does or doesn't work, as just unexpected behavior of the undo code that you didn't write. After all, you are relying on Microsoft's idea of how undo should work. I don't know if it has a time element inside, or stops at a space, or just the last ten typed characters or what.

If you need to, I suppose you could just write it a little more code for doing your own "undo". After the text is parsed, and the approved hex-only content is in place then set some private variable to that. Override the undo so that it inserts the private variable.

Quote:
(Don't know if I should have mentioned it, I'm using: VisualStudio 2008, targeting .Net 3.5, on 64-bit Vista)
Visual Studio 2008
targeting .Net 2.0
64-bit Vista ultimate
8 gig ram
4 cpu
5 monitors
1 poodle
6 robot toys
4 viper pilot mini legos
3rd mocha frappicino of the day
Reply