News Archive

Sort posts by the categories below:

All Categories General Movies Sports Programming Woodworking

Read-Only Combo Boxes Posted at 07:09 AM - 10/06/09 in Programming by Dennis

Last year, I was writing a program where I needed some combo boxes that were "read-only".  What I mean by that is, if the user is authorized to make changes then the combo-box would operate as normal.  If not, then a read-only property was set, and the text portion of the combo couldn't be typed in and the drop down was disabled.  I finally found some code to help me out, I can't remember where it came from but it is very well documented:

   1:  using System;
   2:  using System.Runtime.InteropServices;
   3:  using System.Windows.Forms;
   4:  using System.ComponentModel;
   5:   
   6:  namespace ReadOnlyComboBoxTestApp
   7:  {
   8:      public class exComboBox : ComboBox
   9:      {
  10:   
  11:          #region "-- Declarations --"
  12:          private bool readOnly;
  13:          private bool droppedDown = false;
  14:          
  15:          private int selectedIndex = -1;
  16:          
  17:          private ComboBoxStyle dropDownStyle = ComboBoxStyle.DropDown;
  18:          
  19:          [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true, 
  20:              ExactSpelling = true)]
  21:          private static extern IntPtr GetWindow(IntPtr hwnd, UInt32 wCmd);
  22:   
  23:          [DllImport("user32.dll", CharSet = CharSet.Auto)]
  24:          private static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, 
  25:              bool wParam, Int32 lParam);
  26:          
  27:          private const UInt32 WM_COMMAND = 0x111;
  28:          private const UInt32 EM_SETREADONLY = 0xcf;
  29:          private const UInt32 EM_EMPTYUNDOBUFFER = 0xcd;
  30:          private const UInt32 CB_SHOWDROPDOWN = 0x14f;
  31:          private const UInt32 GW_CHILD = 5;
  32:   
  33:          #endregion
  34:          
  35:          #region "-- Properties --"
  36:   
  37:          [Browsable(true), DefaultValue(false)]
  38:          public bool ReadOnly
  39:          {
  40:              get { return readOnly; }
  41:              set
  42:              {
  43:                  // In design mode we don't want setting the read only property 
  44:                  // to alter the dropdown style.
  45:                  if (!DesignMode)
  46:                  {
  47:                      // If the DropDownStyle is anything other than DropDown then setting
  48:                      // ReadOnly to true will have no affect. Therefore we'll force the style
  49:                      // to DropDown as it goes to ReadOnly and restore it when it's turned off.
  50:                      if (value)
  51:                      {
  52:                          // If the value is changing then we want to save the dropdown style.
  53:                          // In case the value gets set to true more than once we don't want 
  54:                          // to lose the saved drop down style.
  55:                          if (readOnly != value)
  56:                          {
  57:                              dropDownStyle = base.DropDownStyle;
  58:                              base.DropDownStyle = ComboBoxStyle.DropDown;
  59:                          }
  60:                      }
  61:                      // restore the saved drop down style
  62:                      else
  63:                      {
  64:                          base.DropDownStyle = dropDownStyle;
  65:                      }
  66:                  }
  67:                  readOnly = value;
  68:                  
  69:                  // If readonly then don't let the user tab to the field
  70:                  base.TabStop = !value;
  71:                  
  72:                  // Setting TabStop to false causes the text in the box to be selected if it matches
  73:                  // an entry in the list. Setting selection length to zero removes the selection.
  74:                  base.SelectionLength = 0;
  75:                  
  76:                  // Send the textbox portion of the combo the readonly message.
  77:                  // It will change the color and behavior.
  78:                  IntPtr windowHandle = GetWindow(this.Handle, GW_CHILD);
  79:                  SendMessage(windowHandle, EM_SETREADONLY, value, 0);
  80:                  
  81:                  // If text was typed or pasted into the textbox, the context menu will
  82:                  // have the undo activated. When the text box is in the readonly state
  83:                  // the undo will still be active from the right click context menu
  84:                  // allowing the user to restore the previous value. This sendmessage
  85:                  // will clear the undo buffer which will clear the undo.
  86:                  SendMessage(windowHandle, EM_EMPTYUNDOBUFFER, value, 0);
  87:                  
  88:                  // the dropdown may have been dropped before the readonly is set
  89:                  droppedDown = false;
  90:                  this.Refresh();
  91:              }
  92:          }
  93:          
  94:          // Saving and returning a local copy of the selected index keeps a
  95:          // changed value from being returned when the control is in the
  96:          // readonly state. The OnSelectedIndexChanged event captures the
  97:          // index value that is returned here. Must be shadows or else the
  98:          // value passed won't cause the OnSelectedIndexChanged method to fire
  99:          // and the text value to be displayed, won't.
 100:          //
 101:          public new int SelectedIndex
 102:          {
 103:              get { return selectedIndex; }
 104:              set
 105:              {
 106:                  selectedIndex = value;
 107:                  base.SelectedIndex = value;
 108:                  // Set it twice to work around databound bug KB327244
 109:                  if (value == -1)
 110:                  {
 111:                      selectedIndex = value;
 112:                      base.SelectedIndex = value;
 113:                  }
 114:              }
 115:          }
 116:          #endregion
 117:   
 118:          #region "-- Overrides --"
 119:          
 120:          // Intercepting message 273 when readonly and the listbox is dropped
 121:          // keeps the user from selecting an item in the list and having it update
 122:          // the text value of the combo as well as firing the associated changed events.
 123:          // Since we intercept a windows message we will have to manually bring up
 124:          // the listbox.
 125:          //
 126:          // msg 305 (0x131)   =  an item was clicked from the dropdown list
 127:          // msg 273 (0x111)   = (WM_COMMAND) follows dropdown list click and all other actions?
 128:          // msg 8465 (0x2111) = (WM_REFLECT + WM_COMMAND) subsequent command after the 273
 129:          //
 130:          protected override void WndProc(ref Message m)
 131:          {
 132:              // Cannot use me.DroppedDown, it causes a System.StackOverflowException.
 133:              // Asking for it's value must produce windows messages for the combobox
 134:              // and thus create a recursive loop.
 135:              if (readOnly & m.Msg == WM_COMMAND) return;
 136:   
 137:   
 138:              base.WndProc(ref m);
 139:          }
 140:          
 141:          // This event will not fire when msg 273 is intercepted in WndProc. When in the
 142:          // readonly state clicking on an item in the listbox appears to have no effect. It
 143:          // does in fact change the value of MyBase.SelectedIndex. Saving the last good index
 144:          // value locally allows the overriden Index property to supply the proper index value.
 145:          //
 146:          protected override void OnSelectedIndexChanged(System.EventArgs e)
 147:          {
 148:              selectedIndex = base.SelectedIndex;
 149:              base.OnSelectedIndexChanged(e);
 150:          }
 151:   
 152:          // We must manually track dropped state. Asking the control if it's
 153:          // dropped from within WndProc will cause a System.StackOverflowException.
 154:          //
 155:          protected override void OnDropDown(System.EventArgs e)
 156:          {
 157:              droppedDown = true;
 158:              base.OnDropDown(e);
 159:          }
 160:          
 161:          // The up and down arrow keys cause the combobox to change selection to the next
 162:          // or previous in the list. The page up and page down keys change the selection
 163:          // by one page at a time as defined by the size of the dropdown list. Setting
 164:          // e.Handled to true if any of these keys is pressed stops the selection change
 165:          // when readonly. The alt down arrow combination is allowed since it drops the listbox.
 166:          //
 167:          protected override void OnKeyDown( KeyEventArgs e)
 168:          {
 169:              if (readOnly)
 170:              {
 171:                  if (e.KeyCode == Keys.Up || e.KeyCode == Keys.PageUp || 
 172:                      e.KeyCode == Keys.PageDown || (e.KeyCode == Keys.Down & 
 173:                      ((Control.ModifierKeys & Keys.Alt) != Keys.Alt)))
 174:                  {
 175:                      e.Handled = true;
 176:                  }
 177:              }
 178:              base.OnKeyDown(e);
 179:          }
 180:          
 181:          // The combobox default behavior when pressing F4 is to drop the listbox.
 182:          // If F4 is immediately pressed a second time the OnSelectionChangeCommitted
 183:          // event fires regardless of whether a change has been made or not. When
 184:          // readonly we don't want a change event to fire. This code will stop it.
 185:          //
 186:          protected override void OnSelectionChangeCommitted(System.EventArgs e)
 187:          {
 188:              if (!readOnly)
 189:              {
 190:                  base.OnSelectionChangeCommitted(e);
 191:              }
 192:          }
 193:          #endregion
 194:      }
 195:   
 196:  }

Here's the implementation:

   1:          private void button1_Click(object sender, EventArgs e)
   2:          {
   3:              exComboBox1.ReadOnly = true;
   4:          }
   5:   
   6:          private void button2_Click(object sender, EventArgs e)
   7:          {
   8:              exComboBox1.ReadOnly = false;
   9:          }
  10:   

Comments:
Posted at 06:06 PM - 07/21/10Buildings are quite expensive and not everyone can buy it. However, loan are invented to help different people in such kind of cases. Poster: HoganLesa30
Posted at 10:36 AM - 07/02/10People in the world get the home loans in different creditors, because it is fast and easy. Poster: ElmaNEWTON21
Posted at 02:19 AM - 07/02/10I received 1 st home loans when I was 32 and it helped my family very much. However, I need the small business loan again. Poster: MERCERRachael23
Posted at 04:51 PM - 07/01/10That is well known that money can make people disembarrass. But how to act when someone doesn't have cash? The one way only is to get the loans and secured loan. Poster: EricksonOra
Posted at 10:18 AM - 05/24/10asdfrePoster: medhat
Posted at 07:47 AM - 05/17/10Some specialists tell that credit loans help people to live the way they want, because they can feel free to buy necessary goods. Moreover, some banks give short term loan for different persons. Poster: LoweManuela28
Posted at 07:26 PM - 03/30/10I had got a desire to make my own business, nevertheless I did not have got enough amount of money to do this. Thank God my close colleague proposed to take the mortgage loans. Thus I took the consolidation loans and realized my old dream. Poster: OdessaSharpe25
Posted at 09:05 PM - 03/08/10If you are in uncomfortable position and have got no cash to move out from that, you would have to take the business loans. Because it would aid you for sure. I get financial loan every time I need and feel myself good just because of this. Poster: JANNAAyers21

Previous Posts
TitleDate
A Boring Blog07:30 AM - 08/11/09
I give up!06:44 AM - 08/06/09
No more Duncan...09:21 PM - 07/22/09
Vacation: Days 4 & 505:53 AM - 07/04/09
Vacation: Days 2 & 305:59 PM - 07/02/09
Vacation: Day 107:20 AM - 06/30/09
Happy Father's Day!01:01 PM - 06/21/09
See, I'm not the only one06:55 AM - 06/20/09
Just Plain Mad!09:07 PM - 06/06/09
Irritated09:09 AM - 06/04/09
More flags! More Fun!02:26 PM - 06/02/09
I've been Taken!08:35 PM - 05/24/09
Let's Celebrate!05:57 AM - 05/20/09
Happy Mother's Day!05:46 AM - 05/11/09
Up in smoke09:39 PM - 04/30/09
He is risen!02:01 PM - 04/12/09
Proof that whiners get their way09:06 PM - 04/02/09
A few more Josephs04:40 PM - 03/29/09
Bad Dog! No Biscuit!08:39 AM - 03/27/09
OMG! They killed Kenny!08:12 PM - 03/25/09
Is it just me?06:14 AM - 03/24/09
Whatcha been up to?08:11 PM - 03/08/09
Mmmmhhhhhmmmm!09:34 PM - 02/15/09
A Question...07:35 PM - 02/13/09
Am I the only one?09:08 PM - 02/09/09