Recently in dotNet Framework Category

.NET Compact Framework中,把原有的Form.Handle属性去掉了。表面上看似乎无法获得一个窗口的句柄了。实际上我们可以变通一下来解决这个问题。首先,通过Form.Capture让窗口获得焦点,接下来使用GetCapture API来取得焦点窗口的句柄。类似的方法还可以获得其他一些有焦点控件的句柄

Code:

[DllImport("coredll.dll")]
private static extern IntPtr SetCapture(IntPtr hWnd);

[DllImport("coredll.dll")]
private static extern IntPtr GetCapture();

public static IntPtr GetHandle()
{
 IntPtr hOldWnd = GetCapture();
 this.Capture = true;
IntPtr ret = GetCapture();
 this.Capture = false;
 SetCapture(hOldWnd);
 return ret;
}

Visual Studio .NET 2003 Windows Mobile用户提供的控件大多不太理想。有些是样式不大如意。更多时候是我们找不到一个能满足我们功能的控件。比如带有图片的ListBox, 带有CheckBoxListBox,带有IconMenu等等。(同时也奇怪为什么M$不把Smartphone里显示短信的控件放在ToolBox)

因此自定义控件(Custom Control)。几乎就是.NET CF开发的必修课了。在这片文章里,通过制作一个简单的按钮控件来说明自定义控件的基本步骤。

publicclass CustomControl: System.Windows.Forms.Control

{

// …

protectedoverridevoid OnPaint(PaintEventArgs e)

{

// DO SOMETHING

}

protectedoverridevoid OnPaintBackground(PaintEventArgs pevent)

{

// DO NOTHING

}

// …

}

由于.NET CF并不支持控件的OwnerDraw机制,所以要想自定义控件只能派生自System.Windows.Forms.Control了。然后白手起家,慢慢搭建自己的控件库。

Windows.Forms.Control派生出自己的CustomControl。之后还有重载OnPaintOnPaintBackground两个方法,对控件和控件背景进行高效的绘制。因为.NET CF是运行在移动设备之上,因此绘图的效率对显示的影响是十分明显的。为了提高效率我们从以下几个方面着手:

l使用缓冲区绘图。将绘制过程放在缓冲区内进行。需要绘制控件时,直接将缓冲区内容全部绘出。

l努力将绘图运算放置在OnPaintOnPaintBackground函数之外。

l充分利用类继承特性,避免重复绘制。

l避免在OnPaintOnPaintBackground函数内产生和销毁对象。

//…

protected Bitmap m_bmpBuffer = null;

protected Graphics m_gxBuffer = null;

//…

protectedoverridevoid OnResize(EventArgs e)

{

// Dispose Old Graphic Buffer

if (this.m_bmpBuffer != null)

this.m_bmpBuffer.Dispose();

if (this.m_gxBuffer != null)

this.m_gxBuffer.Dispose();

m_borderRect = new Rectangle

(

this.ClientRectangle.Left

,this.ClientRectangle.Top

,this.ClientRectangle.Right - 1

,this.ClientRectangle.Bottom - 1

);

this.m_bmpBuffer = new Bitmap

(

this.ClientRectangle.Width

, this.ClientRectangle.Height

);

this.m_gxBuffer = Graphics.FromImage(this.m_bmpBuffer);

this.Invalidate();

base.OnResize (e);

}

上面的代码中,开辟了一个m_gxBuffer 缓冲区。并通过重载OnResize函数来调整缓冲区的大小用以适应控件的大小。

protectedoverridevoid OnPaint(PaintEventArgs e)

{

if (Enabled)

{

Pen borderPen = new Pen(m_borderColor);

m_gxBuffer.Clear(this.BackColor);

if (m_border)

m_gxBuffer.DrawRectangle(borderPen, m_borderRect);

}

else

{

Pen disablePen = new Pen(Color.DarkGray);

m_gxBuffer.Clear(Color.Gray);

if (m_border)

m_gxBuffer.DrawRectangle(disablePen, m_borderRect);

}

if (m_bufferOutput)

e.Graphics.DrawImage(m_bmpBuffer,0,0);

}

之后在OnPaint中就开始使用m_gxBuffer来进行缓冲区绘图了。当然在整个OnPaint结束之前应该调用e.Graphics.DrawImage将缓冲区输出到屏幕上。很快一个控件的雏形就出现了。现在给他增加一些功能让他看起来更像是个按钮(而不是现在这个丑样子)

privatebool m_active = false;

private Color m_activeBackColor = Color.LightGray;

private Color m_activeForeColor = Color.FromArgb(74,97,148);

首先我们给控件增加一些有用的属性。比如我们要判断按钮是否被按下了。以及按下按钮时,按钮应该是什么样子的。(最简单的就是改变他的颜色了吧)

不要过多考虑按钮可能出现的状态。比如在普通的使用触摸屏的移动设备上,我们根本无需把Hover特性考虑在内。因为凭借Windows CE你永远不会知道你的笔是否在一个按钮的上方。

几条简单的if语句就可以把状态的判断完全搞定

protectedoverridevoid OnMouseMove(MouseEventArgs e)

{

if (e.Button MouseButtons.Left)

{

if (this.m_active

&& this.ClientRectangle.Contains(e.X, e.Y) false)

{

this.m_active = false;

this.Invalidate();

}

elseif (!this.m_active

&& this.ClientRectangle.Contains(e.X, e.Y) true)

{

this.m_active = true;

this.Invalidate();

}

}

base.OnMouseMove (e);

}

protectedoverridevoid OnMouseDown(MouseEventArgs e)

{

if (e.Button MouseButtons.Left)

{

this.m_active = true;

this.Focus();

this.Invalidate();

}

base.OnMouseDown (e);

}

protectedoverridevoid OnMouseUp(MouseEventArgs e)

{

if (e.Button MouseButtons.Left)

{

this.m_active = false;

this.Invalidate();

}

base.OnMouseUp (e);

}

这样就可以准确的判断出按钮是否被点击(Click)

protectedoverridevoid OnPaint(System.Windows.Forms.PaintEventArgs e)

{

// …

if (this.m_active)

{

m_gxBuffer.Clear(this.m_activeBackColor);

m_gxBuffer.DrawRectangle(activePen, m_borderRect);

if (this.Text.Length > 0)

{

m_gxBuffer.DrawString

(

this.Text

, this.Font, activeForeBrush

,this.TextPosX+ 2

,this.TextPosY+ 1

);

}

}

else

{

base.OnPaint(e);

}

// …

}

好了,现在来看看OnPaint,他利用上面得到的m_active来区分绘制那种状态的按钮。

一个按钮就算基本完成了,下面我们要做的工作就是如何把它加入到我们的ToolBox中,以便随时使用。

由于.NET 对于Design Time(设计时期设计器里看到的控件) Runtime(程序运行时看到的控件)的控件需要分别用不同的方式编译。所以要采用宏定义作为开关来控制一些特性。

首先,DesignTime的控件必须包含System.ComponentModel命名空间。

#if NETCFDESIGNTIME

using System.ComponentModel;

#endif

为了能在设计器里设置控件的属性,还要对这些加以特殊的声明。例如BorderColor属性

#if NETCFDESIGNTIME

[System.ComponentModel.Category("Appearance")]

[System.ComponentModel.Description("Border Color")]

#endif

public Color BorderColor

{

get

{

if (m_borderColor Color.Empty)

m_borderColor = Color.FromArgb(165,165,165);

returnthis.m_borderColor;

}

set

{

this.m_borderColor = value;

this.Invalidate();

}

}

这里System.ComponentModel.Category表示属性的类别,比如Appearance就是外观类。下面的Description看字面就知道是属性的描述了。此外还可以通过加System.ComponentModel.DefaultValue来设置属性的默认值。但是这里DefaultValue只能是一些基本类型。如果是特殊类型比如Color之类,提前初始化就可以了。另外,还可以设置控件的默认处理事件。也就是当在DesignTime双击这个控件时自动安排的处理事件。比如

#if NETCFDESIGNTIME

[System.ComponentModel.DefaultProperty("Text")]

[System.ComponentModel.DefaultEvent("Click")]

#endif

之后进入.NET 2003的命令行窗口进行DesignTime控件的编译

csc /noconfig /define:NETCFDESIGNTIME /target:library /out:CustomButton.dll Button.cs /res:"Bitmaps\CustomControl.Button.bmp"
/r:"C:\Program Files\Microsoft Visual Studio .NET 2003\CompactFrameworkSDK\v1.0.5000\Windows CE\Designer\System.CF.Design.dll"
/r:"C:\Program
Files\Microsoft Visual Studio .NET

2003\CompactFrameworkSDK\v1.0.5000\Windows

CE\Designer\System.CF.Windows.Forms.dll"
/r:"C:\Program Files\Microsoft Visual Studio .NET 2003\CompactFrameworkSDK\v1.0.5000\Windows CE\Designer\System.CF.Drawing.dll"
/r:System.Windows.Forms.dll /r:System.Drawing.dll
/r:System.dll /r:System.XML.dll /r:System.Web.Services.dll
/r:System.Data.dll /nowarn:1595

这里可以添加一个和你控件命名控件同名的BMP文件用来做控件在ToolBox上显示的图标。不然的话,.NET IDE会用一个难看的齿轮代替的。BMP可以用.NET的资源编辑器创建。格式为16×16×256.

最后在.NET IDEToolBox中添加自己的控件就可以使用了。

October 2008

Sun Mon Tue Wed Thu Fri Sat
      1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31  

Friends' Links

Recent Comments

  • jianingy: test read more
  • mmx: thank u very much ! read more
  • FW: pls contact me with email.about APIHook. read more
  • jianingy: 这个lc是啥意思? -------- read more
  • cnhackTNT: 晕,被过滤掉了,再试试: s/(?<!\\)\$NICK/lc/e; 汗,过滤了小于符号,只好写<了呵呵 read more
  • cnhackTNT: s/(? 这样可以少打几个字呵呵 read more
  • R.Q.: 酱紫哦,了了 -------- read more

Archives

Powered by Movable Type 4.21-en