|
//------------------------------------------------------------------------------
// <copyright file="CheckedListBox.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
/*
*/
namespace System.Windows.Forms {
using Accessibility;
using System.Text;
using System.Runtime.Remoting;
using System.Diagnostics;
using System;
using System.Security.Permissions;
using System.Collections;
using System.Windows.Forms;
using System.Windows.Forms.VisualStyles;
using System.Windows.Forms.ComponentModel;
using System.Drawing;
using System.ComponentModel;
using System.Runtime.InteropServices;
using Hashtable = System.Collections.Hashtable;
using Microsoft.Win32;
using System.Drawing.Design;
using System.Globalization;
using System.Drawing.Text;
/// <include file='doc\CheckedListBox.uex' path='docs/doc[@for="CheckedListBox"]/*' />
/// <devdoc>
/// <para>
///
/// Displays a list with a checkbox to the left
///
/// of each item.
///
/// </para>
/// </devdoc>
[
ComVisible(true),
ClassInterface(ClassInterfaceType.AutoDispatch),
LookupBindingProperties(), // ...overrides equivalent attribute in ListControl
SRDescription(SR.DescriptionCheckedListBox)
]
public class CheckedListBox : ListBox {
private int idealCheckSize = 13;
private const int LB_CHECKED = 1;
private const int LB_UNCHECKED = 0;
private const int LB_ERROR = -1;
private const int BORDER_SIZE = 1;
/// <include file='doc\CheckedListBox.uex' path='docs/doc[@for="CheckedListBox.killnextselect"]/*' />
/// <devdoc>
/// Decides whether or not to ignore the next LBN_SELCHANGE
/// message - used to prevent cursor keys from toggling checkboxes
/// </devdoc>
private bool killnextselect = false;
/// <include file='doc\CheckedListBox.uex' path='docs/doc[@for="CheckedListBox.onItemCheck"]/*' />
/// <devdoc>
/// Current listener of the onItemCheck event.
/// </devdoc>
private ItemCheckEventHandler onItemCheck;
/// <include file='doc\CheckedListBox.uex' path='docs/doc[@for="CheckedListBox.checkOnClick"]/*' />
/// <devdoc>
/// Indicates whether or not we should toggle check state on the first
/// click on an item, or whether we should wait for the user to click
/// again.
/// </devdoc>
private bool checkOnClick = false;
/// <include file='doc\CheckedListBox.uex' path='docs/doc[@for="CheckedListBox.flat"]/*' />
/// <devdoc>
/// Should we use 3d checkboxes or flat ones?
/// </devdoc>
private bool flat = true;
/// <include file='doc\CheckedListBox.uex' path='docs/doc[@for="CheckedListBox.lastSelected"]/*' />
/// <devdoc>
/// Indicates which item was last selected. We want to keep track
/// of this so we can be a little less aggressive about checking/
/// unchecking the items as the user moves around.
/// </devdoc>
private int lastSelected = -1;
/// <include file='doc\CheckedListBox.uex' path='docs/doc[@for="CheckedListBox.checkedItemCollection"]/*' />
/// <devdoc>
/// The collection of checked items in the CheckedListBox.
/// </devdoc>
private CheckedItemCollection checkedItemCollection = null;
private CheckedIndexCollection checkedIndexCollection = null;
private static int LBC_GETCHECKSTATE;
private static int LBC_SETCHECKSTATE;
static CheckedListBox() {
LBC_GETCHECKSTATE = SafeNativeMethods.RegisterWindowMessage("LBC_GETCHECKSTATE");
LBC_SETCHECKSTATE = SafeNativeMethods.RegisterWindowMessage("LBC_SETCHECKSTATE");
}
/// <include file='doc\CheckedListBox.uex' path='docs/doc[@for="CheckedListBox.CheckedListBox"]/*' />
/// <devdoc>
/// Creates a new CheckedListBox for the user.
/// </devdoc>
public CheckedListBox() : base() {
// If we eat WM_ERASEBKGRND messages, the background will be
// painted sometimes but not others. See ASURT 28545.
// SetStyle(ControlStyles.Opaque, true);
// If a long item is drawn with ellipsis, we must redraw the ellipsed part
// as well as the newly uncovered region.
SetStyle(ControlStyles.ResizeRedraw, true);
}
/// <include file='doc\CheckedListBox.uex' path='docs/doc[@for="CheckedListBox.CheckOnClick"]/*' />
/// <devdoc>
/// Indicates whether or not the checkbox should be toggled whenever an
/// item is selected. The default behaviour is to just change the
/// selection, and then make the user click again to check it. However,
/// some may prefer checking the item as soon as it is clicked.
/// </devdoc>
[
SRCategory(SR.CatBehavior),
DefaultValue(false),
SRDescription(SR.CheckedListBoxCheckOnClickDescr)
]
public bool CheckOnClick {
get {
return checkOnClick;
}
set {
checkOnClick = value;
}
}
/// <include file='doc\CheckedListBox.uex' path='docs/doc[@for="CheckedListBox.CheckedIndices"]/*' />
/// <devdoc>
/// Collection of checked indices in this CheckedListBox.
/// </devdoc>
[
Browsable(false),
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
]
public CheckedIndexCollection CheckedIndices {
get {
if (checkedIndexCollection == null) {
checkedIndexCollection = new CheckedIndexCollection(this);
}
return checkedIndexCollection;
}
}
/// <include file='doc\CheckedListBox.uex' path='docs/doc[@for="CheckedListBox.CheckedItems"]/*' />
/// <devdoc>
/// Collection of checked items in this CheckedListBox.
/// </devdoc>
[
Browsable(false),
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
]
public CheckedItemCollection CheckedItems {
get {
if (checkedItemCollection == null) {
checkedItemCollection = new CheckedItemCollection(this);
}
return checkedItemCollection;
}
}
/// <include file='doc\CheckedListBox.uex' path='docs/doc[@for="CheckedListBox.CreateParams"]/*' />
/// <devdoc>
/// This is called when creating a window. Inheriting classes can ovveride
/// this to add extra functionality, but should not forget to first call
/// base.CreateParams() to make sure the control continues to work
/// correctly.
/// </devdoc>
protected override CreateParams CreateParams {
[SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.UnmanagedCode)]
get {
CreateParams cp = base.CreateParams;
cp.Style |= NativeMethods.LBS_OWNERDRAWFIXED | NativeMethods.LBS_WANTKEYBOARDINPUT;
return cp;
}
}
/// <include file='doc\CheckedListBox.uex' path='docs/doc[@for="CheckedListBox.DataSource"]/*' />
/// <devdoc>
/// CheckedListBox DataSource.
/// </devdoc>
/// <internalonly/><hideinheritance/>
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
public new object DataSource {
get {
return base.DataSource;
}
set {
base.DataSource = value;
}
}
/// <include file='doc\CheckedListBox.uex' path='docs/doc[@for="CheckedListBox.DisplayMember"]/*' />
/// <devdoc>
/// CheckedListBox DisplayMember.
/// </devdoc>
/// <internalonly/><hideinheritance/>
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
public new string DisplayMember {
get {
return base.DisplayMember ;
}
set {
base.DisplayMember = value;
}
}
/// <include file='doc\CheckedListBox.uex' path='docs/doc[@for="CheckedListBox.DrawMode"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
[
Browsable(false), EditorBrowsable(EditorBrowsableState.Never),
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
]
public override DrawMode DrawMode {
get {
return DrawMode.Normal;
}
set {
}
}
/// <include file='doc\CheckedListBox.uex' path='docs/doc[@for="CheckedListBox.ItemHeight"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
[
Browsable(false), EditorBrowsable(EditorBrowsableState.Never),
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
]
public override int ItemHeight {
get {
// this should take FontHeight + buffer into Consideration.
return Font.Height + scaledListItemBordersHeight;
}
set {
}
}
/// <include file='doc\CheckedListBox.uex' path='docs/doc[@for="CheckedListBox.Items"]/*' />
/// <devdoc>
/// Collection of items in this listbox.
/// </devdoc>
[
SRCategory(SR.CatData),
DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
Localizable(true),
SRDescription(SR.ListBoxItemsDescr),
Editor("System.Windows.Forms.Design.ListControlStringCollectionEditor, " + AssemblyRef.SystemDesign, typeof(UITypeEditor))
]
new public CheckedListBox.ObjectCollection Items {
get {
return(CheckedListBox.ObjectCollection)base.Items;
}
}
// Computes the maximum width of all items in the ListBox
//
internal override int MaxItemWidth {
get {
// Overridden to include the size of the checkbox
// Allows for one pixel either side of the checkbox, plus another 1 pixel buffer = 3 pixels
//
return base.MaxItemWidth + idealCheckSize + scaledListItemPaddingBuffer;
}
}
/// <include file='doc\CheckedListBox.uex' path='docs/doc[@for="CheckedListBox.SelectionMode"]/*' />
/// <devdoc>
/// For CheckedListBoxes, multi-selection is not supported. You can set
/// selection to be able to select one item or no items.
/// </devdoc>
public override SelectionMode SelectionMode {
get {
return base.SelectionMode;
}
set {
//valid values are 0x0 to 0x3
if (!ClientUtils.IsEnumValid(value, (int)value, (int)SelectionMode.None, (int)SelectionMode.MultiExtended)){
throw new InvalidEnumArgumentException("value", (int)value, typeof(SelectionMode));
}
if (value != SelectionMode.One
&& value != SelectionMode.None) {
throw new ArgumentException(SR.GetString(SR.CheckedListBoxInvalidSelectionMode));
}
if (value != SelectionMode) {
base.SelectionMode = value;
RecreateHandle();
}
}
}
/// <include file='doc\CheckedListBox.uex' path='docs/doc[@for="CheckedListBox.ThreeDCheckBoxes"]/*' />
/// <devdoc>
/// Indicates if the CheckBoxes should show up as flat or 3D in appearance.
/// </devdoc>
[
SRCategory(SR.CatAppearance),
DefaultValue(false),
SRDescription(SR.CheckedListBoxThreeDCheckBoxesDescr)
]
public bool ThreeDCheckBoxes {
get {
return !flat;
}
set {
// change the style and repaint.
//
if (flat == value) {
flat = !value;
// see if we have some items, and only invalidate if we do.
CheckedListBox.ObjectCollection items = (CheckedListBox.ObjectCollection) Items;
if ((items != null) && (items.Count > 0)) {
this.Invalidate();
}
}
}
}
/// <devdoc>
/// Determines whether to use compatible text rendering engine (GDI+) or not (GDI).
/// </devdoc>
[
DefaultValue(false),
SRCategory(SR.CatBehavior),
SRDescription(SR.UseCompatibleTextRenderingDescr)
]
public bool UseCompatibleTextRendering {
get{
return base.UseCompatibleTextRenderingInt;
}
set{
base.UseCompatibleTextRenderingInt = value;
}
}
/// <devdoc>
/// Determines whether the control supports rendering text using GDI+ and GDI.
/// This is provided for container controls to iterate through its children to set UseCompatibleTextRendering to the same
/// value if the child control supports it.
/// </devdoc>
internal override bool SupportsUseCompatibleTextRendering {
get {
return true;
}
}
/// <include file='doc\CheckedListBox.uex' path='docs/doc[@for="CheckedListBox.ValueMember"]/*' />
/// <devdoc>
/// CheckedListBox ValueMember.
/// </devdoc>
/// <internalonly/><hideinheritance/>
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
public new string ValueMember {
get {
return base.ValueMember;
}
set {
base.ValueMember = value;
}
}
/// <include file='doc\CheckedListBox.uex' path='docs/doc[@for="ComboBox.DataSourceChanged"]/*' />
/// <internalonly/>
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
new public event EventHandler DataSourceChanged {
add {
base.DataSourceChanged += value;
}
remove {
base.DataSourceChanged -= value;
}
}
/// <include file='doc\CheckedListBox.uex' path='docs/doc[@for="ComboBox.DisplayMemberChanged"]/*' />
/// <internalonly/>
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
new public event EventHandler DisplayMemberChanged {
add {
base.DisplayMemberChanged += value;
}
remove {
base.DisplayMemberChanged -= value;
}
}
/// <include file='doc\CheckedListBox.uex' path='docs/doc[@for="CheckedListBox.ItemCheck"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
[SRCategory(SR.CatBehavior), SRDescription(SR.CheckedListBoxItemCheckDescr)]
public event ItemCheckEventHandler ItemCheck {
add {
onItemCheck += value;
}
remove {
onItemCheck -= value;
}
}
/// <include file='doc\CheckedListBox.uex' path='docs/doc[@for="CheckedListBox.Click"]/*' />
/// <internalonly/><hideinheritance/>
[Browsable(true), EditorBrowsable(EditorBrowsableState.Always)]
public new event EventHandler Click {
add {
base.Click += value;
}
remove {
base.Click -= value;
}
}
/// <include file='doc\CheckedListBox.uex' path='docs/doc[@for="CheckedListBox.MouseClick"]/*' />
/// <internalonly/><hideinheritance/>
[Browsable(true), EditorBrowsable(EditorBrowsableState.Always)]
public new event MouseEventHandler MouseClick {
add {
base.MouseClick += value;
}
remove {
base.MouseClick -= value;
}
}
/// <include file='doc\CheckedListBox.uex' path='docs/doc[@for="CheckedListBox.DrawItem"]/*' />
/// <internalonly/><hideinheritance/>
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
public new event DrawItemEventHandler DrawItem {
add {
base.DrawItem += value;
}
remove {
base.DrawItem -= value;
}
}
/// <include file='doc\CheckedListBox.uex' path='docs/doc[@for="CheckedListBox.MeasureItem"]/*' />
/// <internalonly/><hideinheritance/>
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
public new event MeasureItemEventHandler MeasureItem {
add {
base.MeasureItem += value;
}
remove {
base.MeasureItem -= value;
}
}
/// <include file='doc\CheckedListBox.uex' path='docs/doc[@for="CheckedListBox.Padding"]/*' />
/// <devdoc>
/// <para>
/// <para>[To be supplied.]</para>
/// </para>
/// </devdoc>
[
Browsable(false),
EditorBrowsable(EditorBrowsableState.Never),
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
]
public new Padding Padding {
get { return base.Padding; }
set { base.Padding = value;}
}
/// <include file='doc\CheckedListBox.uex' path='docs/doc[@for="ComboBox.ValueMemberChanged"]/*' />
/// <internalonly/>
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
new public event EventHandler ValueMemberChanged {
add {
base.ValueMemberChanged += value;
}
remove {
base.ValueMemberChanged -= value;
}
}
/// <include file='doc\CheckedListBox.uex' path='docs/doc[@for="CheckedListBox.CreateAccessibilityInstance"]/*' />
/// <internalonly/>
/// <devdoc>
/// Constructs the new instance of the accessibility object for this control. Subclasses
/// should not call base.CreateAccessibilityObject.
/// </devdoc>
protected override AccessibleObject CreateAccessibilityInstance() {
return new CheckedListBoxAccessibleObject(this);
}
/// <include file='doc\CheckedListBox.uex' path='docs/doc[@for="CheckedListBox.CreateItemCollection"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
protected override ListBox.ObjectCollection CreateItemCollection() {
return new ObjectCollection(this);
}
/// <include file='doc\CheckedListBox.uex' path='docs/doc[@for="CheckedListBox.GetItemCheckState"]/*' />
/// <devdoc>
/// Gets the check value of the current item. This value will be from the
/// System.Windows.Forms.CheckState enumeration.
/// </devdoc>
public CheckState GetItemCheckState(int index) {
if (index < 0 || index >= Items.Count)
throw new ArgumentOutOfRangeException("index", SR.GetString(SR.InvalidArgument, "index", (index).ToString(CultureInfo.CurrentCulture)));
return CheckedItems.GetCheckedState(index);
}
/// <include file='doc\CheckedListBox.uex' path='docs/doc[@for="CheckedListBox.GetItemChecked"]/*' />
/// <devdoc>
/// Indicates if the given item is, in any way, shape, or form, checked.
/// This will return true if the item is fully or indeterminately checked.
/// </devdoc>
public bool GetItemChecked(int index) {
return(GetItemCheckState(index) != CheckState.Unchecked);
}
/// <include file='doc\CheckedListBox.uex' path='docs/doc[@for="CheckedListBox.InvalidateItem"]/*' />
/// <devdoc>
/// Invalidates the given item in the listbox
/// </devdoc>
/// <internalonly/>
private void InvalidateItem(int index) {
if (IsHandleCreated) {
NativeMethods.RECT rect = new NativeMethods.RECT();
SendMessage(NativeMethods.LB_GETITEMRECT, index, ref rect);
SafeNativeMethods.InvalidateRect(new HandleRef(this, Handle), ref rect, false);
}
}
/// <include file='doc\CheckedListBox.uex' path='docs/doc[@for="CheckedListBox.LbnSelChange"]/*' />
/// <devdoc>
/// A redirected LBN_SELCHANGE message notification.
/// </devdoc>
/// <internalonly/>
private void LbnSelChange() {
// prepare to change the selection. we'll fire an event for
// this. Note that we'll only change the selection when the
// user clicks again on a currently selected item, or when the
// user has CheckOnClick set to true. Otherwise
// just using the up and down arrows selects or unselects
// every item around town ...
//
// Get the index of the item to check/uncheck
int index = SelectedIndex;
// make sure we have a valid index, otherwise we're going to
// fail ahead...
if (index < 0 || index >= Items.Count)
return;
// Send an accessibility notification
//
AccessibilityNotifyClients(AccessibleEvents.Focus, index);
AccessibilityNotifyClients(AccessibleEvents.Selection, index);
//# VS7 86
if (!killnextselect && (index == lastSelected || checkOnClick == true)) {
CheckState currentValue = CheckedItems.GetCheckedState(index);
CheckState newValue = (currentValue != CheckState.Unchecked)
? CheckState.Unchecked
: CheckState.Checked;
ItemCheckEventArgs itemCheckEvent = new ItemCheckEventArgs(index, newValue, currentValue);
OnItemCheck(itemCheckEvent);
// take whatever value the user set, and set that as the value.
//
CheckedItems.SetCheckedState(index, itemCheckEvent.NewValue);
// Send accessibility notifications for state change
if (AccessibilityImprovements.Level1) {
AccessibilityNotifyClients(AccessibleEvents.StateChange, index);
AccessibilityNotifyClients(AccessibleEvents.NameChange, index);
}
}
lastSelected = index;
InvalidateItem(index);
}
/// <include file='doc\CheckedListBox.uex' path='docs/doc[@for="CheckedListBox.OnClick"]/*' />
/// <devdoc>
/// Ensures that mouse clicks can toggle...
/// </devdoc>
/// <internalonly/>
protected override void OnClick(EventArgs e) {
killnextselect = false;
base.OnClick(e);
}
/// <include file='doc\CheckedListBox.uex' path='docs/doc[@for="CheckedListBox.OnHandleCreated"]/*' />
/// <devdoc>
/// When the handle is created we can dump any cached item-check pairs.
/// </devdoc>
/// <internalonly/>
protected override void OnHandleCreated(EventArgs e) {
base.OnHandleCreated(e);
SendMessage(NativeMethods.LB_SETITEMHEIGHT, 0, ItemHeight);
}
/// <include file='doc\CheckedListBox.uex' path='docs/doc[@for="CheckedListBox.OnDrawItem"]/*' />
/// <devdoc>
/// Actually goes and fires the drawItem event. Inheriting controls
/// should use this to know when the event is fired [this is preferable to
/// adding an event handler yourself for this event]. They should,
/// however, remember to call base.OnDrawItem(e); to ensure the event is
/// still fired to external listeners
/// </devdoc>
protected override void OnDrawItem(DrawItemEventArgs e) {
object item;
if (Font.Height < 0)
{
this.Font = Control.DefaultFont;
}
if (e.Index >= 0) {
if (e.Index < Items.Count) {
item = Items[e.Index];
}
else {
// If the item is not part of our collection, we will just
// get the string for it and display it.
//
item = NativeGetItemText(e.Index);
}
Rectangle bounds = e.Bounds;
int height = this.ItemHeight;
// set up the appearance of the checkbox
//
ButtonState state = ButtonState.Normal;
if (flat) {
state |= ButtonState.Flat;
}
if (e.Index < Items.Count) {
switch (CheckedItems.GetCheckedState(e.Index)) {
case CheckState.Checked:
state |= ButtonState.Checked;
break;
case CheckState.Indeterminate:
state |= ButtonState.Checked | ButtonState.Inactive;
break;
}
}
// If we are drawing themed CheckBox .. get the size from renderer..
// the Renderer might return a different size in different DPI modes..
if (Application.RenderWithVisualStyles) {
VisualStyles.CheckBoxState cbState = CheckBoxRenderer.ConvertFromButtonState(state, false, ((e.State & DrawItemState.HotLight) == DrawItemState.HotLight));
idealCheckSize = (int)(CheckBoxRenderer.GetGlyphSize(e.Graphics, cbState, HandleInternal)).Width;
}
// Determine bounds for the checkbox
//
int centeringFactor = Math.Max((height - idealCheckSize) / 2, 0);
// Keep the checkbox within the item's upper and lower bounds
if (centeringFactor + idealCheckSize > bounds.Height) {
centeringFactor = bounds.Height - idealCheckSize;
}
Rectangle box = new Rectangle(bounds.X + scaledListItemStartPosition,
bounds.Y + centeringFactor,
idealCheckSize,
idealCheckSize);
if (RightToLeft == RightToLeft.Yes) {
// For a RightToLeft checked list box, we want the checkbox
// to be drawn at the right.
// So we override the X position.
box.X = bounds.X + bounds.Width - idealCheckSize - scaledListItemStartPosition;
}
// Draw the checkbox.
//
if (Application.RenderWithVisualStyles) {
VisualStyles.CheckBoxState cbState = CheckBoxRenderer.ConvertFromButtonState(state, false, ((e.State & DrawItemState.HotLight) == DrawItemState.HotLight));
CheckBoxRenderer.DrawCheckBox(e.Graphics, new Point(box.X, box.Y), cbState, HandleInternal);
}
else {
ControlPaint.DrawCheckBox(e.Graphics, box, state);
}
// Determine bounds for the text portion of the item
//
Rectangle textBounds = new Rectangle(
bounds.X + idealCheckSize + (scaledListItemStartPosition * 2),
bounds.Y,
bounds.Width - (idealCheckSize + (scaledListItemStartPosition * 2)),
bounds.Height);
if (RightToLeft == RightToLeft.Yes) {
// For a RightToLeft checked list box, we want the text
// to be drawn at the left.
// So we override the X position.
textBounds.X = bounds.X;
}
// Setup text font, color, and text
//
string text = "";
Color backColor = (SelectionMode != SelectionMode.None) ? e.BackColor : BackColor;
Color foreColor = (SelectionMode != SelectionMode.None) ? e.ForeColor : ForeColor;
if (!Enabled) {
foreColor = SystemColors.GrayText;
}
Font font = Font;
text = GetItemText(item);
if (SelectionMode != SelectionMode.None && (e.State & DrawItemState.Selected) == DrawItemState.Selected) {
if (Enabled)
{
backColor = SystemColors.Highlight;
foreColor = SystemColors.HighlightText;
}
else
{
backColor = SystemColors.InactiveBorder;
foreColor = SystemColors.GrayText;
}
}
// Draw the text
//
// Due to some sort of unpredictable painting optimization in the Windows ListBox control,
// we need to always paint the background rectangle for the current line.
using (Brush b = new SolidBrush(backColor)) {
e.Graphics.FillRectangle(b, textBounds);
}
Rectangle stringBounds = new Rectangle(
textBounds.X + BORDER_SIZE,
textBounds.Y,
textBounds.Width - BORDER_SIZE,
textBounds.Height - 2 * BORDER_SIZE); // minus borders
if( UseCompatibleTextRendering ){
using (StringFormat format = new StringFormat()) {
if (UseTabStops) {
// Set tab stops so it looks similar to a ListBox, at least with the default font size.
float tabDistance = 3.6f * Font.Height; // about 7 characters
float[] tabStops = new float[15];
float tabOffset = -(idealCheckSize + (scaledListItemStartPosition * 2));
for (int i = 1; i < tabStops.Length; i++)
tabStops[i] = tabDistance;
//(bug 111825)
if (Math.Abs(tabOffset) < tabDistance) {
tabStops[0] = tabDistance +tabOffset;
}
else {
tabStops[0] = tabDistance;
}
format.SetTabStops(0, tabStops);
}
else if (UseCustomTabOffsets) {
//Set TabStops to userDefined values
int wpar = CustomTabOffsets.Count;
float[] tabStops = new float[wpar];
CustomTabOffsets.CopyTo(tabStops, 0);
format.SetTabStops(0, tabStops);
}
// Adjust string format for Rtl controls
if (RightToLeft == RightToLeft.Yes) {
format.FormatFlags |= StringFormatFlags.DirectionRightToLeft;
}
// ListBox doesn't word-wrap its items, so neither should CheckedListBox
//
format.FormatFlags |= StringFormatFlags.NoWrap;
// VSWhidbey 95774: Set Trimming to None to prevent DrawString() from whacking the entire
// string when there is only one character per tab included in the string.
format.Trimming = StringTrimming.None;
// Do actual drawing
using (SolidBrush brush = new SolidBrush(foreColor)) {
e.Graphics.DrawString(text, font, brush, stringBounds, format);
}
}
}
else{
TextFormatFlags flags = TextFormatFlags.Default;
flags |= TextFormatFlags.NoPrefix;
if (UseTabStops || UseCustomTabOffsets) {
flags |= TextFormatFlags.ExpandTabs;
}
// Adjust string format for Rtl controls
if (RightToLeft == RightToLeft.Yes) {
flags |= TextFormatFlags.RightToLeft;
flags |= TextFormatFlags.Right;
}
// Do actual drawing
TextRenderer.DrawText(e.Graphics, text, font, stringBounds, foreColor, flags );
}
// Draw the focus rect if required
//
if ((e.State & DrawItemState.Focus) == DrawItemState.Focus &&
(e.State & DrawItemState.NoFocusRect) != DrawItemState.NoFocusRect) {
ControlPaint.DrawFocusRectangle(e.Graphics, textBounds, foreColor, backColor);
}
}
if (Items.Count == 0 && AccessibilityImprovements.Level3 &&
e.Bounds.Width > 2 * BORDER_SIZE && e.Bounds.Height > 2 * BORDER_SIZE) {
Color backColor = (SelectionMode != SelectionMode.None) ? e.BackColor : BackColor;
Rectangle bounds = e.Bounds;
Rectangle emptyRectangle = new Rectangle(
bounds.X + BORDER_SIZE,
bounds.Y,
bounds.Width - BORDER_SIZE,
bounds.Height - 2 * BORDER_SIZE); // Upper and lower borders.
if (Focused) {
// Draw focus rectangle for virtual first item in the list if there are no items in the list.
Color foreColor = (SelectionMode != SelectionMode.None) ? e.ForeColor : ForeColor;
if (!Enabled) {
foreColor = SystemColors.GrayText;
}
ControlPaint.DrawFocusRectangle(e.Graphics, emptyRectangle, foreColor, backColor);
}
else if (!Application.RenderWithVisualStyles) {
// If VisualStyles are off, rectangle needs to be explicitly erased, when focus is lost.
// This is because of persisting empty focus rectangle when VisualStyles are off.
using (Brush brush = new SolidBrush(backColor)) {
e.Graphics.FillRectangle(brush, emptyRectangle);
}
}
}
}
/// <include file='doc\CheckedListBox.uex' path='docs/doc[@for="CheckedListBox.OnBackColorChanged"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
protected override void OnBackColorChanged(EventArgs e) {
base.OnBackColorChanged(e);
if (IsHandleCreated) {
SafeNativeMethods.InvalidateRect(new HandleRef(this, Handle), null, true);
}
}
/// <include file='doc\CheckedListBox.uex' path='docs/doc[@for="CheckedListBox.OnFontChanged"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
protected override void OnFontChanged(EventArgs e) {
// Update the item height
//
if (IsHandleCreated) {
SendMessage(NativeMethods.LB_SETITEMHEIGHT, 0, ItemHeight);
}
// The base OnFontChanged will adjust the height of the CheckedListBox accordingly
//
base.OnFontChanged(e);
}
/// <include file='doc\CheckedListBox.uex' path='docs/doc[@for="CheckedListBox.OnKeyPress"]/*' />
/// <devdoc>
/// This is the code that actually fires the "keyPress" event. The Checked
/// ListBox overrides this to look for space characters, since we
/// want to use those to check or uncheck items periodically. Don't
/// forget to call base.OnKeyPress() to ensure that KeyPrese events
/// are correctly fired for all other keys.
/// </devdoc>
/// <internalonly/>
protected override void OnKeyPress(KeyPressEventArgs e) {
if (e.KeyChar == ' ' && SelectionMode != SelectionMode.None) {
LbnSelChange();
}
if (FormattingEnabled) //We want to fire KeyPress only when FormattingEnabled (this is a whidbey property)
{
base.OnKeyPress(e);
}
}
/// <include file='doc\CheckedListBox.uex' path='docs/doc[@for="CheckedListBox.OnItemCheck"]/*' />
/// <devdoc>
/// This is the code that actually fires the itemCheck event. Don't
/// forget to call base.onItemCheck() to ensure that itemCheck vents
/// are correctly fired for all other keys.
/// </devdoc>
/// <internalonly/>
protected virtual void OnItemCheck(ItemCheckEventArgs ice) {
if (onItemCheck != null) onItemCheck(this, ice);
}
/// <include file='doc\CheckedListBox.uex' path='docs/doc[@for="CheckedListBox.OnMeasureItem"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
protected override void OnMeasureItem(MeasureItemEventArgs e) {
base.OnMeasureItem(e);
// we'll use the ideal checkbox size plus enough for padding on the top
// and bottom
//
if (e.ItemHeight < idealCheckSize + 2) {
e.ItemHeight = idealCheckSize + 2;
}
}
/// <include file='doc\CheckedListBox.uex' path='docs/doc[@for="CheckedListBox.OnSelectedIndexChanged"]/*' />
/// <devdoc>
/// Actually goes and fires the selectedIndexChanged event. Inheriting controls
/// should use this to know when the event is fired [this is preferable to
/// adding an event handler on yourself for this event]. They should,
/// however, remember to call base.OnSelectedIndexChanged(e); to ensure the event is
/// still fired to external listeners
/// </devdoc>
protected override void OnSelectedIndexChanged(EventArgs e) {
base.OnSelectedIndexChanged(e);
lastSelected = SelectedIndex;
}
/// <include file='doc\CheckedListBox.uex' path='docs/doc[@for="CheckedListBox.RefreshItems"]/*' />
/// <devdoc>
/// Reparses the objects, getting new text strings for them.
/// </devdoc>
/// <internalonly/>
protected override void RefreshItems() {
Hashtable savedcheckedItems = new Hashtable();
for (int i =0; i < Items.Count ; i ++)
{
savedcheckedItems[i] = CheckedItems.GetCheckedState(i);
}
//call the base
base.RefreshItems();
// restore the checkedItems...
for (int j =0; j < Items.Count; j++)
{
CheckedItems.SetCheckedState(j, (CheckState)savedcheckedItems[j]);
}
}
/// <include file='doc\CheckedListBox.uex' path='docs/doc[@for="CheckedListBox.SetItemCheckState"]/*' />
/// <devdoc>
/// Sets the checked value of the given item. This value should be from
/// the System.Windows.Forms.CheckState enumeration.
/// </devdoc>
public void SetItemCheckState(int index, CheckState value) {
if (index < 0 || index >= Items.Count) {
throw new ArgumentOutOfRangeException("index", SR.GetString(SR.InvalidArgument, "index", (index).ToString(CultureInfo.CurrentCulture)));
}
// valid values are 0-2 inclusive.
if (!ClientUtils.IsEnumValid(value,(int)value, (int)CheckState.Unchecked, (int)CheckState.Indeterminate)){
throw new InvalidEnumArgumentException("value", (int)value, typeof(CheckState));
}
CheckState currentValue = CheckedItems.GetCheckedState(index);
if (value != currentValue) {
ItemCheckEventArgs itemCheckEvent = new ItemCheckEventArgs(index, value, currentValue);
OnItemCheck(itemCheckEvent);
if (itemCheckEvent.NewValue != currentValue) {
CheckedItems.SetCheckedState(index, itemCheckEvent.NewValue);
InvalidateItem(index);
}
}
}
/// <include file='doc\CheckedListBox.uex' path='docs/doc[@for="CheckedListBox.SetItemChecked"]/*' />
/// <devdoc>
/// Sets the checked value of the given item. This value should be a
/// boolean.
/// </devdoc>
public void SetItemChecked(int index, bool value) {
SetItemCheckState(index, value ? CheckState.Checked : CheckState.Unchecked);
}
/// <include file='doc\CheckedListBox.uex' path='docs/doc[@for="CheckedListBox.WmReflectCommand"]/*' />
/// <devdoc>
/// We need to get LBN_SELCHANGE notifications
/// </devdoc>
/// <internalonly/>
[
System.Security.Permissions.SecurityPermissionAttribute(System.Security.Permissions.SecurityAction.LinkDemand, Flags=System.Security.Permissions.SecurityPermissionFlag.UnmanagedCode)
]
protected override void WmReflectCommand(ref Message m) {
switch (NativeMethods.Util.HIWORD(m.WParam)) {
case NativeMethods.LBN_SELCHANGE:
LbnSelChange();
// finally, fire the OnSelectionChange event.
base.WmReflectCommand(ref m);
break;
case NativeMethods.LBN_DBLCLK:
// We want double-clicks to change the checkstate on each click - just like the CheckBox control
//
LbnSelChange();
base.WmReflectCommand(ref m);
break;
default:
base.WmReflectCommand(ref m);
break;
}
}
/// <include file='doc\CheckedListBox.uex' path='docs/doc[@for="CheckedListBox.WmReflectVKeyToItem"]/*' />
/// <devdoc>
/// Handle keyboard input to prevent arrow keys from toggling
/// checkboxes in CheckOnClick mode.
/// </devdoc>
/// <internalonly/>
private void WmReflectVKeyToItem(ref Message m) {
int keycode = NativeMethods.Util.LOWORD(m.WParam);
switch ((Keys)keycode) {
case Keys.Up:
case Keys.Down:
case Keys.PageUp:
case Keys.PageDown:
case Keys.Home:
case Keys.End:
case Keys.Left:
case Keys.Right:
killnextselect = true;
break;
default:
killnextselect = false;
break;
}
m.Result = NativeMethods.InvalidIntPtr;
}
/// <include file='doc\CheckedListBox.uex' path='docs/doc[@for="CheckedListBox.WndProc"]/*' />
/// <devdoc>
/// The listbox's window procedure. Inheriting classes can override this
/// to add extra functionality, but should not forget to call
/// base.wndProc(m); to ensure the button continues to function properly.
/// </devdoc>
/// <internalonly/>
[SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.UnmanagedCode)]
protected override void WndProc(ref Message m) {
switch (m.Msg) {
case NativeMethods.WM_REFLECT + NativeMethods.WM_CHARTOITEM:
m.Result = NativeMethods.InvalidIntPtr;
break;
case NativeMethods.WM_REFLECT + NativeMethods.WM_VKEYTOITEM:
WmReflectVKeyToItem(ref m);
break;
default:
if (m.Msg == LBC_GETCHECKSTATE) {
int item = unchecked( (int) (long)m.WParam);
if (item < 0 || item >= Items.Count) {
m.Result = (IntPtr)LB_ERROR;
}
else {
m.Result = (IntPtr)(GetItemChecked(item) ? LB_CHECKED : LB_UNCHECKED);
}
}
else if (m.Msg == LBC_SETCHECKSTATE) {
int item = unchecked( (int) (long)m.WParam);
int state = unchecked( (int) (long)m.LParam);
if (item < 0 || item >= Items.Count || (state != LB_CHECKED && state != LB_UNCHECKED)) {
m.Result = IntPtr.Zero;
}
else {
SetItemChecked(item, (state == LB_CHECKED));
m.Result = (IntPtr)1;
}
}
else {
base.WndProc(ref m);
}
break;
}
}
/// <include file='doc\CheckedListBox.uex' path='docs/doc[@for="CheckedListBox.ObjectCollection"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
new public class ObjectCollection : ListBox.ObjectCollection {
private CheckedListBox owner;
/// <include file='doc\CheckedListBox.uex' path='docs/doc[@for="CheckedListBox.ObjectCollection.ObjectCollection"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public ObjectCollection(CheckedListBox owner)
: base(owner) {
this.owner = owner;
}
/// <include file='doc\CheckedListBox.uex' path='docs/doc[@for="CheckedListBox.ObjectCollection.Add"]/*' />
/// <devdoc>
/// Lets the user add an item to the listbox with the given initial value
/// for the Checked portion of the item.
/// </devdoc>
public int Add(object item, bool isChecked) {
return Add(item, isChecked ? CheckState.Checked : CheckState.Unchecked);
}
/// <include file='doc\CheckedListBox.uex' path='docs/doc[@for="CheckedListBox.ObjectCollection.Add1"]/*' />
/// <devdoc>
/// Lets the user add an item to the listbox with the given initial value
/// for the Checked portion of the item.
/// </devdoc>
public int Add(object item, CheckState check) {
//validate the enum that's passed in here
//
// Valid values are 0-2 inclusive.
if (!ClientUtils.IsEnumValid(check, (int)check, (int)CheckState.Unchecked, (int)CheckState.Indeterminate)){
throw new InvalidEnumArgumentException("value", (int)check, typeof(CheckState));
}
int index = base.Add(item);
owner.SetItemCheckState(index, check);
return index;
}
}
/// <include file='doc\CheckedListBox.uex' path='docs/doc[@for="CheckedListBox.CheckedIndexCollection"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public class CheckedIndexCollection : IList {
private CheckedListBox owner;
internal CheckedIndexCollection(CheckedListBox owner) {
this.owner = owner;
}
/// <include file='doc\CheckedListBox.uex' path='docs/doc[@for="CheckedListBox.CheckedIndexCollection.Count"]/*' />
/// <devdoc>
/// Number of current checked items.
/// </devdoc>
public int Count {
get {
return owner.CheckedItems.Count;
}
}
/// <include file='doc\CheckedListBox.uex' path='docs/doc[@for="CheckedIndexCollection.ICollection.SyncRoot"]/*' />
/// <internalonly/>
object ICollection.SyncRoot {
get {
return this;
}
}
/// <include file='doc\CheckedListBox.uex' path='docs/doc[@for="CheckedIndexCollection.ICollection.IsSynchronized"]/*' />
/// <internalonly/>
bool ICollection.IsSynchronized {
get {
return false;
}
}
/// <include file='doc\CheckedListBox.uex' path='docs/doc[@for="CheckedIndexCollection.IList.IsFixedSize"]/*' />
/// <internalonly/>
bool IList.IsFixedSize {
get {
return true;
}
}
/// <include file='doc\CheckedListBox.uex' path='docs/doc[@for="CheckedListBox.CheckedIndexCollection.IsReadOnly"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public bool IsReadOnly {
get {
return true;
}
}
/// <include file='doc\CheckedListBox.uex' path='docs/doc[@for="CheckedListBox.CheckedIndexCollection.this"]/*' />
/// <devdoc>
/// Retrieves the specified checked item.
/// </devdoc>
[Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public int this[int index] {
get {
object identifier = InnerArray.GetEntryObject(index, CheckedItemCollection.AnyMask);
return InnerArray.IndexOfIdentifier(identifier, 0);
}
}
/// <include file='doc\CheckedListBox.uex' path='docs/doc[@for="CheckedIndexCollection.IList.this"]/*' />
/// <internalonly/>
object IList.this[int index] {
get {
return this[index];
}
set {
throw new NotSupportedException(SR.GetString(SR.CheckedListBoxCheckedIndexCollectionIsReadOnly));
}
}
/// <include file='doc\CheckedListBox.uex' path='docs/doc[@for="CheckedIndexCollection.IList.Add"]/*' />
/// <internalonly/>
int IList.Add(object value) {
throw new NotSupportedException(SR.GetString(SR.CheckedListBoxCheckedIndexCollectionIsReadOnly));
}
/// <include file='doc\CheckedListBox.uex' path='docs/doc[@for="CheckedIndexCollection.IList.Clear"]/*' />
/// <internalonly/>
void IList.Clear() {
throw new NotSupportedException(SR.GetString(SR.CheckedListBoxCheckedIndexCollectionIsReadOnly));
}
/// <include file='doc\CheckedListBox.uex' path='docs/doc[@for="CheckedIndexCollection.IList.Insert"]/*' />
/// <internalonly/>
void IList.Insert(int index, object value) {
throw new NotSupportedException(SR.GetString(SR.CheckedListBoxCheckedIndexCollectionIsReadOnly));
}
/// <include file='doc\CheckedListBox.uex' path='docs/doc[@for="CheckedIndexCollection.IList.Remove"]/*' />
/// <internalonly/>
void IList.Remove(object value) {
throw new NotSupportedException(SR.GetString(SR.CheckedListBoxCheckedIndexCollectionIsReadOnly));
}
/// <include file='doc\CheckedListBox.uex' path='docs/doc[@for="CheckedIndexCollection.IList.RemoveAt"]/*' />
/// <internalonly/>
void IList.RemoveAt(int index) {
throw new NotSupportedException(SR.GetString(SR.CheckedListBoxCheckedIndexCollectionIsReadOnly));
}
/// <include file='doc\CheckedListBox.uex' path='docs/doc[@for="CheckedListBox.CheckedIndexCollection.Contains"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public bool Contains(int index) {
return (IndexOf(index) != -1);
}
/// <include file='doc\CheckedListBox.uex' path='docs/doc[@for="CheckedIndexCollection.IList.Contains"]/*' />
/// <internalonly/>
bool IList.Contains(object index) {
if (index is Int32) {
return Contains((int)index);
}
else {
return false;
}
}
/// <include file='doc\CheckedListBox.uex' path='docs/doc[@for="CheckedListBox.CheckedIndexCollection.CopyTo"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public void CopyTo(Array dest, int index) {
int cnt = owner.CheckedItems.Count;
for (int i = 0; i < cnt; i++) {
dest.SetValue(this[i], i + index);
}
}
/// <devdoc>
/// This is the item array that stores our data. We share this backing store
/// with the main object collection.
/// </devdoc>
private ItemArray InnerArray {
get {
return ((ObjectCollection)owner.Items).InnerArray;
}
}
/// <include file='doc\CheckedListBox.uex' path='docs/doc[@for="CheckedListBox.CheckedIndexCollection.GetEnumerator"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public IEnumerator GetEnumerator() {
int[] indices = new int[this.Count];
CopyTo(indices, 0);
return indices.GetEnumerator();
}
/// <include file='doc\CheckedListBox.uex' path='docs/doc[@for="CheckedListBox.CheckedIndexCollection.IndexOf"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public int IndexOf(int index) {
if (index >= 0 && index < owner.Items.Count) {
object value = InnerArray.GetEntryObject(index, 0);
return owner.CheckedItems.IndexOfIdentifier(value);
}
return -1;
}
/// <include file='doc\CheckedListBox.uex' path='docs/doc[@for="CheckedIndexCollection.IList.IndexOf"]/*' />
/// <internalonly/>
int IList.IndexOf(object index) {
if (index is Int32) {
return IndexOf((int)index);
}
else {
return -1;
}
}
}
/// <include file='doc\CheckedListBox.uex' path='docs/doc[@for="CheckedListBox.CheckedItemCollection"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public class CheckedItemCollection : IList {
internal static int CheckedItemMask = ItemArray.CreateMask();
internal static int IndeterminateItemMask = ItemArray.CreateMask();
internal static int AnyMask = CheckedItemMask | IndeterminateItemMask;
private CheckedListBox owner;
internal CheckedItemCollection(CheckedListBox owner) {
this.owner = owner;
}
/// <include file='doc\CheckedListBox.uex' path='docs/doc[@for="CheckedListBox.CheckedItemCollection.Count"]/*' />
/// <devdoc>
/// Number of current checked items.
/// </devdoc>
public int Count {
get {
return InnerArray.GetCount(AnyMask);
}
}
/// <devdoc>
/// This is the item array that stores our data. We share this backing store
/// with the main object collection.
/// </devdoc>
private ItemArray InnerArray {
get {
return ((ListBox.ObjectCollection)owner.Items).InnerArray;
}
}
/// <include file='doc\CheckedListBox.uex' path='docs/doc[@for="CheckedListBox.CheckedItemCollection.this"]/*' />
/// <devdoc>
/// Retrieves the specified checked item.
/// </devdoc>
[Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public object this[int index] {
get {
return InnerArray.GetItem(index, AnyMask);
}
set {
throw new NotSupportedException(SR.GetString(SR.CheckedListBoxCheckedItemCollectionIsReadOnly));
}
}
/// <include file='doc\CheckedListBox.uex' path='docs/doc[@for="CheckedItemCollection.ICollection.SyncRoot"]/*' />
/// <internalonly/>
object ICollection.SyncRoot {
get {
return this;
}
}
/// <include file='doc\CheckedListBox.uex' path='docs/doc[@for="CheckedItemCollection.ICollection.IsSynchronized"]/*' />
/// <internalonly/>
bool ICollection.IsSynchronized {
get {
return false;
}
}
/// <include file='doc\CheckedListBox.uex' path='docs/doc[@for="CheckedItemCollection.IList.IsFixedSize"]/*' />
/// <internalonly/>
bool IList.IsFixedSize {
get {
return true;
}
}
/// <include file='doc\CheckedListBox.uex' path='docs/doc[@for="CheckedListBox.CheckedItemCollection.IsReadOnly"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public bool IsReadOnly {
get {
return true;
}
}
/// <include file='doc\CheckedListBox.uex' path='docs/doc[@for="CheckedListBox.CheckedItemCollection.Contains"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public bool Contains(object item) {
return IndexOf(item) != -1;
}
/// <include file='doc\CheckedListBox.uex' path='docs/doc[@for="CheckedListBox.CheckedItemCollection.IndexOf"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public int IndexOf(object item) {
return InnerArray.IndexOf(item, AnyMask);
}
internal int IndexOfIdentifier(object item) {
return InnerArray.IndexOfIdentifier(item, AnyMask);
}
/// <include file='doc\CheckedListBox.uex' path='docs/doc[@for="CheckedItemCollection.IList.Add"]/*' />
/// <internalonly/>
int IList.Add(object value) {
throw new NotSupportedException(SR.GetString(SR.CheckedListBoxCheckedItemCollectionIsReadOnly));
}
/// <include file='doc\CheckedListBox.uex' path='docs/doc[@for="CheckedItemCollection.IList.Clear"]/*' />
/// <internalonly/>
void IList.Clear() {
throw new NotSupportedException(SR.GetString(SR.CheckedListBoxCheckedItemCollectionIsReadOnly));
}
/// <include file='doc\CheckedListBox.uex' path='docs/doc[@for="CheckedItemCollection.IList.Insert"]/*' />
/// <internalonly/>
void IList.Insert(int index, object value) {
throw new NotSupportedException(SR.GetString(SR.CheckedListBoxCheckedItemCollectionIsReadOnly));
}
/// <include file='doc\CheckedListBox.uex' path='docs/doc[@for="CheckedItemCollection.IList.Remove"]/*' />
/// <internalonly/>
void IList.Remove(object value) {
throw new NotSupportedException(SR.GetString(SR.CheckedListBoxCheckedItemCollectionIsReadOnly));
}
/// <include file='doc\CheckedListBox.uex' path='docs/doc[@for="CheckedItemCollection.IList.RemoveAt"]/*' />
/// <internalonly/>
void IList.RemoveAt(int index) {
throw new NotSupportedException(SR.GetString(SR.CheckedListBoxCheckedItemCollectionIsReadOnly));
}
/// <include file='doc\CheckedListBox.uex' path='docs/doc[@for="CheckedListBox.CheckedItemCollection.CopyTo"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public void CopyTo(Array dest, int index) {
int cnt = InnerArray.GetCount(AnyMask);
for (int i = 0; i < cnt; i++) {
dest.SetValue(InnerArray.GetItem(i, AnyMask), i + index);
}
}
/// <devdoc>
/// This method returns if the actual item index is checked. The index is the index to the MAIN
/// collection, not this one.
/// </devdoc>
internal CheckState GetCheckedState(int index) {
bool isChecked = InnerArray.GetState(index, CheckedItemMask);
bool isIndeterminate = InnerArray.GetState(index, IndeterminateItemMask);
Debug.Assert(!isChecked || !isIndeterminate, "Can't be both checked and indeterminate. Somebody broke our state.");
if (isIndeterminate) {
return CheckState.Indeterminate;
}
else if (isChecked) {
return CheckState.Checked;
}
return CheckState.Unchecked;
}
/// <include file='doc\CheckedListBox.uex' path='docs/doc[@for="CheckedListBox.CheckedItemCollection.GetEnumerator"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public IEnumerator GetEnumerator() {
return InnerArray.GetEnumerator(AnyMask, true);
}
/// <devdoc>
/// Same thing for GetChecked.
/// </devdoc>
internal void SetCheckedState(int index, CheckState value) {
bool isChecked;
bool isIndeterminate;
switch(value) {
case CheckState.Checked:
isChecked = true;
isIndeterminate = false;
break;
case CheckState.Indeterminate:
isChecked = false;
isIndeterminate = true;
break;
default:
isChecked = false;
isIndeterminate = false;
break;
}
bool wasChecked = InnerArray.GetState(index, CheckedItemMask);
bool wasIndeterminate = InnerArray.GetState(index, IndeterminateItemMask);
InnerArray.SetState(index, CheckedItemMask, isChecked);
InnerArray.SetState(index, IndeterminateItemMask, isIndeterminate);
if (wasChecked != isChecked || wasIndeterminate != isIndeterminate) {
// Raise a notify event that this item has changed.
owner.AccessibilityNotifyClients(AccessibleEvents.StateChange, index);
}
}
}
/// <include file='doc\CheckedListBox.uex' path='docs/doc[@for="CheckedListBox.CheckedListBoxAccessibleObject"]/*' />
/// <internalonly/>
/// <devdoc>
/// </devdoc>
[System.Runtime.InteropServices.ComVisible(true)]
internal class CheckedListBoxAccessibleObject : ControlAccessibleObject {
/// <include file='doc\CheckedListBox.uex' path='docs/doc[@for="CheckedListBox.CheckedListBoxAccessibleObject.CheckedListBoxAccessibleObject"]/*' />
/// <devdoc>
/// </devdoc>
public CheckedListBoxAccessibleObject(CheckedListBox owner) : base(owner) {
}
private CheckedListBox CheckedListBox {
get {
return (CheckedListBox)Owner;
}
}
/// <include file='doc\CheckedListBox.uex' path='docs/doc[@for="CheckedListBox.CheckedListBoxAccessibleObject.GetChild"]/*' />
/// <devdoc>
/// </devdoc>
public override AccessibleObject GetChild(int index) {
if (index >= 0 && index < CheckedListBox.Items.Count) {
return new CheckedListBoxItemAccessibleObject(this.CheckedListBox.GetItemText(CheckedListBox.Items[index]), index, this);
}
else {
return null;
}
}
/// <include file='doc\CheckedListBox.uex' path='docs/doc[@for="CheckedListBox.CheckedListBoxAccessibleObject.GetChildCount"]/*' />
/// <devdoc>
/// </devdoc>
public override int GetChildCount() {
return CheckedListBox.Items.Count;
}
public override AccessibleObject GetFocused() {
int index = CheckedListBox.FocusedIndex;
if (index >= 0) {
return GetChild(index);
}
return null;
}
public override AccessibleObject GetSelected() {
int index = CheckedListBox.SelectedIndex;
if (index >= 0) {
return GetChild(index);
}
return null;
}
public override AccessibleObject HitTest(int x, int y) {
// Within a child element?
//
int count = GetChildCount();
for(int index=0; index < count; ++index) {
AccessibleObject child = GetChild(index);
if (child.Bounds.Contains(x, y)) {
return child;
}
}
// Within the CheckedListBox bounds?
//
if (this.Bounds.Contains(x, y)) {
return this;
}
return null;
}
[SecurityPermission(SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode)]
public override AccessibleObject Navigate(AccessibleNavigation direction) {
if (GetChildCount() > 0) {
if (direction == AccessibleNavigation.FirstChild) {
return GetChild(0);
}
if (direction == AccessibleNavigation.LastChild) {
return GetChild(GetChildCount() - 1);
}
}
return base.Navigate(direction);
}
}
/// <include file='doc\CheckedListBox.uex' path='docs/doc[@for="CheckedListBox.CheckedListBoxItemAccessibleObject"]/*' />
/// <internalonly/>
/// <devdoc>
/// </devdoc>
[System.Runtime.InteropServices.ComVisible(true)]
internal class CheckedListBoxItemAccessibleObject : AccessibleObject {
private string name;
private int index;
private CheckedListBoxAccessibleObject parent;
public CheckedListBoxItemAccessibleObject(string name, int index, CheckedListBoxAccessibleObject parent) : base() {
this.name = name;
this.parent = parent;
this.index = index;
}
public override Rectangle Bounds {
get {
Rectangle rect = ParentCheckedListBox.GetItemRectangle(index);
// Translate rect to screen coordinates
//
NativeMethods.POINT pt = new NativeMethods.POINT(rect.X, rect.Y);
UnsafeNativeMethods.ClientToScreen(new HandleRef(ParentCheckedListBox, ParentCheckedListBox.Handle), pt);
return new Rectangle(pt.x, pt.y, rect.Width, rect.Height);
}
}
public override string DefaultAction {
get {
if (ParentCheckedListBox.GetItemChecked(index)) {
return SR.GetString(SR.AccessibleActionUncheck);
}
else {
return SR.GetString(SR.AccessibleActionCheck);
}
}
}
private CheckedListBox ParentCheckedListBox {
get {
return(CheckedListBox)parent.Owner;
}
}
public override string Name {
get {
return name;
}
set {
name = value;
}
}
public override AccessibleObject Parent {
[SecurityPermission(SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode)]
get {
return parent;
}
}
public override AccessibleRole Role {
get {
return AccessibleRole.CheckButton;
}
}
public override AccessibleStates State {
get {
AccessibleStates state = AccessibleStates.Selectable | AccessibleStates.Focusable;
// Checked state
//
switch (ParentCheckedListBox.GetItemCheckState(index)) {
case CheckState.Checked:
state |= AccessibleStates.Checked;
break;
case CheckState.Indeterminate:
state |= AccessibleStates.Indeterminate;
break;
case CheckState.Unchecked:
// No accessible state corresponding to unchecked
break;
}
// Selected state
//
if (ParentCheckedListBox.SelectedIndex == index) {
state |= AccessibleStates.Selected | AccessibleStates.Focused;
}
if (AccessibilityImprovements.Level3 && ParentCheckedListBox.Focused && ParentCheckedListBox.SelectedIndex == -1) {
state |= AccessibleStates.Focused;
}
return state;
}
}
public override string Value {
[SecurityPermission(SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode)]
get {
return ParentCheckedListBox.GetItemChecked(index).ToString();
}
}
[SecurityPermission(SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode)]
public override void DoDefaultAction() {
ParentCheckedListBox.SetItemChecked(index, !ParentCheckedListBox.GetItemChecked(index));
}
[SecurityPermission(SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode)]
public override AccessibleObject Navigate(AccessibleNavigation direction) {
// Down/Next
//
if (direction == AccessibleNavigation.Down ||
direction == AccessibleNavigation.Next) {
if (index < parent.GetChildCount() - 1) {
return parent.GetChild(index + 1);
}
}
// Up/Previous
//
if (direction == AccessibleNavigation.Up ||
direction == AccessibleNavigation.Previous) {
if (index > 0) {
return parent.GetChild(index - 1);
}
}
return base.Navigate(direction);
}
[SecurityPermission(SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode)]
public override void Select(AccessibleSelection flags) {
try {
ParentCheckedListBox.AccessibilityObject.GetSystemIAccessibleInternal().accSelect((int) flags, index + 1);
} catch (ArgumentException) {
// In Everett, the CheckedListBox accessible children did not have any selection capability.
// In Whidbey, they delegate the selection capability to OLEACC.
// However, OLEACC does not deal w/ several Selection flags: ExtendSelection, AddSelection, RemoveSelection.
// OLEACC instead throws an ArgumentException.
// Since Whidbey API's should not throw an exception in places where Everett API's did not, we catch
// the ArgumentException and fail silently.
}
}
}
}
}
|