title: C# Include "static" (undeletable/unalterable) text in text field (ComboBox/Textbox)
body: <p>I have been trying to make a custom TextBox component that would allow me to include a static bit of text included in the TextBox's input field, and consequently, disallowing the user to alter it.</p>
  
  <p>I have figured out that I would have to manipulate/hook the key input events (including WndProc).</p>
  
  <p>Concretely, my goal is to prevent the user from paste-replacing, cutting, deleting a static piece of text that can be be either "docked" (or not) to the start or end of the TextBox.</p>
  
  <p>I have tried many things, but the issue that I was constantly facing was that I couldn't deduce the end position of the selection.</p>
  
  <p>What I currently have (inspired/based on <a href="http://www.codeproject.com/Articles/29766/TNumEditBox-A-Numeric-Edit-Control-with-ContextMen" rel="nofollow">TNumEditBox</a>):</p>
  
  <pre><code>public class LibraryComboBox : HybridComboBox //Ignore the parent class' name; it is basically a ComboBox that supports the ReadOnly attribute
  {
      public LibraryComboBox()
          : base()
      { }
  
      public String SelectedLibrary { get; set; } //Static text
      public TextPosition TextPosition = TextPosition.None; //"Docking" position
  
      private const int WM_CHAR = 0x0102;
      private const int WM_CUT = 0x0300;
      private const int WM_COPY = 0x0301;
      private const int WM_PASTE = 0x0302;
      private const int WM_CLEAR = 0x0303;
  
      protected override void WndProc(ref Message m)
      {
          if (m.Msg == WM_PASTE)
          {
              //TODO: Prevent overwriting the static part
          }
          else if (m.Msg == WM_CUT)
          {
              //TODO: Prevent cutting over the static part
          }
          else if (m.Msg == WM_CLEAR)
          {
              base.OnTextChanged(EventArgs.Empty);
          }
          else
          {
              base.WndProc(ref m);
          }
      }
  
      protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
      {
          if (keyData == (Keys)Shortcut.CtrlV)
          {
  
              string text = Clipboard.GetText();
  
              for (int k = 0; k &lt; text.Length; k++)
              {
                  SendCharKey(text[k]);
              }
              return true;
          }
          else if (keyData == (Keys)Shortcut.CtrlC)
          {
              Clipboard.SetText(this.SelectedText);
              return true;
          }
          return base.ProcessCmdKey(ref msg, keyData);
      }
  
      protected override void OnKeyDown(KeyEventArgs e)
      {
          base.OnKeyDown(e);
  
          if (!this.ReadOnly)
          {
              if (e.KeyData == Keys.Delete || e.KeyData == Keys.Back)
              {
                  //TODO: Remove corresponding characters
                  e.SuppressKeyPress = true;  // does not transform event to KeyPress, but to KeyUp
              }
          }
      }
  
      protected override void OnKeyPress(KeyPressEventArgs e)
      {
          base.OnKeyPress(e);
  
          if (this.ReadOnly)
          {
              return;
          }
  
          //TODO: Prevent any unauthorized changes to the library path
  
          if (this.SelectionStart &lt; this.Text.IndexOf(this.SelectedLibrary))
              e.Handled = true;
      }
  
      private void SendCharKey(char c)
      {
          Message msg = new Message();
  
          msg.HWnd = this.Handle;
          msg.Msg = WM_CHAR;
          msg.WParam = (IntPtr)c;
          msg.LParam = IntPtr.Zero;
  
          base.WndProc(ref msg);
      }
  }
  
  public enum TextPosition
  {
      None = 0,
      Left = 1,
      Right = 2
  }
  </code></pre>