|
//------------------------------------------------------------------------------
// <copyright file="DropDownButton.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
namespace System.Windows.Forms.PropertyGridInternal {
using System.Diagnostics;
using System;
using System.Drawing;
using System.ComponentModel;
using System.Windows.Forms;
using System.Windows.Forms.VisualStyles;
using System.Windows.Forms.ButtonInternal;
using Microsoft.Win32;
internal sealed class DropDownButton : Button {
private bool useComboBoxTheme = false;
private bool ignoreMouse;
public DropDownButton() {
SetStyle(ControlStyles.Selectable, true);
SetAccessibleName();
}
// VSWhidbey 375220 - when the holder is open, we don't fire clicks
//
public bool IgnoreMouse {
get {
return ignoreMouse;
}
set {
ignoreMouse = value;
}
}
/// <summary>
/// Indicates whether or not the control supports UIA Providers via
/// IRawElementProviderFragment/IRawElementProviderFragmentRoot interfaces.
/// </summary>
internal override bool SupportsUiaProviders {
get {
return AccessibilityImprovements.Level3;
}
}
public bool UseComboBoxTheme {
set {
if (useComboBoxTheme != value) {
useComboBoxTheme = value;
if (AccessibilityImprovements.Level1) {
SetAccessibleName();
}
Invalidate();
}
}
}
protected override void OnClick(EventArgs e) {
if (!IgnoreMouse) {
base.OnClick(e);
}
}
protected override void OnMouseUp(MouseEventArgs e) {
if (!IgnoreMouse) {
base.OnMouseUp(e);
}
}
protected override void OnMouseDown(MouseEventArgs e) {
if (!IgnoreMouse) {
base.OnMouseDown(e);
}
}
protected override void OnPaint(PaintEventArgs pevent) {
base.OnPaint(pevent);
if (Application.RenderWithVisualStyles & useComboBoxTheme) {
ComboBoxState cbState = ComboBoxState.Normal;
if (base.MouseIsDown) {
cbState = ComboBoxState.Pressed;
}
else if (base.MouseIsOver) {
cbState = ComboBoxState.Hot;
}
Rectangle dropDownButtonRect = new Rectangle(0, 0, Width, Height);
if (cbState == ComboBoxState.Normal) {
pevent.Graphics.FillRectangle(SystemBrushes.Window, dropDownButtonRect);
}
if (!DpiHelper.EnableDpiChangedHighDpiImprovements) {
ComboBoxRenderer.DrawDropDownButton(pevent.Graphics, dropDownButtonRect, cbState);
}
else {
ComboBoxRenderer.DrawDropDownButtonForHandle(pevent.Graphics, dropDownButtonRect, cbState, this.HandleInternal);
}
if (AccessibilityImprovements.Level1) {
// Redraw focus cues
// For consistency with other PropertyGrid buttons, i.e. those opening system dialogs ("..."), that always show visual cues when focused,
// we need to do the same for this custom button, painted as ComboBox control part (drop-down).
if (Focused) {
dropDownButtonRect.Inflate(-1, -1);
ControlPaint.DrawFocusRectangle(pevent.Graphics, dropDownButtonRect, ForeColor, BackColor);
}
}
}
}
internal void PerformButtonClick() {
if (Visible && Enabled) {
OnClick(EventArgs.Empty);
}
}
private void SetAccessibleName() {
if (AccessibilityImprovements.Level1 && useComboBoxTheme) {
this.AccessibleName = SR.GetString(SR.PropertyGridDropDownButtonComboBoxAccessibleName);
}
else {
this.AccessibleName = SR.GetString(SR.PropertyGridDropDownButtonAccessibleName);
}
}
/// <summary>
/// Constructs the new instance of the accessibility object for this control.
/// </summary>
/// <returns>The accessibility object for this control.</returns>
protected override AccessibleObject CreateAccessibilityInstance() {
if (AccessibilityImprovements.Level3) {
return new DropDownButtonAccessibleObject(this);
}
return base.CreateAccessibilityInstance();
}
internal override ButtonBaseAdapter CreateStandardAdapter() {
return new DropDownButtonAdapter(this);
}
}
internal class DropDownButtonAdapter : ButtonStandardAdapter {
internal DropDownButtonAdapter(ButtonBase control) : base(control) {}
private void DDB_Draw3DBorder(System.Drawing.Graphics g, Rectangle r, bool raised) {
if (Control.BackColor != SystemColors.Control && SystemInformation.HighContrast) {
if (raised) {
Color c = ControlPaint.LightLight(Control.BackColor);
ControlPaint.DrawBorder(g, r,
c, 1, ButtonBorderStyle.Outset,
c, 1, ButtonBorderStyle.Outset,
c, 2, ButtonBorderStyle.Inset,
c, 2, ButtonBorderStyle.Inset);
}
else {
ControlPaint.DrawBorder(g, r, ControlPaint.Dark(Control.BackColor), ButtonBorderStyle.Solid);
}
}
else {
if (raised) {
Color c = ControlPaint.Light(Control.BackColor);
ControlPaint.DrawBorder(g, r,
c, 1, ButtonBorderStyle.Solid,
c, 1, ButtonBorderStyle.Solid,
Control.BackColor, 2, ButtonBorderStyle.Outset,
Control.BackColor, 2, ButtonBorderStyle.Outset);
Rectangle inside = r;
inside.Offset(1,1);
inside.Width -= 3;
inside.Height -= 3;
c = ControlPaint.LightLight(Control.BackColor);
ControlPaint.DrawBorder(g, inside,
c, 1, ButtonBorderStyle.Solid,
c, 1, ButtonBorderStyle.Solid,
c, 1, ButtonBorderStyle.None,
c, 1, ButtonBorderStyle.None);
}
else {
ControlPaint.DrawBorder(g, r, ControlPaint.Dark(Control.BackColor), ButtonBorderStyle.Solid);
}
}
}
internal override void PaintUp(PaintEventArgs pevent, CheckState state) {
base.PaintUp(pevent, state);
if (!Application.RenderWithVisualStyles) {
DDB_Draw3DBorder(pevent.Graphics, Control.ClientRectangle, true);
}
else {
Color c = SystemColors.Window;
Rectangle rect = Control.ClientRectangle;
rect.Inflate(0, -1);
ControlPaint.DrawBorder(pevent.Graphics, rect,
c, 1, ButtonBorderStyle.None,
c, 1, ButtonBorderStyle.None,
c, 1, ButtonBorderStyle.Solid,
c, 1, ButtonBorderStyle.None);
}
}
internal override void DrawImageCore(Graphics graphics, Image image, Rectangle imageBounds, Point imageStart, ButtonBaseAdapter.LayoutData layout) {
if (AccessibilityImprovements.Level3 && IsFilledWithHighlightColor && (Control.MouseIsOver || Control.Focused)) {
ControlPaint.DrawImageReplaceColor(graphics, image, imageBounds, Color.Black, SystemColors.HighlightText);
}
else {
ControlPaint.DrawImageReplaceColor(graphics, image, imageBounds, Color.Black, Control.ForeColor);
}
}
}
/// <summary>
/// Represents the accessibility object for the PropertyGrid DropDown button.
/// This DropDownButtonAccessibleObject is available in Level3 only.
/// </summary>
[Runtime.InteropServices.ComVisible(true)]
internal class DropDownButtonAccessibleObject : Control.ControlAccessibleObject {
private DropDownButton _owningDropDownButton;
private PropertyGridView _owningPropertyGrid;
/// <summary>
/// Constructs the new instance of DropDownButtonAccessibleObject.
/// </summary>
/// <param name="owningDropDownButton"></param>
public DropDownButtonAccessibleObject(DropDownButton owningDropDownButton) : base(owningDropDownButton) {
_owningDropDownButton = owningDropDownButton;
_owningPropertyGrid = owningDropDownButton.Parent as PropertyGridView;
UseStdAccessibleObjects(owningDropDownButton.Handle);
}
public override void DoDefaultAction() {
_owningDropDownButton.PerformButtonClick();
}
/// <summary>
/// Request to return the element in the specified direction.
/// </summary>
/// <param name="direction">Indicates the direction in which to navigate.</param>
/// <returns>Returns the element in the specified direction.</returns>
internal override UnsafeNativeMethods.IRawElementProviderFragment FragmentNavigate(UnsafeNativeMethods.NavigateDirection direction) {
if (direction == UnsafeNativeMethods.NavigateDirection.Parent &&
_owningPropertyGrid.SelectedGridEntry != null &&
_owningDropDownButton.Visible) {
return _owningPropertyGrid.SelectedGridEntry?.AccessibilityObject;
}
else if (direction == UnsafeNativeMethods.NavigateDirection.PreviousSibling) {
return _owningPropertyGrid.EditAccessibleObject;
}
return base.FragmentNavigate(direction);
}
/// <summary>
/// Returns the element that is the root node of this fragment of UI.
/// </summary>
internal override UnsafeNativeMethods.IRawElementProviderFragmentRoot FragmentRoot {
get {
return _owningPropertyGrid.AccessibilityObject;
}
}
/// <summary>
/// Request value of specified property from an element.
/// </summary>
/// <param name="propertyId">Identifier indicating the property to return</param>
/// <returns>Returns a ValInfo indicating whether the element supports this property, or has no value for it.</returns>
internal override object GetPropertyValue(int propertyID) {
switch (propertyID) {
case NativeMethods.UIA_ControlTypePropertyId:
return NativeMethods.UIA_ButtonControlTypeId;
case NativeMethods.UIA_NamePropertyId:
return Name;
case NativeMethods.UIA_IsLegacyIAccessiblePatternAvailablePropertyId:
return true;
case NativeMethods.UIA_LegacyIAccessibleRolePropertyId:
return Role;
default:
return base.GetPropertyValue(propertyID);
}
}
/// <summary>
/// Indicates whether the specified pattern is supported.
/// </summary>
/// <param name="patternId">The pattern ID.</param>
/// <returns>True if specified pattern is supported, otherwise false.</returns>
internal override bool IsPatternSupported(int patternId) {
if (patternId == NativeMethods.UIA_LegacyIAccessiblePatternId) {
return true;
}
return base.IsPatternSupported(patternId);
}
/// <summary>
/// Gets the accessible role.
/// </summary>
public override AccessibleRole Role {
get {
return AccessibleRole.PushButton;
}
}
/// <summary>
/// Request that focus is set to this item.
/// The UIAutomation framework will ensure that the UI hosting this fragment is already
/// focused before calling this method, so this method should only update its internal
/// focus state; it should not attempt to give its own HWND the focus, for example.
/// </summary>
internal override void SetFocus() {
RaiseAutomationEvent(NativeMethods.UIA_AutomationFocusChangedEventId);
base.SetFocus();
}
}
}
|