using System; using System.ComponentModel; using System.Diagnostics; using System.Drawing; using System.Windows.Forms; namespace AT.STO.UI.Win { /// /// Control that allows any other control that implements IDropDownAware to be displayed /// in it's own combo-like dropdown area. This Control tries to mimic the standard ComboBox /// as accurately as possible. /// public partial class DropDownPanel : UserControl, IDropDownAware { #region Private Variable Declarations private IDropDownAware _dropDownControl = null; private DropDownWindowHelper _dropDownHelper = null; private Form _owner = null; #endregion #region Constructor / Destructor /// /// Default constructor /// public DropDownPanel() { InitializeComponent(); _dropDownHelper = new DropDownWindowHelper(); _dropDownHelper.DropDownClosed += new DropDownClosedEventHandler(DropDownHelper_DropDownClosed); _dropDownHelper.DropDownCancel += new DropDownCancelEventHandler(DropDownHelper_DropDownCancel); combo.DisplayMember = "Text"; combo.ValueMember = "Id"; } #endregion #region Control Events /// /// The owning form is set within this event, wich is required to /// force the owning form not to loose focus when the dropdown is /// being displayed. Inherited controls should provide the PopupControl /// within an overridden implementation of this event. /// /// protected override void OnHandleCreated(EventArgs e) { _owner = this.FindForm(); _dropDownHelper.ReleaseHandle(); if (_owner != null) { _dropDownHelper.AssignHandle(_owner.Handle); } } /// /// Make sure that the overall control's height is exactly the height /// of the internal ComboBox and that the ComboBox's widt is exactly the /// width of the control. /// /// protected override void OnResize(EventArgs e) { base.OnResize(e); combo.Location = new Point(0, 0); combo.Width = this.ClientRectangle.Width; this.Height = combo.Height; } #endregion #region Event Handler /// /// We make our DropDownForm host the choosen control and show it instead /// of the dropdown portion of the ComboBox. /// /// /// private void Combo_DropDown(object sender, EventArgs e) { if (!_dropDownHelper.DropDownShowing) { DropDownForm dropDown = new DropDownForm(_dropDownControl); dropDown.FinishEditing += new DropDownValueChangedEventHandler(DropDown_FinishEditing); dropDown.ValueChanged += new DropDownValueChangedEventHandler(DropDown_ValueChanged); combo.DroppedDown = false; dropDown.Width = combo.Width; // KBR ADDED 2/15/08 _dropDownHelper.ShowDropDown(_owner, dropDown, GetDropDownPosition(dropDown)); } else { _dropDownHelper.CloseDropDown(); this.Focus(); } } private void DropDownHelper_DropDownClosed(object sender, DropDownClosedEventArgs e) { IDropDownAware dropDown = (e.DropDown as IDropDownAware); if ((dropDown != null) && (dropDown.Value != null)) { dropDown.FinishEditing -= new DropDownValueChangedEventHandler(DropDown_FinishEditing); dropDown.ValueChanged -= new DropDownValueChangedEventHandler(DropDown_ValueChanged); } combo.DroppedDown = false; } private void DropDownHelper_DropDownCancel(object sender, DropDownCancelEventArgs e) { if (this.Bounds.Contains(Parent.PointToClient(e.CursorLocation))) { e.Cancel = true; } else { IDropDownAware dropDown = (e.DropDown as IDropDownAware); if (dropDown != null) { dropDown.FinishEditing -= new DropDownValueChangedEventHandler(DropDown_FinishEditing); dropDown.ValueChanged -= new DropDownValueChangedEventHandler(DropDown_ValueChanged); } } } private void DropDown_FinishEditing(object sender, DropDownValueChangedEventArgs e) { if (e.Value != null) { SetValue(e.Value as ILookupItem); } if (this.FinishEditing != null) { this.FinishEditing(this, e); } _dropDownControl.FinishEditing -= new DropDownValueChangedEventHandler(DropDown_FinishEditing); _dropDownControl.ValueChanged -= new DropDownValueChangedEventHandler(DropDown_ValueChanged); _dropDownHelper.CloseDropDown(); } private void DropDown_ValueChanged(object sender, DropDownValueChangedEventArgs e) { if (this.ValueChanged != null) { this.ValueChanged(this, e); } } #endregion #region Public Properties /// /// Get or set the control (has to implement IDropDownAware) that is to /// be displayed as the dropdown portion of the combobox. /// [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public IDropDownAware DropDownControl { get { return _dropDownControl; } set { _dropDownControl = value; this.Controls.Add(_dropDownControl as Control); } } #endregion #region Public Methods public override string ToString() { return this.Name; } #endregion #region Private Methods /// /// Calculate an acceptable position of the DropDownForm even in a /// multi screen environment. /// /// /// private Point GetDropDownPosition(DropDownForm DropDown) { Point lt = Parent.PointToScreen(new Point(Left, Top)); Point rb = Parent.PointToScreen(new Point(Right, Bottom)); Rectangle screen = Screen.FromControl(this).Bounds; Point point = new Point(); if (((lt.X + DropDown.Width) > (screen.X + screen.Width)) && ((rb.X - DropDown.Width) >= screen.X)) { point.X = rb.X - DropDown.Width; if ((point.X + DropDown.Width) > (screen.X + screen.Width)) { point.X = ((screen.X + screen.Width) - DropDown.Width); } } else { point.X = lt.X; if (point.X < screen.X) { point.X = screen.X; } } if (((rb.Y + DropDown.Height) > (screen.Y + screen.Height)) && ((lt.Y - DropDown.Height) >= screen.Y)) { point.Y = lt.Y - DropDown.Height; if (point.Y < screen.Y) { point.Y = screen.Y; } } else { point.Y = rb.Y; if ((point.Y + DropDown.Height) > (screen.Y + screen.Height)) { point.Y = ((screen.Y + screen.Height) - DropDown.Height); } } return point; } /// /// In this implementation we don't the user to edit the ComboBox /// directly, so we add the new value to the item collection after /// clearing it first. /// /// /// private void SetValue(ILookupItem Value) where T: struct { if (DropDownControl != null) { ILookupItem[] arr = new ILookupItem[0]; combo.DataSource = arr; if ((Value != null) && (Value is ILookupItem)) { DropDownControl.Value = Value; arr = new ILookupItem[1]{(ILookupItem) Value}; combo.DataSource = arr; combo.SelectedIndex = 0; //combo.Focus(); } else { DropDownControl.Value = null; } } } #endregion #region IDropDownAware Implementation /// /// Fired either on OK, Cancel or a click outside the control to indicate /// that the user has finished editing. /// public event DropDownValueChangedEventHandler FinishEditing; /// /// Fired on any change of the controls's value during the editing process. /// public event DropDownValueChangedEventHandler ValueChanged; /// /// Gets or sets the controls' value. /// [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public object Value { get { return _dropDownControl.Value; } set { SetValue(value as ILookupItem); } } #endregion } }