diff --git a/PROMS/DropDownPanel/Controls/DropDownPanel.Designer.cs b/PROMS/DropDownPanel/Controls/DropDownPanel.Designer.cs new file mode 100644 index 00000000..2c4199bd --- /dev/null +++ b/PROMS/DropDownPanel/Controls/DropDownPanel.Designer.cs @@ -0,0 +1,61 @@ +namespace AT.STO.UI.Win +{ + partial class DropDownPanel + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.combo = new System.Windows.Forms.ComboBox(); + this.SuspendLayout(); + // + // combo + // + this.combo.DropDownHeight = 1; + this.combo.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.combo.FormattingEnabled = true; + this.combo.IntegralHeight = false; + this.combo.Location = new System.Drawing.Point(0, 0); + this.combo.Name = "combo"; + this.combo.Size = new System.Drawing.Size(86, 21); + this.combo.TabIndex = 0; + this.combo.DropDown += new System.EventHandler(this.Combo_DropDown); + // + // DropDownPanel + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.combo); + this.Name = "DropDownPanel"; + this.Size = new System.Drawing.Size(105, 32); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.ComboBox combo; + } +} diff --git a/PROMS/DropDownPanel/Controls/DropDownPanel.cs b/PROMS/DropDownPanel/Controls/DropDownPanel.cs new file mode 100644 index 00000000..8547a6f5 --- /dev/null +++ b/PROMS/DropDownPanel/Controls/DropDownPanel.cs @@ -0,0 +1,287 @@ +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 + } +} diff --git a/PROMS/DropDownPanel/DropDownPanel.csproj b/PROMS/DropDownPanel/DropDownPanel.csproj new file mode 100644 index 00000000..7e1a4f9b --- /dev/null +++ b/PROMS/DropDownPanel/DropDownPanel.csproj @@ -0,0 +1,77 @@ + + + Debug + AnyCPU + 8.0.50727 + 2.0 + {34ADDF19-CBBA-4A11-BC99-D141BA2D29EC} + Library + Properties + DropDownPanel + DropDownPanel + SAK + SAK + SAK + SAK + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + Form + + + DropDownForm.cs + + + UserControl + + + DropDownPanel.cs + + + + + + + + + + + + + DropDownForm.cs + Designer + + + + + \ No newline at end of file diff --git a/PROMS/DropDownPanel/DropDownPanel.csproj.vspscc b/PROMS/DropDownPanel/DropDownPanel.csproj.vspscc new file mode 100644 index 00000000..b6d32892 --- /dev/null +++ b/PROMS/DropDownPanel/DropDownPanel.csproj.vspscc @@ -0,0 +1,10 @@ +"" +{ +"FILE_VERSION" = "9237" +"ENLISTMENT_CHOICE" = "NEVER" +"PROJECT_FILE_RELATIVE_PATH" = "" +"NUMBER_OF_EXCLUDED_FILES" = "0" +"ORIGINAL_PROJECT_FILE_PATH" = "" +"NUMBER_OF_NESTED_PROJECTS" = "0" +"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER" +} diff --git a/PROMS/DropDownPanel/Events/Events.cs b/PROMS/DropDownPanel/Events/Events.cs new file mode 100644 index 00000000..e5659774 --- /dev/null +++ b/PROMS/DropDownPanel/Events/Events.cs @@ -0,0 +1,154 @@ +using System; +using System.Drawing; +using System.Windows.Forms; + +namespace AT.STO.UI.Win +{ + /// + /// Represents the method which responds to a event. + /// + /// + /// + public delegate void DropDownCancelEventHandler(object sender, DropDownCancelEventArgs e); + + /// + /// Represents the method which responds to a event. + /// + /// + /// + public delegate void DropDownClosedEventHandler(object sender, DropDownClosedEventArgs e); + + /// + /// + /// + /// The object firing the event. + /// + public delegate void DropDownValueChangedEventHandler(object sender, DropDownValueChangedEventArgs e); + + /// + /// Arguments to a . Provides a + /// reference to the popup form that is to be closed and + /// allows the operation to be cancelled. + /// + /// Thousand thanks to Steve McMahon: + /// http://www.vbaccelerator.com/home/NET/Code/Controls/Popup_Windows/Popup_Windows/Popup_Form_Demonstration.asp + /// + public class DropDownCancelEventArgs : EventArgs + { + #region Private Variable Declarations + private bool _cancel = false; + private Point _cursorLocation; + private Form _dropDown = null; + #endregion + #region Constructor / Destructor + /// + /// Constructs a new instance of this class. + /// + /// The popup form + /// The mouse location, if any, where the + /// mouse event that would cancel the popup occured. + public DropDownCancelEventArgs(Form DropDown, Point CursorLocation) + { + _dropDown = DropDown; + _cursorLocation = CursorLocation; + _cancel = false; + } + #endregion + #region Public Properties + /// + /// + /// + public bool Cancel + { + get { return _cancel; } + set { _cancel = value; } + } + + /// + /// + /// + public Point CursorLocation + { + get { return _cursorLocation; } + } + + /// + /// + /// + public Form DropDown + { + get { return _dropDown; } + } + #endregion + } + + /// + /// Contains event information for a event. + /// + /// Thousand thanks to Steve McMahon: + /// http://www.vbaccelerator.com/home/NET/Code/Controls/Popup_Windows/Popup_Windows/Popup_Form_Demonstration.asp + /// + public class DropDownClosedEventArgs : EventArgs + { + #region Private Variable Declarations + private Form _dropDown = null; + #endregion + #region Constructor / Destructor + /// + /// Constructs a new instance of this class for the specified + /// popup form. + /// + /// DropDown Form which is being closed. + public DropDownClosedEventArgs(Form DropDown) + { + _dropDown = DropDown; + } + #endregion + #region Public Properties + /// + /// Gets the dropdown form which is being closed. + /// + public Form DropDown + { + get { return _dropDown; } + } + #endregion + } + + /// + /// Contains event information for DropDownValueChangedEventHandler. + /// + public class DropDownValueChangedEventArgs : EventArgs + { + #region Private Variable Declarations + private object _value = null; + #endregion + #region Constructor / Destructor + /// + /// Default Constructor + /// + public DropDownValueChangedEventArgs() + { + } + + /// + /// Initialization with the control's value. + /// + /// + public DropDownValueChangedEventArgs(object Value) + { + _value = Value; + } + #endregion + #region Public Properties + /// + /// Gets or sets the control's value. + /// + public object Value + { + get { return _value; } + set { _value = value; } + } + #endregion + } +} diff --git a/PROMS/DropDownPanel/Forms/DropDownForm.cs b/PROMS/DropDownPanel/Forms/DropDownForm.cs new file mode 100644 index 00000000..6e6a45db --- /dev/null +++ b/PROMS/DropDownPanel/Forms/DropDownForm.cs @@ -0,0 +1,116 @@ +using System; +using System.ComponentModel; +using System.Drawing; +using System.Windows.Forms; + +namespace AT.STO.UI.Win +{ + /// + /// The form that pops up instead of the dropdown portion of the + /// DropDownPanel's combobox. It containes the actual control to + /// display. + /// + internal partial class DropDownForm : Form, IDropDownAware + { + #region Private Variable Declaration + private IDropDownAware _control = null; + #endregion + #region Constructor / Destructor + /// + /// Default Constructor + /// + public DropDownForm() + { + InitializeComponent(); + } + + /// + /// Constructor to initialize the for with the control to display. + /// + /// The control to display. + public DropDownForm(IDropDownAware Ctrl) : this() + { + if (Ctrl != null) + { + _control = Ctrl; + + InitializeControl(_control as Control); + } + } + #endregion + #region Form Events + protected override void OnClosing(CancelEventArgs e) + { + this.Controls.Remove(_control as Control); + base.OnClosing(e); + } + + protected override void OnShown(EventArgs e) + { + base.OnShown(e); + + _control.FinishEditing += new DropDownValueChangedEventHandler(Ctrl_FinishEditing); + _control.ValueChanged += new DropDownValueChangedEventHandler(Ctrl_ValueChanged); + } + #endregion + #region Event Handler + private void Ctrl_FinishEditing(object sender, DropDownValueChangedEventArgs e) + { + if (this.FinishEditing != null) + { + this.FinishEditing(this, e); + } + + _control.FinishEditing -= new DropDownValueChangedEventHandler(Ctrl_FinishEditing); + _control.ValueChanged -= new DropDownValueChangedEventHandler(Ctrl_ValueChanged); + } + + private void Ctrl_ValueChanged(object sender, DropDownValueChangedEventArgs e) + { + if (this.ValueChanged != null) + { + this.ValueChanged(this, e); + } + } + #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. + /// + public object Value + { + get { return _control.Value; } + set { _control.Value = value; } + } + #endregion + #region Private Methods + private void InitializeControl(Control Ctrl) + { + Size size = Ctrl.Size; + Size inner = this.ClientRectangle.Size; + Size outer = this.Size; + int gap = outer.Width - inner.Width; + + size.Width += gap; + size.Height += gap; + + this.Size = size; + this.Controls.Add(Ctrl); + Ctrl.Location = new Point(0, 0); + Ctrl.Visible = true; + Ctrl.Invalidate(); + } + #endregion + } +} diff --git a/PROMS/DropDownPanel/Forms/DropDownForm.designer.cs b/PROMS/DropDownPanel/Forms/DropDownForm.designer.cs new file mode 100644 index 00000000..ed5125ab --- /dev/null +++ b/PROMS/DropDownPanel/Forms/DropDownForm.designer.cs @@ -0,0 +1,52 @@ +namespace AT.STO.UI.Win +{ + partial class DropDownForm + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.SuspendLayout(); + // + // DropDownForm + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.BackColor = System.Drawing.SystemColors.Window; + this.ClientSize = new System.Drawing.Size(347, 211); + this.ControlBox = false; + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow; + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "DropDownForm"; + this.ShowIcon = false; + this.ShowInTaskbar = false; + this.ResumeLayout(false); + + } + + #endregion + } +} \ No newline at end of file diff --git a/PROMS/DropDownPanel/Forms/DropDownForm.resx b/PROMS/DropDownPanel/Forms/DropDownForm.resx new file mode 100644 index 00000000..19dc0dd8 --- /dev/null +++ b/PROMS/DropDownPanel/Forms/DropDownForm.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/PROMS/DropDownPanel/Helper/DropDownMessageFilter.cs b/PROMS/DropDownPanel/Helper/DropDownMessageFilter.cs new file mode 100644 index 00000000..cca60462 --- /dev/null +++ b/PROMS/DropDownPanel/Helper/DropDownMessageFilter.cs @@ -0,0 +1,110 @@ +using System; +using System.Drawing; +using System.Windows.Forms; + +namespace AT.STO.UI.Win +{ + /// + /// A Message Loop filter which detect mouse events whilst the popup form is shown + /// and notifies the owning class when a mouse + /// click outside the popup occurs. + /// + /// Thousand thanks to Steve McMahon: + /// http://www.vbaccelerator.com/home/NET/Code/Controls/Popup_Windows/Popup_Windows/Popup_Form_Demonstration.asp + /// + internal class DropDownMessageFilter : IMessageFilter + { + #region Private Constants + private const int WM_LBUTTONDOWN = 0x201; + private const int WM_RBUTTONDOWN = 0x204; + private const int WM_MBUTTONDOWN = 0x207; + private const int WM_NCLBUTTONDOWN = 0x0A1; + private const int WM_NCRBUTTONDOWN = 0x0A4; + private const int WM_NCMBUTTONDOWN = 0x0A7; + #endregion + #region Private Variable Declarations + private Form _dropDown = null; + private DropDownWindowHelper _owner = null; + #endregion + #region Event Declarations + public event DropDownCancelEventHandler DropDownCancel; + #endregion + #region Constructor / Destructor + /// + /// Constructs a new instance of this class and sets the owning + /// object. + /// + /// The object + /// which owns this class. + public DropDownMessageFilter(DropDownWindowHelper Owner) + { + _owner = Owner; + } + #endregion + #region Public Properties + /// + /// Gets/sets the dropdown form which is being displayed. + /// + public Form DropDown + { + get { return _dropDown; } + set { _dropDown = value; } + } + #endregion + #region Private Methods + private void OnMouseDown() + { + Point cursorPos = Cursor.Position; // Get the cursor location + + if (!_dropDown.Bounds.Contains(cursorPos)) // Check if it is within the popup form + { + OnDropDownCancel(new DropDownCancelEventArgs(_dropDown, cursorPos)); // If not, then call to see if it should be closed + } + } + #endregion + #region DropDownCancelEvent Implementation + protected virtual void OnDropDownCancel(DropDownCancelEventArgs e) + { + if (this.DropDownCancel != null) + { + this.DropDownCancel(this, e); + } + + if (!e.Cancel) + { + _owner.CloseDropDown(); + _dropDown = null; // Clear reference for GC + } + } + #endregion + #region IMessageFilter Implementation + /// + /// Checks the message loop for mouse messages whilst the popup + /// window is displayed. If one is detected the position is + /// checked to see if it is outside the form, and the owner + /// is notified if so. + /// + /// Windows Message about to be processed by the + /// message loop + /// true to filter the message, false otherwise. + /// This implementation always returns false. + public bool PreFilterMessage(ref Message m) + { + if (_dropDown != null) + { + switch (m.Msg) + { + case WM_LBUTTONDOWN: + case WM_RBUTTONDOWN: + case WM_MBUTTONDOWN: + case WM_NCLBUTTONDOWN: + case WM_NCRBUTTONDOWN: + case WM_NCMBUTTONDOWN: OnMouseDown(); break; + } + } + + return false; + } + #endregion + } +} diff --git a/PROMS/DropDownPanel/Helper/DropDownWindowHelper.cs b/PROMS/DropDownPanel/Helper/DropDownWindowHelper.cs new file mode 100644 index 00000000..0d996e60 --- /dev/null +++ b/PROMS/DropDownPanel/Helper/DropDownWindowHelper.cs @@ -0,0 +1,203 @@ +using System; +using System.Drawing; +using System.Runtime.InteropServices; +using System.Windows.Forms; + +namespace AT.STO.UI.Win +{ + /// + /// A class to assist in creating popup windows like Combo Box drop-downs and Menus. + /// This class includes functionality to keep the title bar of the popup owner form + /// active whilst the popup is displayed, and to automatically cancel the popup + /// whenever the user clicks outside the popup window or shifts focus to another + /// application. + /// + /// Thousand thanks to Steve McMahon: + /// http://www.vbaccelerator.com/home/NET/Code/Controls/Popup_Windows/Popup_Windows/Popup_Form_Demonstration.asp + /// + internal class DropDownWindowHelper : NativeWindow + { + #region Private Variable Declarations + private EventHandler DropDownClosedHandler = null; + + private Form _dropDown = null; + private bool _dropDownShowing = false; + private DropDownMessageFilter _filter = null; + private Form _owner = null; + private bool _skipClose = false; + #endregion + #region Event Declarations + public event DropDownCancelEventHandler DropDownCancel; + public event DropDownClosedEventHandler DropDownClosed; + #endregion + #region Constructor / Destructor + /// + /// Default constructor. + /// + /// Use the + /// method to attach this class to the form you want to show popups from. + public DropDownWindowHelper() + { + _filter = new DropDownMessageFilter(this); + _filter.DropDownCancel += new DropDownCancelEventHandler(Popup_Cancel); + } + #endregion + #region Event Handler + private void Popup_Cancel(object sender, DropDownCancelEventArgs e) + { + OnDropDownCancel(e); + } + + /// + /// Responds to the + /// event from the popup form. + /// + /// Popup form that has been closed. + /// Not used. + private void Popup_Closed(object sender, EventArgs e) + { + CloseDropDown(); + } + + /// + /// Subclasses the owning form's existing Window Procedure to enables the + /// title bar to remain active when a popup is show, and to detect if + /// the user clicks onto another application whilst the popup is visible. + /// + /// Window Procedure Message + protected override void WndProc(ref Message m) + { + base.WndProc(ref m); + + if (DropDownShowing) + { + if (m.Msg == UIApiCalls.WM_NCACTIVATE) + { + if (((int)m.WParam) == 0) // Check if the title bar will made inactive: + { // Note it's no good to try and consume this message; if you try to do that you'll end up with windows + UIApiCalls.SendMessage(this.Handle, UIApiCalls.WM_NCACTIVATE, 1, IntPtr.Zero); // If so reactivate it. + } + } + else if (m.Msg == UIApiCalls.WM_ACTIVATEAPP) + { + if ((int)m.WParam == 0) // Check if the application is being deactivated. + { + CloseDropDown(); // It is so cancel the popup: + UIApiCalls.PostMessage(this.Handle, UIApiCalls.WM_NCACTIVATE, 0, IntPtr.Zero); // And put the title bar into the inactive state: + } + } + } + } + #endregion + #region Public Methods + /// + /// Shows the specified Form as a popup window, keeping the + /// Owner's title bar active and preparing to cancel the popup + /// should the user click anywhere outside the popup window. + /// Typical code to use this message is as follows: + /// + /// frmPopup popup = new frmPopup(); + /// Point location = this.PointToScreen(new Point(button1.Left, button1.Bottom)); + /// popupHelper.ShowPopup(this, popup, location); + /// + /// Put as much initialisation code as possible + /// into the popup form's constructor, rather than the + /// event as this will improve visual appearance. + /// + /// Main form which owns the popup + /// Window to show as a popup + /// Location relative to the screen to show the popup at. + public void ShowDropDown(Form Owner, Form DropDown, Point Location) + { + _owner = Owner; + _dropDown = DropDown; + Application.AddMessageFilter(_filter); // Start checking for the popup being cancelled + DropDown.StartPosition = FormStartPosition.Manual; // Set the location of the popup form: + DropDown.Location = Location; + Owner.AddOwnedForm(DropDown); // Make it owned by the window that's displaying it: + DropDownClosedHandler = new EventHandler(Popup_Closed); // Respond to the Closed event in case the popup is closed by its own internal means + DropDown.Closed += DropDownClosedHandler; + + _dropDownShowing = true; // Show the popup: + DropDown.Show(); + DropDown.Activate(); + + // A little bit of fun. We've shown the popup, but because we've kept the main window's + // title bar in focus the tab sequence isn't quite right. This can be fixed by sending a tab, + // but that on its own would shift focus to the second control in the form. So send a tab, + // followed by a reverse-tab. + UIApiCalls.keybd_event((byte) Keys.Tab, 0, 0, 0); + UIApiCalls.keybd_event((byte) Keys.Tab, 0, UIApiCalls.KEYEVENTF_KEYUP, 0); + UIApiCalls.keybd_event((byte) Keys.ShiftKey, 0, 0, 0); + UIApiCalls.keybd_event((byte) Keys.Tab, 0, 0, 0); + UIApiCalls.keybd_event((byte) Keys.Tab, 0, UIApiCalls.KEYEVENTF_KEYUP, 0); + UIApiCalls.keybd_event((byte) Keys.ShiftKey, 0, UIApiCalls.KEYEVENTF_KEYUP, 0); + + _filter.DropDown = DropDown; // Start filtering for mouse clicks outside the popup + } + + /// + /// Called when the popup is being hidden. + /// + public void CloseDropDown() + { + if (DropDownShowing) + { + if (!_skipClose) + { + OnPDropDownClosed(new DropDownClosedEventArgs(_dropDown)); + } + + _skipClose = false; + + _owner.RemoveOwnedForm(_dropDown); // Make sure the popup is closed and we've cleaned up: + _dropDownShowing = false; + _dropDown.Closed -= DropDownClosedHandler; + DropDownClosedHandler = null; + _dropDown.Close(); + + Application.RemoveMessageFilter(_filter); // No longer need to filter for clicks outside the popup. + + // If we did something from the popup which shifted focus to a new form, like showing another popup + // or dialog, then Windows won't know how to bring the original owner back to the foreground, so + // force it here: + _owner.Activate(); + + _dropDown = null; // Null out references for GC + _owner = null; + } + } + #endregion + #region Public Properties + /// + /// Indicator weither the DropDown is showing. + /// + public bool DropDownShowing + { + get { return _dropDownShowing; } + } + #endregion + #region Event Implementation + protected virtual void OnDropDownCancel(DropDownCancelEventArgs e) + { + if (this.DropDownCancel != null) + { + this.DropDownCancel(this, e); + + if (!e.Cancel) + { + _skipClose = true; + } + } + } + + protected virtual void OnPDropDownClosed(DropDownClosedEventArgs e) + { + if (this.DropDownClosed != null) + { + this.DropDownClosed(this, e); + } + } + #endregion + } +} diff --git a/PROMS/DropDownPanel/Interfaces/IDropDownAware.cs b/PROMS/DropDownPanel/Interfaces/IDropDownAware.cs new file mode 100644 index 00000000..94874f2b --- /dev/null +++ b/PROMS/DropDownPanel/Interfaces/IDropDownAware.cs @@ -0,0 +1,30 @@ +using System; + +namespace AT.STO.UI.Win +{ + /// + /// Standard interface that has to be implemented by control's that + /// should be diplayed in the dropdown area of the DropDownPanel. + /// + public interface IDropDownAware + { + #region Event Declarations + /// + /// Fired either on OK, Cancel or a click outside the control to indicate + /// that the user has finished editing. + /// + event DropDownValueChangedEventHandler FinishEditing; + + /// + /// Fired on any change of the controls's value during the editing process. + /// + event DropDownValueChangedEventHandler ValueChanged; + #endregion + #region Public Properties + /// + /// Gets or sets the controls' value. + /// + object Value { get; set; } + #endregion + } +} diff --git a/PROMS/DropDownPanel/Interfaces/ILookupItem.cs b/PROMS/DropDownPanel/Interfaces/ILookupItem.cs new file mode 100644 index 00000000..b3181e2a --- /dev/null +++ b/PROMS/DropDownPanel/Interfaces/ILookupItem.cs @@ -0,0 +1,10 @@ +using System; + +namespace AT.STO.UI.Win +{ + public interface ILookupItem where T: struct + { + T Id { get; } + string Text { get; } + } +} diff --git a/PROMS/DropDownPanel/Properties/AssemblyInfo.cs b/PROMS/DropDownPanel/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..edf85828 --- /dev/null +++ b/PROMS/DropDownPanel/Properties/AssemblyInfo.cs @@ -0,0 +1,35 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("DropDownPanel")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("DropDownPanel")] +[assembly: AssemblyCopyright("Copyright © 2007")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("d59d03fc-b0ff-4210-867d-cfa4cef1728c")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Revision and Build Numbers +// by using the '*' as shown below: +[assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/PROMS/DropDownPanel/Unmanaged/UIApiCalls.cs b/PROMS/DropDownPanel/Unmanaged/UIApiCalls.cs new file mode 100644 index 00000000..92b2f160 --- /dev/null +++ b/PROMS/DropDownPanel/Unmanaged/UIApiCalls.cs @@ -0,0 +1,25 @@ +using System; +using System.Runtime.InteropServices; + +namespace AT.STO.UI.Win +{ + public static class UIApiCalls + { + #region Public Constants + public const int WM_ACTIVATE = 0x006; + public const int WM_ACTIVATEAPP = 0x01C; + public const int WM_NCACTIVATE = 0x086; + public const int KEYEVENTF_KEYUP = 0x0002; + #endregion + #region Public Static API Calls + [DllImport("user32", CharSet = CharSet.Auto)] + public extern static int SendMessage(IntPtr handle, int msg, int wParam, IntPtr lParam); + + [DllImport("user32", CharSet = CharSet.Auto)] + public extern static int PostMessage(IntPtr handle, int msg, int wParam, IntPtr lParam); + + [DllImport("user32")] + public extern static void keybd_event(byte bVk, byte bScan, int dwFlags, int dwExtraInfo); + #endregion + } +}