开发者

Subclass TextBox control to draw custom border

I'm trying to make a custom control inherited from TextBox. I'm looking to do some custom drawing of the border of the control. I've run into a few issues in my test application:

1) The TextBox.HandleCreated event is never called when I debug the program. The textbox is visible on the form and I can interact with it, so I know the handle was created. I guess this is being called before I subscribe to the event?

2) WM_NCPAINT message is never received when I debug the program. I know this is called early on in the lifetime of the control. I assume I have the same problem here as I do with issue #1.

Is there any way to resolve these issues using Compact Framework 3.5? Am I doin开发者_开发问答g this the preferred way?

Here is the relevant code:

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);
        }
    }
}


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

This answer contains code for doing this (it will work on CF). This isn't technically sub-classing, but it's a much easier way to achieve this effect.


MSDN says SetWindowLong returns "The previous value of the specified 32-bit integer indicates success. Zero indicates failure."

Are you checking the return value?

The P/Invoke format of SetWindowLong is thus:

/// <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);

Is that how you are declaring SetWindowLong?

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜