1 // Permission is hereby granted, free of charge, to any person obtaining 2 // a copy of this software and associated documentation files (the 3 // "Software"), to deal in the Software without restriction, including 4 // without limitation the rights to use, copy, modify, merge, publish, 5 // distribute, sublicense, and/or sell copies of the Software, and to 6 // permit persons to whom the Software is furnished to do so, subject to 7 // the following conditions: 8 // 9 // The above copyright notice and this permission notice shall be 10 // included in all copies or substantial portions of the Software. 11 // 12 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 13 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 14 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 16 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 17 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 18 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 19 // 20 // Copyright (c) 2004-2006 Novell, Inc. 21 // 22 // Authors: 23 // Jordi Mas i Hernandez, jordi@ximian.com 24 // Mike Kestner <mkestner@novell.com> 25 // 26 // 27 28 using System; 29 using System.Drawing; 30 using System.Collections; 31 using System.ComponentModel; 32 using System.Reflection; 33 using System.Runtime.InteropServices; 34 35 namespace System.Windows.Forms 36 { 37 [ClassInterface (ClassInterfaceType.AutoDispatch)] 38 [ComVisible (true)] 39 [LookupBindingPropertiesAttribute ()] 40 public class CheckedListBox : ListBox 41 { 42 private CheckedIndexCollection checked_indices; 43 private CheckedItemCollection checked_items; 44 private Hashtable check_states = new Hashtable (); 45 private bool check_onclick = false; 46 private bool three_dcheckboxes = false; 47 CheckedListBox()48 public CheckedListBox () 49 { 50 checked_indices = new CheckedIndexCollection (this); 51 checked_items = new CheckedItemCollection (this); 52 SetStyle (ControlStyles.ResizeRedraw, true); 53 } 54 55 #region events 56 static object ItemCheckEvent = new object (); 57 58 [Browsable (true)] 59 [EditorBrowsable (EditorBrowsableState.Always)] 60 public new event EventHandler Click { 61 add { base.Click += value; } 62 remove { base.Click -= value; } 63 } 64 65 [Browsable (false)] 66 [EditorBrowsable (EditorBrowsableState.Never)] 67 public new event EventHandler DataSourceChanged { 68 add { base.DataSourceChanged += value; } 69 remove { base.DataSourceChanged -= value; } 70 } 71 72 [Browsable (false)] 73 [EditorBrowsable (EditorBrowsableState.Never)] 74 public new event EventHandler DisplayMemberChanged { 75 add { base.DisplayMemberChanged += value; } 76 remove { base.DisplayMemberChanged -= value; } 77 } 78 79 [Browsable (false)] 80 [EditorBrowsable (EditorBrowsableState.Never)] 81 public new event DrawItemEventHandler DrawItem { 82 add { base.DrawItem += value; } 83 remove { base.DrawItem -= value; } 84 } 85 86 [Browsable (false)] 87 [EditorBrowsable (EditorBrowsableState.Never)] 88 public new event MeasureItemEventHandler MeasureItem { 89 add { base.MeasureItem += value; } 90 remove { base.MeasureItem -= value; } 91 } 92 93 [Browsable (false)] 94 [EditorBrowsable (EditorBrowsableState.Never)] 95 public new event EventHandler ValueMemberChanged { 96 add { base.ValueMemberChanged += value; } 97 remove { base.ValueMemberChanged -= value; } 98 } 99 100 public event ItemCheckEventHandler ItemCheck { 101 add { Events.AddHandler (ItemCheckEvent, value); } 102 remove { Events.RemoveHandler (ItemCheckEvent, value); } 103 } 104 105 [Browsable (true)] 106 [EditorBrowsable (EditorBrowsableState.Always)] 107 public new event MouseEventHandler MouseClick { 108 add { base.MouseClick += value; } 109 remove { base.MouseClick -= value; } 110 } 111 #endregion Events 112 113 #region Public Properties 114 115 [Browsable (false)] 116 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] 117 public CheckedListBox.CheckedIndexCollection CheckedIndices { 118 get {return checked_indices; } 119 } 120 121 [Browsable (false)] 122 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] 123 public CheckedListBox.CheckedItemCollection CheckedItems { 124 get {return checked_items; } 125 } 126 127 [DefaultValue (false)] 128 public bool CheckOnClick { 129 get { return check_onclick; } 130 set { check_onclick = value; } 131 } 132 133 protected override CreateParams CreateParams { 134 get { return base.CreateParams;} 135 } 136 137 [EditorBrowsable (EditorBrowsableState.Never)] 138 [Browsable (false)] 139 public new object DataSource { 140 get { return base.DataSource; } 141 // FIXME: docs say you can't use a DataSource with this subclass 142 set { base.DataSource = value; } 143 } 144 145 [EditorBrowsable (EditorBrowsableState.Never)] 146 [Browsable (false)] 147 public new string DisplayMember { 148 get { return base.DisplayMember; } 149 set { base.DisplayMember = value; } 150 } 151 152 [Browsable (false)] 153 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] 154 [EditorBrowsable (EditorBrowsableState.Never)] 155 public override DrawMode DrawMode { 156 get { return DrawMode.Normal; } 157 set { /* Not an exception, but has no effect. */ } 158 } 159 160 [Browsable (false)] 161 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] 162 [EditorBrowsable (EditorBrowsableState.Never)] 163 public override int ItemHeight { 164 get { return base.ItemHeight; } 165 set { /* Not an exception, but has no effect. */ } 166 } 167 168 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)] 169 [Localizable (true)] 170 [Editor ("System.Windows.Forms.Design.ListControlStringCollectionEditor, " + Consts.AssemblySystem_Design, typeof (System.Drawing.Design.UITypeEditor))] 171 public new CheckedListBox.ObjectCollection Items { 172 get { return (CheckedListBox.ObjectCollection) base.Items; } 173 } 174 175 public override SelectionMode SelectionMode { 176 get { return base.SelectionMode; } 177 set { 178 if (!Enum.IsDefined (typeof (SelectionMode), value)) 179 throw new InvalidEnumArgumentException ("value", (int) value, typeof (SelectionMode)); 180 181 if (value == SelectionMode.MultiSimple || value == SelectionMode.MultiExtended) 182 throw new ArgumentException ("Multi selection not supported on CheckedListBox"); 183 184 base.SelectionMode = value; 185 } 186 } 187 188 [DefaultValue (false)] 189 public bool ThreeDCheckBoxes { 190 get { return three_dcheckboxes; } 191 set { 192 if (three_dcheckboxes == value) 193 return; 194 195 three_dcheckboxes = value; 196 Refresh (); 197 } 198 } 199 200 [Browsable (false)] 201 [EditorBrowsable (EditorBrowsableState.Never)] 202 public new string ValueMember { 203 get { return base.ValueMember; } 204 set { base.ValueMember = value; } 205 } 206 207 [Browsable (false)] 208 [EditorBrowsable (EditorBrowsableState.Never)] 209 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] 210 public new Padding Padding { 211 get { return base.Padding; } 212 set { base.Padding = value; } 213 } 214 #endregion Public Properties 215 216 #region Public Methods 217 CreateAccessibilityInstance()218 protected override AccessibleObject CreateAccessibilityInstance () 219 { 220 return base.CreateAccessibilityInstance (); 221 } 222 CreateItemCollection()223 protected override ListBox.ObjectCollection CreateItemCollection () 224 { 225 return new ObjectCollection (this); 226 } 227 GetItemChecked(int index)228 public bool GetItemChecked (int index) 229 { 230 return check_states.Contains (Items [index]); 231 } 232 GetItemCheckState(int index)233 public CheckState GetItemCheckState (int index) 234 { 235 if (index < 0 || index >= Items.Count) 236 throw new ArgumentOutOfRangeException ("Index of out range"); 237 238 object o = Items [index]; 239 if (check_states.Contains (o)) 240 return (CheckState) check_states [o]; 241 else 242 return CheckState.Unchecked; 243 } 244 OnBackColorChanged(EventArgs e)245 protected override void OnBackColorChanged (EventArgs e) 246 { 247 base.OnBackColorChanged (e); 248 } 249 OnClick(EventArgs e)250 protected override void OnClick (EventArgs e) 251 { 252 base.OnClick (e); 253 } 254 OnDrawItem(DrawItemEventArgs e)255 protected override void OnDrawItem (DrawItemEventArgs e) 256 { 257 if (check_states.Contains (Items [e.Index])) { 258 DrawItemState state = e.State | DrawItemState.Checked; 259 if (((CheckState) check_states [Items [e.Index]]) == CheckState.Indeterminate) 260 state |= DrawItemState.Inactive; 261 e = new DrawItemEventArgs (e.Graphics, e.Font, e.Bounds, e.Index, state, e.ForeColor, e.BackColor); 262 } 263 ThemeEngine.Current.DrawCheckedListBoxItem (this, e); 264 } 265 OnFontChanged(EventArgs e)266 protected override void OnFontChanged (EventArgs e) 267 { 268 base.OnFontChanged (e); 269 } 270 OnHandleCreated(EventArgs e)271 protected override void OnHandleCreated (EventArgs e) 272 { 273 base.OnHandleCreated (e); 274 } 275 OnItemCheck(ItemCheckEventArgs ice)276 protected virtual void OnItemCheck (ItemCheckEventArgs ice) 277 { 278 ItemCheckEventHandler eh = (ItemCheckEventHandler)(Events [ItemCheckEvent]); 279 if (eh != null) 280 eh (this, ice); 281 } 282 OnKeyPress(KeyPressEventArgs e)283 protected override void OnKeyPress (KeyPressEventArgs e) 284 { 285 base.OnKeyPress (e); 286 287 if (e.KeyChar == ' ' && FocusedItem != -1) 288 SetItemChecked (FocusedItem, !GetItemChecked (FocusedItem)); 289 } 290 OnMeasureItem(MeasureItemEventArgs e)291 protected override void OnMeasureItem (MeasureItemEventArgs e) 292 { 293 base.OnMeasureItem (e); 294 } 295 OnSelectedIndexChanged(EventArgs e)296 protected override void OnSelectedIndexChanged (EventArgs e) 297 { 298 base.OnSelectedIndexChanged (e); 299 } 300 RefreshItems()301 protected override void RefreshItems () 302 { 303 base.RefreshItems (); 304 } 305 SetItemChecked(int index, bool value)306 public void SetItemChecked (int index, bool value) 307 { 308 SetItemCheckState (index, value ? CheckState.Checked : CheckState.Unchecked); 309 } 310 SetItemCheckState(int index, CheckState value)311 public void SetItemCheckState (int index, CheckState value) 312 { 313 if (index < 0 || index >= Items.Count) 314 throw new ArgumentOutOfRangeException ("Index of out range"); 315 316 if (!Enum.IsDefined (typeof (CheckState), value)) 317 throw new InvalidEnumArgumentException (string.Format("Enum argument value '{0}' is not valid for CheckState", value)); 318 319 CheckState old_value = GetItemCheckState (index); 320 321 if (old_value == value) 322 return; 323 324 ItemCheckEventArgs icea = new ItemCheckEventArgs (index, value, old_value); 325 OnItemCheck (icea); 326 327 switch (icea.NewValue) { 328 case CheckState.Checked: 329 case CheckState.Indeterminate: 330 check_states[Items[index]] = icea.NewValue; 331 break; 332 case CheckState.Unchecked: 333 check_states.Remove (Items[index]); 334 break; 335 default: 336 break; 337 } 338 339 UpdateCollections (); 340 341 InvalidateCheckbox (index); 342 } 343 WmReflectCommand(ref Message m)344 protected override void WmReflectCommand (ref Message m) 345 { 346 base.WmReflectCommand (ref m); 347 } 348 WndProc(ref Message m)349 protected override void WndProc (ref Message m) 350 { 351 base.WndProc (ref m); 352 } 353 354 #endregion Public Methods 355 356 #region Private Methods 357 358 int last_clicked_index = -1; 359 OnItemClick(int index)360 internal override void OnItemClick (int index) 361 { 362 if ((CheckOnClick || last_clicked_index == index) && index > -1) { 363 if (GetItemChecked (index)) 364 SetItemCheckState (index, CheckState.Unchecked); 365 else 366 SetItemCheckState (index, CheckState.Checked); 367 } 368 369 last_clicked_index = index; 370 base.OnItemClick (index); 371 } 372 CollectionChanged()373 internal override void CollectionChanged () 374 { 375 base.CollectionChanged (); 376 UpdateCollections (); 377 } 378 InvalidateCheckbox(int index)379 private void InvalidateCheckbox (int index) 380 { 381 Rectangle area = GetItemDisplayRectangle (index, TopIndex); 382 area.X += 2; 383 area.Y += (area.Height - 11) / 2; 384 area.Width = 11; 385 area.Height = 11; 386 Invalidate (area); 387 } 388 UpdateCollections()389 private void UpdateCollections () 390 { 391 CheckedItems.Refresh (); 392 CheckedIndices.Refresh (); 393 } 394 395 #endregion Private Methods 396 397 public new class ObjectCollection : ListBox.ObjectCollection 398 { 399 private CheckedListBox owner; 400 ObjectCollection(CheckedListBox owner)401 public ObjectCollection (CheckedListBox owner) : base (owner) 402 { 403 this.owner = owner; 404 } 405 Add(object item, bool isChecked)406 public int Add (object item, bool isChecked) 407 { 408 return Add (item, isChecked ? CheckState.Checked : CheckState.Unchecked); 409 } 410 Add(object item, CheckState check)411 public int Add (object item, CheckState check) 412 { 413 int idx = Add (item); 414 415 ItemCheckEventArgs icea = new ItemCheckEventArgs (idx, check, CheckState.Unchecked); 416 417 if (check == CheckState.Checked) 418 owner.OnItemCheck (icea); 419 420 if (icea.NewValue != CheckState.Unchecked) 421 owner.check_states[item] = icea.NewValue; 422 423 owner.UpdateCollections (); 424 return idx; 425 } 426 } 427 428 public class CheckedIndexCollection : IList, ICollection, IEnumerable 429 { 430 private CheckedListBox owner; 431 private ArrayList indices = new ArrayList (); 432 CheckedIndexCollection(CheckedListBox owner)433 internal CheckedIndexCollection (CheckedListBox owner) 434 { 435 this.owner = owner; 436 } 437 438 #region Public Properties 439 public int Count { 440 get { return indices.Count; } 441 } 442 443 public bool IsReadOnly { 444 get { return true;} 445 } 446 447 bool ICollection.IsSynchronized { 448 get { return false; } 449 } 450 451 bool IList.IsFixedSize{ 452 get { return true; } 453 } 454 455 object ICollection.SyncRoot { 456 get { return this; } 457 } 458 459 [Browsable (false)] 460 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] 461 public int this[int index] { 462 get { 463 if (index < 0 || index >= Count) 464 throw new ArgumentOutOfRangeException ("Index of out range"); 465 466 return (int) indices[index]; 467 } 468 } 469 #endregion Public Properties 470 Contains(int index)471 public bool Contains (int index) 472 { 473 return indices.Contains (index); 474 } 475 476 CopyTo(Array dest, int index)477 public void CopyTo (Array dest, int index) 478 { 479 indices.CopyTo (dest, index); 480 } 481 GetEnumerator()482 public IEnumerator GetEnumerator () 483 { 484 return indices.GetEnumerator (); 485 } 486 IList.Add(object value)487 int IList.Add (object value) 488 { 489 throw new NotSupportedException (); 490 } 491 IList.Clear()492 void IList.Clear () 493 { 494 throw new NotSupportedException (); 495 } 496 IList.Contains(object index)497 bool IList.Contains (object index) 498 { 499 return Contains ((int)index); 500 } 501 IList.IndexOf(object index)502 int IList.IndexOf (object index) 503 { 504 return IndexOf ((int) index); 505 } 506 IList.Insert(int index, object value)507 void IList.Insert (int index, object value) 508 { 509 throw new NotSupportedException (); 510 } 511 IList.Remove(object value)512 void IList.Remove (object value) 513 { 514 throw new NotSupportedException (); 515 } 516 IList.RemoveAt(int index)517 void IList.RemoveAt (int index) 518 { 519 throw new NotSupportedException (); 520 } 521 522 object IList.this[int index]{ 523 get {return indices[index]; } 524 set {throw new NotImplementedException (); } 525 } 526 IndexOf(int index)527 public int IndexOf (int index) 528 { 529 return indices.IndexOf (index); 530 } 531 532 #region Private Methods Refresh()533 internal void Refresh () 534 { 535 indices.Clear (); 536 for (int i = 0; i < owner.Items.Count; i++) 537 if (owner.check_states.Contains (owner.Items [i])) 538 indices.Add (i); 539 } 540 #endregion Private Methods 541 542 } 543 544 public class CheckedItemCollection : IList, ICollection, IEnumerable 545 { 546 private CheckedListBox owner; 547 private ArrayList list = new ArrayList (); 548 CheckedItemCollection(CheckedListBox owner)549 internal CheckedItemCollection (CheckedListBox owner) 550 { 551 this.owner = owner; 552 } 553 554 #region Public Properties 555 public int Count { 556 get { return list.Count; } 557 } 558 559 public bool IsReadOnly { 560 get { return true; } 561 } 562 563 [Browsable (false)] 564 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] 565 public object this [int index] { 566 get { 567 if (index < 0 || index >= Count) 568 throw new ArgumentOutOfRangeException ("Index of out range"); 569 570 return list[index]; 571 } 572 set {throw new NotSupportedException ();} 573 } 574 575 bool ICollection.IsSynchronized { 576 get { return true; } 577 } 578 579 object ICollection.SyncRoot { 580 get { return this; } 581 } 582 583 bool IList.IsFixedSize { 584 get { return true; } 585 } 586 587 #endregion Public Properties 588 589 #region Public Methods Contains(object item)590 public bool Contains (object item) 591 { 592 return list.Contains (item); 593 } 594 CopyTo(Array dest, int index)595 public void CopyTo (Array dest, int index) 596 { 597 list.CopyTo (dest, index); 598 } 599 IList.Add(object value)600 int IList.Add (object value) 601 { 602 throw new NotSupportedException (); 603 } 604 IList.Clear()605 void IList.Clear () 606 { 607 throw new NotSupportedException (); 608 } 609 IList.Insert(int index, object value)610 void IList.Insert (int index, object value) 611 { 612 throw new NotSupportedException (); 613 } 614 IList.Remove(object value)615 void IList.Remove (object value) 616 { 617 throw new NotSupportedException (); 618 } 619 IList.RemoveAt(int index)620 void IList.RemoveAt (int index) 621 { 622 throw new NotSupportedException (); 623 } 624 IndexOf(object item)625 public int IndexOf (object item) 626 { 627 return list.IndexOf (item); 628 } 629 GetEnumerator()630 public IEnumerator GetEnumerator () 631 { 632 return list.GetEnumerator (); 633 } 634 635 #endregion Public Methods 636 637 #region Private Methods Refresh()638 internal void Refresh () 639 { 640 list.Clear (); 641 for (int i = 0; i < owner.Items.Count; i++) 642 if (owner.check_states.Contains (owner.Items [i])) 643 list.Add (owner.Items[i]); 644 } 645 #endregion Private Methods 646 } 647 [DefaultValue (false)] 648 public bool UseCompatibleTextRendering { 649 get { return use_compatible_text_rendering; } 650 set { use_compatible_text_rendering = value; } 651 } 652 } 653 } 654 655