子类TextBox控件绘制自定义边框

时间:2011-10-06 17:28:41

标签: windows-mobile

我正在尝试从TextBox继承自定义控件。我正在寻找一些控件边框的自定义绘图。我在测试应用程序中遇到了一些问题:

1)调试程序时,永远不会调用TextBox.HandleCreated事件。文本框在表单上可见,我可以与它交互,所以我知道句柄已创建。我想这是在我订阅活动之前被调用的?

2)调试程序时从未收到WM_NCPAINT消息。我知道这是在控制生命的早期调用的。我假设我在这里遇到与问题#1相同的问题。

有没有办法使用Compact Framework 3.5解决这些问题?我这样做是首选吗?

以下是相关代码:

public class ETextBox : TextBox
{
    private IntPtr mOldWndProc;
    private Win32Helper.WndProcDelegate mNewWndProc;

    public ETextBox(Rectangle rc)
    {
        HandleCreated += new EventHandler(ETextBox_HandleCreated);
        HandleDestroyed += new EventHandler(ETextBox_HandleDestroyed);
        Bounds = rc;
    }

    public ETextBox(String s, Rectangle rc)
        : this(rc)
    {
        Text = s;
    }

    private void SubclassWindow()
    {
        mOldWndProc = Win32Helper.GetWindowLong(Handle, Win32Helper.GWL_WNDPROC);
        mNewWndProc = new Win32Helper.WndProcDelegate(WindowProc);
        Win32Helper.SetWindowLong(Handle, Win32Helper.GWL_WNDPROC, Marshal.GetFunctionPointerForDelegate(mNewWndProc));
    }

    private void UnsubclassWindow()
    {
        if (mOldWndProc == IntPtr.Zero)
            throw new InvalidOperationException();
        Win32Helper.SetWindowLong(Handle, Win32Helper.GWL_WNDPROC, mOldWndProc);
    }

    private void ETextBox_HandleDestroyed(object sender, EventArgs e)
    {
        UnsubclassWindow();
    }

    private void ETextBox_HandleCreated(object sender, EventArgs e)
    {
        SubclassWindow();
    }

    private IntPtr WindowProc(IntPtr hwnd, uint msg, IntPtr wParam, IntPtr lParam)
    {
        switch (msg)
        {
            case Win32Helper.WM_ERASEBKGND:
                return IntPtr.Zero;

            case Win32Helper.WM_NCPAINT:
                return IntPtr.Zero;

            default:
                return Win32Helper.CallWindowProc(mOldWndProc, hwnd, msg, wParam, lParam);
        }
    }
}

2 个答案:

答案 0 :(得分:1)

Is there a way to implement a flat TextBox in C#?

这个答案包含执行此操作的代码(它适用于CF)。这在技术上不是分类,但它是一种更容易实现这种效果的方法。

答案 1 :(得分:1)

MSDN表示SetWindowLong返回“指定的32位整数的前一个值表示成功。零表示失败。

你在检查返回值吗?

SetWindowLong P/Invoke format因此:

/// <summary>
/// Changes an attribute of the specified window. The function also sets the 32-bit (long) value at the specified offset into the extra window memory.
/// </summary>
/// <param name="hWnd">A handle to the window and, indirectly, the class to which the window belongs..</param>
/// <param name="nIndex">The zero-based offset to the value to be set. Valid values are in the range zero through the number of bytes of extra window memory, minus the size of an integer. To set any other value, specify one of the following values: GWL_EXSTYLE, GWL_HINSTANCE, GWL_ID, GWL_STYLE, GWL_USERDATA, GWL_WNDPROC </param>
/// <param name="dwNewLong">The replacement value.</param>
/// <returns>If the function succeeds, the return value is the previous value of the specified 32-bit integer. 
/// If the function fails, the return value is zero. To get extended error information, call GetLastError. </returns>
[DllImport("user32.dll")]
static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);

这是你宣布SetWindowLong的方式吗?