ASP.NET编写组件控件实例:多列下拉框和鼠标相关组件(2)
/// <summary>
/// 鼠标按下事件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void SizableControl_MouseDown(object sender, MouseEventArgs e)
{
if (!m_Enable)
return;
m_ResizeOriginalPoint = Control.MousePosition;
}
/// <summary>
/// 鼠标移动事件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void SizableControl_MouseMove(object sender, MouseEventArgs e)
{
if (!m_Enable)
return;
if (e.Button == MouseButtons.None)
{
this.CheckMousePoint(sender as Control, e.Location);
return;
}
if (e.Button != MouseButtons.Left)
return;
Point OffsetPoint = Control.MousePosition;
OffsetPoint.Offset(-m_ResizeOriginalPoint.X, -m_ResizeOriginalPoint.Y);
switch (m_HandleArea)
{
case ResizeHandleAreaEnum.TopLeft:
this.SetControlBound(OffsetPoint.X, OffsetPoint.Y, -OffsetPoint.X, -OffsetPoint.Y);
break;
case ResizeHandleAreaEnum.TopCenter:
this.SetControlBound(0, OffsetPoint.Y, 0, -OffsetPoint.Y);
break;
case ResizeHandleAreaEnum.TopRight:
this.SetControlBound(0, OffsetPoint.Y, OffsetPoint.X, -OffsetPoint.Y);
break;
case ResizeHandleAreaEnum.CenterLeft:
this.SetControlBound(OffsetPoint.X, 0, -OffsetPoint.X, 0);
break;
case ResizeHandleAreaEnum.CenterRight:
this.SetControlBound(0, 0, OffsetPoint.X, 0);
break;
case ResizeHandleAreaEnum.BottomLeft:
this.SetControlBound(OffsetPoint.X, 0, -OffsetPoint.X, OffsetPoint.Y);
break;
case ResizeHandleAreaEnum.BottomCenter:
this.SetControlBound(0, 0, 0, OffsetPoint.Y);
break;
case ResizeHandleAreaEnum.BottomRight:
this.SetControlBound(0, 0, OffsetPoint.X, OffsetPoint.Y);
break;
case ResizeHandleAreaEnum.Center:
default:
break;
}
this.m_ResizeOriginalPoint = Control.MousePosition;
}
/// <summary>
/// 鼠标离开事件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void SizableControl_MouseLeave(object sender, EventArgs e)
{
if (!m_Enable)
return;
(sender as Control).Cursor = Cursors.Default;
this.m_ResizableControl.Cursor = Cursors.Default;
}
其他方法都是辅助检测和调整坐标用的。下面介绍如何实现自定义的UITypeEditor。这里定义了一个枚举ResizeHandleAreaEnum,用来标识调整大小的区域。因为设置的响应操作的区域允许有多个,所以这些枚举值必须都是2的次方数,在二进制中表示则都只有一位是1的,这样就可以通过位操作来解析值了。


/// <summary>
/// 改变大小控制区域枚举
/// </summary>
[Flags]
[Serializable]
[Editor(typeof(ResizeHandleAreaUITypeEditor), typeof(System.Drawing.Design.UITypeEditor))]
public enum ResizeHandleAreaEnum
{
/// <summary>
/// 中央区域,不响应操作
/// </summary>
Center = 0,
/// <summary>
/// 顶端靠左
/// </summary>
TopLeft = 1,
/// <summary>
/// 顶端居中
/// </summary>
TopCenter = 2,
/// <summary>
/// 顶端靠右
/// </summary>
TopRight = 4,
/// <summary>
/// 中间靠左
/// </summary>
CenterLeft = 8,
/// <summary>
/// 中间靠右
/// </summary>
CenterRight = 16,
/// <summary>
/// 底部靠左
/// </summary>
BottomLeft = 32,
/// <summary>
/// 底部居中
/// </summary>
BottomCenter = 64,
/// <summary>
/// 底部靠右
/// </summary>
BottomRight = 128,
}
枚举定义好之后,在项目中添加一个自定义控件,在其中放置8个CheckBox,设置Appearance属性为Button外观。然后排布为虚拟边框的效果,如下图:
该控件主要是将ResizeHandleAreaEnum枚举值和CheckBox控件的选中状态对应起来,通过位操作来解析和设置响应操作的区域枚举,内部代码如下:


//原始响应区域
private ResizeHandleAreaEnum m_OldAears;
/// <summary>
/// 改变大小的响应区域枚举
/// </summary>
public ResizeHandleAreaEnum ResizeHandleAreas
{
get
{
ResizeHandleAreaEnum Areas = ResizeHandleAreaEnum.Center;
if (chkTopLeft.Checked)
Areas |= ResizeHandleAreaEnum.TopLeft;
if (chkTopCenter.Checked)
Areas |= ResizeHandleAreaEnum.TopCenter;
if (chkTopRight.Checked)
Areas |= ResizeHandleAreaEnum.TopRight;
if (chkCenterLeft.Checked)
Areas |= ResizeHandleAreaEnum.CenterLeft;
if (chkCenterRight.Checked)
Areas |= ResizeHandleAreaEnum.CenterRight;
if (chkBottomLeft.Checked)
Areas |= ResizeHandleAreaEnum.BottomLeft;
if (chkBottomCenter.Checked)
Areas |= ResizeHandleAreaEnum.BottomCenter;
if (chkBottomRight.Checked)
Areas |= ResizeHandleAreaEnum.BottomRight;
if (Areas == ResizeHandleAreaEnum.Center)
return m_OldAears;
else
return Areas;
}
}
/// <summary>
/// 设置响应改变大小的区域
/// </summary>
/// <param name="ResizeHandleArea"></param>
public void SetValue(ResizeHandleAreaEnum ResizeHandleArea)
{
m_OldAears = ResizeHandleArea;
chkTopLeft.Checked = ((m_OldAears & ResizeHandleAreaEnum.TopLeft) != 0);
chkTopCenter.Checked = ((m_OldAears & ResizeHandleAreaEnum.TopCenter) != 0);
chkTopRight.Checked = ((m_OldAears & ResizeHandleAreaEnum.TopRight) != 0);
chkCenterLeft.Checked = ((m_OldAears & ResizeHandleAreaEnum.CenterLeft) != 0);
chkCenterRight.Checked = ((m_OldAears & ResizeHandleAreaEnum.CenterRight) != 0);
chkBottomLeft.Checked = ((m_OldAears & ResizeHandleAreaEnum.BottomLeft) != 0);
chkBottomCenter.Checked = ((m_OldAears & ResizeHandleAreaEnum.BottomCenter) != 0);
chkBottomRight.Checked = ((m_OldAears & ResizeHandleAreaEnum.BottomRight) != 0);
}
实现IExtenderProvider接口后,将组件拖放到窗体上,设置相关HandleControl之后,则会为其内部控件增加HandleMove属性,效果如下图:
接下来介绍ResizableComponent可改变大小组件的实现。
该组件的类图如下:
组件的类图和类详细信息
MovableComponent组件包含5个属性:
Enable:指示组件是否可用
EnableInnerControl:指示是否允许HandleControl控件的内部控件响应鼠标操作。
HandleControl:响应鼠标操作的控件,可以和被移动的控件不一致,一般是被移动控件内部的控件。
MovableControl:被移动的控件。
MoveableDirection:控件可以被移动的方向,默认为All,不限制移动方向。