如何设置Winform控件的ClientRectangle

简介:
  最近学习制作WinForm控件,自己动手写控件的时候才发现System.Windows.Forms.Control 竟然没有提供默认的border绘制。记得以前用API做控件的时候,只需要设置空间窗口的WS_BORDER 风格就可以。遍寻无方,只有自己绘制了,这里有出现一个,如果border在客户区,那么在OnPaint方法里不得不每次都要考虑Border所占用的区域,而且,如果从这个类派生的话,将无法获得准确的客户区。
      现在要解决的问题就是如何重新设置客户区的矩形区域的尺寸,查看了一下Control类的ClientRectangle属性:
public Rectangle ClientRectangle { get; }是个只读属性,看来是不能通过这个属性达到目的了。再查找Control类的文档,也没有这方面的说明,没有办法,只能用API搞定了。可以通过计算非客户区尺寸来设置客户区尺寸,Border在非客户绘制。下面就是主要的代码,就是通过重载WndProc方法,捕捉WM_NCCALCSIZE消息,实现自己的逻辑。
     
protected   override   void  WndProc( ref  Message m)
{
switch (m.Msg)
{
case (int)WinAPI_WM.WM_NCCALCSIZE:
if (m.WParam.ToInt32() == 0)
{
WinAPI_RECT rc 
= (WinAPI_RECT)m.GetLParam(typeof(WinAPI_RECT));
rc.Left 
+= 1;
rc.Top 
+= 1
rc.Right 
-= 1
rc.Bottom 
-= 1;
Marshal.StructureToPtr(rc, m.LParam, 
true);
m.Result 
= IntPtr.Zero;
}

else
{
WinAPI_NCCALCSIZE_PARAMS csp;
csp 
= (WinAPI_NCCALCSIZE_PARAMS)m.GetLParam(typeof(WinAPI_NCCALCSIZE_PARAMS));
csp.rgrc0.Top 
+= 1
csp.rgrc0.Bottom 
-= 1;
csp.rgrc0.Left 
+= 1
csp.rgrc0.Right 
-= 1;

Marshal.StructureToPtr(csp, m.LParam, 
true);
//Return zero to preserve client rectangle
m.Result = IntPtr.Zero;
}

break;
case (int)WinAPI_WM.WM_NCPAINT:
{
m.WParam 
= NCPaint(m.WParam);
break;
}

}


base.WndProc(ref m);
}


public  IntPtr NCPaint(IntPtr region)
{
IntPtr hDC 
= GetWindowDC(this.Handle);
if (hDC != IntPtr.Zero)
{
Graphics grTemp 
= Graphics.FromHdc(hDC);

int ScrollBarWidth = SystemInformation.VerticalScrollBarWidth;
int ScrollBarHeight = SystemInformation.HorizontalScrollBarHeight;

WINDOWINFO wi 
= new WINDOWINFO();
wi.cbSize 
= (uint)Marshal.SizeOf(wi);

//得到当前控件的窗口信息
GetWindowInfo(Handle, ref wi);

wi.rcClient.Right
--;
wi.rcClient.Bottom
--;


//获得当前控件的区域
Region UpdateRegion = new Region(new Rectangle(wi.rcWindow.Top,wi.rcWindow.Left,wi.rcWindow.Right-wi.rcWindow.Left,wi.rcWindow.Bottom-wi.rcWindow.Top));

//获得客户区以外的区域
UpdateRegion.Exclude(new Rectangle(wi.rcClient.Top, wi.rcClient.Left, wi.rcClient.Right - wi.rcClient.Left, wi.rcClient.Bottom - wi.rcClient.Top));

if (IsHScrollVisible && IsVScrollVisible)
{
UpdateRegion.Exclude(Rectangle.FromLTRB
(wi.rcClient.Right 
+ 1, wi.rcClient.Bottom + 1,
wi.rcWindow.Right, wi.rcWindow.Bottom));
}


//得到当前区域的句柄
IntPtr hRgn = UpdateRegion.GetHrgn(grTemp);

//For Painting we need to zero offset the Rectangles.
Rectangle WindowRect = new Rectangle(wi.rcWindow.Top, wi.rcWindow.Left, wi.rcWindow.Right - wi.rcWindow.Left, wi.rcWindow.Bottom - wi.rcWindow.Top);

Point offset 
= Point.Empty - (Size)WindowRect.Location;

WindowRect.Offset(offset);

Rectangle ClientRect 
= WindowRect;

ClientRect.Inflate(
-1-1);

//Fill the BorderArea
Region PaintRegion = new Region(WindowRect);
PaintRegion.Exclude(ClientRect);
grTemp.FillRegion(SystemBrushes.Control, PaintRegion);

//Fill the Area between the scrollbars
if (IsHScrollVisible && IsVScrollVisible)
{
Rectangle ScrollRect 
= new Rectangle(ClientRect.Right - ScrollBarWidth,
ClientRect.Bottom 
- ScrollBarHeight, ScrollBarWidth + 2, ScrollBarHeight + 2);
ScrollRect.Offset(
-1-1);
grTemp.FillRectangle(SystemBrushes.Control, ScrollRect);
}


//Adjust ClientRect for Drawing Border.
ClientRect.Inflate(22);
ClientRect.Width
--;
ClientRect.Height
--;

//Draw Outer Raised Border
ControlPaint.DrawBorder3D(grTemp, WindowRect, Border3DStyle.Raised,
Border3DSide.Bottom 
| Border3DSide.Left | Border3DSide.Right | Border3DSide.Top);

//Draw Inner Sunken Border
ControlPaint.DrawBorder3D(grTemp, ClientRect, Border3DStyle.Sunken,
Border3DSide.Bottom 
| Border3DSide.Left | Border3DSide.Right | Border3DSide.Top);

ReleaseDC(Handle, hDC);

grTemp.Dispose();

return hRgn;

}


RefreshScrollBar();
return region;
}





本文转自纶巾客博客园博客,原文链接:http://www.cnblogs.com/guanjinke/archive/2006/11/29/576961.html,如需转载请自行联系原作者
目录
相关文章
|
C# 索引 Windows
Winform控件优化之TabControl控件的使用和常用功能
TabControl是一个分页切换(tab)控件,不同的页框内可以呈现不同的内容,将主要介绍调整tab的左右侧显示、设置多行tab、禁用或删除tabpage、隐藏TabControl头部的选项卡等
5056 0
Winform控件优化之TabControl控件的使用和常用功能
|
机器学习/深度学习 数据可视化 程序员
WinForm控件属性大全
WinForm控件属性大全
443 0
|
C#
WPF 创建自定义窗体
原文:WPF 创建自定义窗体 在前面的一篇博客"WPF 自定义Metro Style窗体",展示了如何创建一个类似于Metro Style的Window,并在程序中使用。但是这个窗体不能够自由的改变大小。
1399 0
|
C# Windows 安全
WinForm控件与WPF控件的交互
原文:WinForm控件与WPF控件的交互 这个问题其实也可以理解为:怎样在WPF/XAML中使用Winform中的控件(如PictureBox)?首先看看XAML代码:(注意下面加粗的部分)              ...
1088 0
|
C# 前端开发
使用Adorner显示WPF控件的边界点
原文:使用Adorner显示WPF控件的边界点 当我们拖动WPF控件时,我们为了更清楚地需要显示控件,一般我们会在WPF控件所围成的矩形区域的四个边界点上作一个特殊的记号(比如圆点)。
1276 0
|
前端开发 C#
WPF 窗体显示最前端
原文:WPF 窗体显示最前端 版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/jjx0224/article/details/8782845 ...
1161 0
|
C#
WPF 后台C#设置控件背景图片
原文:WPF 后台C#设置控件背景图片 以前的程序中有做过,当时只是记得uri很长一大段就没怎么记。今天有人问了也就写下来。
2052 0
|
C#
WPF中一个控件绑定另一个控件的属性
原文:WPF中一个控件绑定另一个控件的属性 如同一个Grid中的一个按钮根据另一个按钮的显示与否作出不同的响应: 绑定的时候通过ElementName来指定控件               ...
1860 0
|
C#
wpf 深度复制控件,打印控件
原文:wpf 深度复制控件,打印控件 ...
1042 0