288 lines
7.8 KiB
C#
288 lines
7.8 KiB
C#
using System;
|
|
using System.ComponentModel;
|
|
using System.Diagnostics;
|
|
using System.Drawing;
|
|
using System.Windows.Forms;
|
|
|
|
namespace AT.STO.UI.Win
|
|
{
|
|
/// <summary>
|
|
/// 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.
|
|
/// </summary>
|
|
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
|
|
/// <summary>
|
|
/// Default constructor
|
|
/// </summary>
|
|
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
|
|
/// <summary>
|
|
/// 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.
|
|
/// </summary>
|
|
/// <param name="e"></param>
|
|
protected override void OnHandleCreated(EventArgs e)
|
|
{
|
|
_owner = this.FindForm();
|
|
_dropDownHelper.ReleaseHandle();
|
|
|
|
if (_owner != null)
|
|
{
|
|
_dropDownHelper.AssignHandle(_owner.Handle);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 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.
|
|
/// </summary>
|
|
/// <param name="e"></param>
|
|
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
|
|
/// <summary>
|
|
/// We make our DropDownForm host the choosen control and show it instead
|
|
/// of the dropdown portion of the ComboBox.
|
|
/// </summary>
|
|
/// <param name="sender"></param>
|
|
/// <param name="e"></param>
|
|
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;
|
|
_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<long>(e.Value as ILookupItem<long>);
|
|
}
|
|
|
|
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
|
|
/// <summary>
|
|
/// Get or set the control (has to implement IDropDownAware) that is to
|
|
/// be displayed as the dropdown portion of the combobox.
|
|
/// </summary>
|
|
[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
|
|
/// <summary>
|
|
/// Calculate an acceptable position of the DropDownForm even in a
|
|
/// multi screen environment.
|
|
/// </summary>
|
|
/// <param name="DropDown"></param>
|
|
/// <returns></returns>
|
|
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;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 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.
|
|
/// </summary>
|
|
/// <typeparam name="T"></typeparam>
|
|
/// <param name="Value"></param>
|
|
private void SetValue<T>(ILookupItem<T> Value) where T: struct
|
|
{
|
|
if (DropDownControl != null)
|
|
{
|
|
ILookupItem<T>[] arr = new ILookupItem<T>[0];
|
|
|
|
combo.DataSource = arr;
|
|
|
|
if ((Value != null) && (Value is ILookupItem<long>))
|
|
{
|
|
DropDownControl.Value = Value;
|
|
|
|
arr = new ILookupItem<T>[1]{(ILookupItem<T>) Value};
|
|
combo.DataSource = arr;
|
|
combo.SelectedIndex = 0;
|
|
combo.Focus();
|
|
}
|
|
else
|
|
{
|
|
DropDownControl.Value = null;
|
|
}
|
|
}
|
|
}
|
|
#endregion
|
|
#region IDropDownAware Implementation
|
|
/// <summary>
|
|
/// Fired either on OK, Cancel or a click outside the control to indicate
|
|
/// that the user has finished editing.
|
|
/// </summary>
|
|
public event DropDownValueChangedEventHandler FinishEditing;
|
|
|
|
/// <summary>
|
|
/// Fired on any change of the controls's value during the editing process.
|
|
/// </summary>
|
|
public event DropDownValueChangedEventHandler ValueChanged;
|
|
|
|
/// <summary>
|
|
/// Gets or sets the controls' value.
|
|
/// </summary>
|
|
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
|
public object Value
|
|
{
|
|
get { return _dropDownControl.Value; }
|
|
set { SetValue<long>(value as ILookupItem<long>); }
|
|
}
|
|
#endregion
|
|
}
|
|
}
|