Click here to Skip to main content
13,197,271 members (57,757 online)
Click here to Skip to main content
Add your own
alternative version


54 bookmarked
Posted 19 Dec 2008

Creating On-Screen Keyboard Using Attached Behavior in WPF

, 19 Dec 2008
Rate this:
Please Sign up or sign in to vote.
An implementation of a numeric on-screen keyboard using attached behaviors in WPF


This article describes an implementation of a numeric on-screen keyboard using attached properties and UserControl in WPF. It can be used in WPF applications just like a Popup control. And, you can easily modify this sample into a full-size on-screen keyboard for any language of your choice.

The source code was compiled and tested against Visual Studio 2008 SP1 with .NET 3.0 as target framework, and the demo EXE will work in either Windows XP or Windows Vista with .NET 3.0 installed.

The Design of the Code

Here are the main design goals at a glance:

  • Enable the on-screen keyboard simply by setting the attached property PopupKeyboard.IsEnabled="true" on any FrameworkElement.
  • Position the control by setting the Placement, PlacementTarget, PlacementRectangle, HorizontalOffset, and VerticalOffset properties, just like you position a Popup control.
  • Switch the keyboard states between Normal and Hidden by double-clicking the FrameworkElement where the keyboard is attached.
  • When the mouse cursor leaves the FrameworkElement, the keyboard will remember its last keyboard state so that it can be used later.

Using the Code

To use the control, you will need to include the files PopupKeyboard.xaml and PopupKeyboard.xaml.cs in your project and then add an xmlns to the window.


After this is set, the following set of attached properties will be available to any FrameworkElement in that Window:


You can check MSDN documentation Popup Placement Behavior on how to set up attached properties Placement, PlacementTarget, PlacementRectangle, HorizontalOffset, VerticalOffset, and CustomPopupPlacementCallback. The attached properties State, Height, and Width set the initial keyboard state (Normal or Hidden), keyboard height and width respectively. And, the last attached properties IsEnabled sets a value that indicates whether the keyboard is available.

Following is a sample on how to set these attached properties:




    local:PopupKeyboard.PlacementTarget="{Binding ElementName=txtEmployeeID}"





Also, you can check the demo source code for more information on how to use the numeric on-screen keyboard.

How It Works

The numeric on-screen keyboard is composed mainly of two classes: PopupKeyboardUserControl and PopupKeyboard. The internal class PopupKeyboardUserControl derives from UserControl that includes XAML and all the logic for the on-screen keyboard. Class PopupKeyboard is a static class that has a reference to an object of PopupKeyboardUserControl and defines all the attached properties needed to display and position the on-screen keyboard.

Next, I will briefly describe how these two classes are actually coded:

1. Keyboard Events Simulation

In order to simulate keyboard events, I use the keybd_event function to synthesize a keystroke, and here is the syntax for the Windows API function:

[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern void keybd_event
	(byte bVk, byte bScan, uint dwFlags, UIntPtr dwExtraInfo);

For every key Button defined in file PopupKeyboard.xaml, its Click event is linked to event handler cmdNumericButton_Click, which includes the logic to simulate keyboard events, for example, when you click Button "btn010300", the following lines of code will be executed, and it simulates a user pressing the keyboard button "Number 1".

// Number 1
case "btn010300":
    keybd_event(VK_1, 0, 0, (UIntPtr)0);
    keybd_event(VK_1, 0, KEYEVENTF_KEYUP, (UIntPtr)0);
    // event already handled
    e.Handled = true;

By modifying the XAML file PopupKeyboard.xaml and changing event handler cmdNumericButton_Click, you can implement any type of on-screen keyboard of your choice, while the rest of the source codes do not need any change.

2. The Keyboard is a Popup Control

Class PopupKeyboardUserControl defines a property called IsOpen that controls whether the keyboard is open or not. When setting IsOpen = true, function HookupParentPopup() is called, which essentially creates a Popup control and attaches the keyboard to it. You can check the relevant source code below:

/// <summary>
/// IsOpen
/// </summary>
public static readonly DependencyProperty IsOpenProperty =
    new FrameworkPropertyMetadata(
        new PropertyChangedCallback(IsOpenChanged)));

public bool IsOpen
    get { return (bool)GetValue(IsOpenProperty); }
    set { SetValue(IsOpenProperty, value); }

/// <summary>
/// PropertyChangedCallback method for IsOpen Property
/// </summary>
/// <param name=""element""></param>
/// <param name=""e""></param>
private static void IsOpenChanged(DependencyObject element, 
				DependencyPropertyChangedEventArgs e)
    PopupKeyboardUserControl ctrl = (PopupKeyboardUserControl)element;

    if ((bool)e.NewValue)
        if (ctrl._parentPopup == null)

/// <summary>
/// Create the Popup and attach the CustomControl to it.
/// </summary>
private void HookupParentPopup()
    _parentPopup = new Popup();

    _parentPopup.AllowsTransparency = true;
    _parentPopup.PopupAnimation = PopupAnimation.Scroll;

    // Set Height and Width
    this.Height = this.NormalHeight;
    this.Width = this.NormalWidth;

    Popup.CreateRootPopup(_parentPopup, this);

3. Defining Attached Properties

Static class PopupKeyboard includes all the necessary attached properties to enable and position the numeric on-screen keyboard. As an example, I list the definition for attached property IsEnabled as follows:

/// <summary>
/// IsEnabled
/// </summary>
public static readonly DependencyProperty IsEnabledProperty =
    new FrameworkPropertyMetadata(false,
        new PropertyChangedCallback(PopupKeyboard.OnIsEnabledChanged)));

public static bool GetIsEnabled(DependencyObject element)
    if (element == null)
        throw new ArgumentNullException("element");

    return (bool)element.GetValue(IsEnabledProperty);

public static void SetIsEnabled(DependencyObject element, bool value)
    if (element == null)
        throw new ArgumentNullException("element");

    element.SetValue(IsEnabledProperty, value);

/// <summary>
/// PropertyChangedCallback method for IsEnabled Attached Property
/// </summary>
/// <param name=""element""></param>
/// <param name=""e""></param>
private static void OnIsEnabledChanged
	(DependencyObject element, DependencyPropertyChangedEventArgs e)
    FrameworkElement frameworkElement = element as FrameworkElement;

    // Attach & detach handlers for events GotKeyboardFocus, 
    // LostKeyboardFocus, MouseDown, and SizeChanged
    if (frameworkElement != null)
        if (((bool)e.NewValue == true) && ((bool)e.OldValue == false))
		new KeyboardFocusChangedEventHandler
		(frameworkElement_GotKeyboardFocus), true);
		new KeyboardFocusChangedEventHandler
		(frameworkElement_LostKeyboardFocus), true);
		new MouseButtonEventHandler(frameworkElement_MouseDown), true);
		new SizeChangedEventHandler(frameworkElement_SizeChanged), true);
        else if (((bool)e.NewValue == false) && ((bool)e.OldValue == true))
		new KeyboardFocusChangedEventHandler
		new KeyboardFocusChangedEventHandler
		new MouseButtonEventHandler(frameworkElement_MouseDown));
		new SizeChangedEventHandler(frameworkElement_SizeChanged));

    Window currentWindow = Window.GetWindow(element);

    // Attach or detach handler for event LocationChanged
    if (currentWindow != null)
        if (((bool)e.NewValue == true) && ((bool)e.OldValue == false))
            currentWindow.LocationChanged += currentWindow_LocationChanged;
        else if (((bool)e.NewValue == false) && ((bool)e.OldValue == true))
            currentWindow.LocationChanged -= currentWindow_LocationChanged;

When setting attached property PopupKeyboard.IsEnabled="true" for a control, event handlers for events GotKeyboardFocus, LostKeyboardFocus, MouseUp, and SizeChanged are added to that control, and event handler for event LocationChanged is added to the current Window. These event handlers contain the logic to enable, hide, and reposition the numeric on-screen keyboard by passing the settings from the attached properties to the relevant property settings inside the PopupKeyboardUserControl object. Essentially, they tie together the attached properties with the internal class PopupKeyboardUserControl.

4. Passing Values in GotKeyboardFocus and LostKeyboardFocus Event Handlers

When event GetKeyboardFocus is fired, a new instance of PopupKeyboardUserControl is created, and the settings from attached properties are passed in as you can see below:

/// <summary>
/// Event handler for GotKeyboardFocus
/// </summary>
/// <param name=""sender""></param>
/// <param name=""e""></param>
private static void frameworkElement_GotKeyboardFocus
	(object sender, System.Windows.Input.KeyboardFocusChangedEventArgs e)
    FrameworkElement frameworkElement = sender as FrameworkElement;

    if (frameworkElement != null)
        if (PopupKeyboard._popupKeyboardUserControl == null)
            _popupKeyboardUserControl = new PopupKeyboardUserControl();

            // Set all the necessary properties
            _popupKeyboardUserControl.Placement = 
            _popupKeyboardUserControl.PlacementTarget = 
            _popupKeyboardUserControl.PlacementRectangle = 
            _popupKeyboardUserControl.HorizontalOffset = 
            _popupKeyboardUserControl.VerticalOffset = 
            _popupKeyboardUserControl.StaysOpen = true;
            _popupKeyboardUserControl.CustomPopupPlacementCallback = 
            _popupKeyboardUserControl.State = PopupKeyboard.GetState(frameworkElement);
            _popupKeyboardUserControl.NormalHeight = 
            _popupKeyboardUserControl.NormalWidth = 

            if (PopupKeyboard.GetState(frameworkElement) == KeyboardState.Normal)
                PopupKeyboard._popupKeyboardUserControl.IsOpen = true;

Similarly, when event LostKeyboardFocus is fired, the latest setting for property State (either Normal or Hidden) is saved, and keyboard is closed by setting IsOpen = false:

/// <summary>
/// Event handler for LostKeyboardFocus
/// </summary>
/// <param name=""sender""></param>
/// <param name=""e""></param>
private static void frameworkElement_LostKeyboardFocus
	(object sender, System.Windows.Input.KeyboardFocusChangedEventArgs e)
    FrameworkElement frameworkElement = sender as FrameworkElement;

    if (frameworkElement != null)
        if (PopupKeyboard._popupKeyboardUserControl != null)
            // Retrieves the setting for the State property
            PopupKeyboard.SetState(frameworkElement, _popupKeyboardUserControl.State);

            PopupKeyboard._popupKeyboardUserControl.IsOpen = false;
            PopupKeyboard._popupKeyboardUserControl = null;


That's it. I hope you'll find this article helpful and instructive, and please vote if you like it.


  • Dec. 20, 2008 - Initial release


This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


About the Author

Weidong Shen
Software Developer (Senior)
United States United States
Weidong has been an information system professional since 1990. He has a Master's degree in Computer Science, and is currently a MCSD .NET

You may also be interested in...


Comments and Discussions

QuestionVB Version Pin
Garethb_8311-Sep-13 3:58
memberGarethb_8311-Sep-13 3:58 
AnswerRe: VB Version Pin
Weidong Shen12-Sep-13 1:16
memberWeidong Shen12-Sep-13 1:16 
GeneralRe: VB Version Pin
Garethb_8312-Sep-13 1:35
memberGarethb_8312-Sep-13 1:35 
GeneralRe: VB Version Pin
Weidong Shen14-Sep-13 18:59
memberWeidong Shen14-Sep-13 18:59 
GeneralRe: VB Version Pin
Garethb_8316-Sep-13 2:36
memberGarethb_8316-Sep-13 2:36 
GeneralRe: VB Version Pin
Garethb_8316-Sep-13 3:17
memberGarethb_8316-Sep-13 3:17 
QuestionGreat Article!!! Need Some Help Please Pin
Ron Mittelman26-Nov-12 12:54
memberRon Mittelman26-Nov-12 12:54 
AnswerRe: Great Article!!! Need Some Help Please Pin
Weidong Shen27-Nov-12 3:30
memberWeidong Shen27-Nov-12 3:30 
GeneralRe: Great Article!!! Need Some Help Please Pin
Ron Mittelman27-Nov-12 6:38
memberRon Mittelman27-Nov-12 6:38 
GeneralRe: Great Article!!! Need Some Help Please Pin
Weidong Shen27-Nov-12 11:27
memberWeidong Shen27-Nov-12 11:27 
GeneralRe: Great Article!!! Need Some Help Please Pin
Ron Mittelman28-Nov-12 6:59
memberRon Mittelman28-Nov-12 6:59 
GeneralRe: Great Article!!! Need Some Help Please Pin
Ron Mittelman28-Nov-12 7:13
memberRon Mittelman28-Nov-12 7:13 
GeneralRe: Great Article!!! Need Some Help Please Pin
Weidong Shen28-Nov-12 14:17
memberWeidong Shen28-Nov-12 14:17 
GeneralRe: Great Article!!! Need Some Help Please Pin
Ron Mittelman29-Nov-12 6:35
memberRon Mittelman29-Nov-12 6:35 
GeneralRe: Great Article!!! Need Some Help Please Pin
Weidong Shen30-Nov-12 14:01
memberWeidong Shen30-Nov-12 14:01 
QuestionValidation when the keypad closes. Pin
Preston Phillips9-Sep-11 4:40
memberPreston Phillips9-Sep-11 4:40 
AnswerRe: Validation when the keypad closes. Pin
Weidong Shen9-Sep-11 5:36
memberWeidong Shen9-Sep-11 5:36 
GeneralRe: Validation when the keypad closes. Pin
Preston Phillips9-Sep-11 6:05
memberPreston Phillips9-Sep-11 6:05 
GeneralRe: Validation when the keypad closes. Pin
Weidong Shen9-Sep-11 16:10
memberWeidong Shen9-Sep-11 16:10 
QuestionSend key is slow Pin
diemtrang30-May-11 0:05
memberdiemtrang30-May-11 0:05 
AnswerRe: Send key is slow Pin
Weidong Shen31-May-11 8:14
memberWeidong Shen31-May-11 8:14 
QuestionHow about SendKeys API? Pin
Georgi Atanasov20-Dec-08 6:17
memberGeorgi Atanasov20-Dec-08 6:17 
AnswerRe: How about SendKeys API? Pin
Weidong Shen20-Dec-08 6:27
memberWeidong Shen20-Dec-08 6:27 
GeneralNice Implementation Pin
sam.hill20-Dec-08 6:02
membersam.hill20-Dec-08 6:02 
GeneralRe: Nice Implementation Pin
Weidong Shen20-Dec-08 6:13
memberWeidong Shen20-Dec-08 6:13 
GeneralOn-screen keyboards Pin
PIEBALDconsult20-Dec-08 4:03
memberPIEBALDconsult20-Dec-08 4:03 
GeneralRe: On-screen keyboards Pin
Weidong Shen20-Dec-08 4:27
memberWeidong Shen20-Dec-08 4:27 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Terms of Use | Mobile
Web04 | 2.8.171020.1 | Last Updated 20 Dec 2008
Article Copyright 2008 by Weidong Shen
Everything else Copyright © CodeProject, 1999-2017
Layout: fixed | fluid