如何使WPF输入控件在触摸屏中获得焦点时显示虚拟键盘

时间:2013-09-30 03:13:53

标签: wpf wpf-controls touch

对于我们的WPF应用程序,当它在触摸屏(Surface Pro .etc)上运行时,TextBox / PasswordBox控件无法显示虚拟键盘当他们集中注意力时。

在WPF中实现此功能的任何好方法吗?


更新

我们最终想要达到的目标是:

如果用户在PC上运行应用程序,我们不关心此功能,这意味着用户是否有物理键盘,我们什么都不像在PC上运行的普通WPF应用程序那样。

如果用户在Surface Pro上运行,当他点击TextBox时,内置的虚拟键盘会显示出来,而且应该是用户友好的,例如键盘会永远不会掩盖输入元素。


更新2:

那么,WPF不能轻易设置一些属性来实现这个功能吗?在我看来,这个功能应该是内置的WPF,我不明白为什么我找不到一个简单的方法来实现。

8 个答案:

答案 0 :(得分:26)

试试这个,

首先检查物理键盘的存在:

KeyboardCapabilities keyboardCapabilities = new Windows.Devices.Input.KeyboardCapabilities();
return  keyboardCapabilities.KeyboardPresent != 0 ? true : false;

如果找不到物理键盘,请使用Windows的内置虚拟键盘:

Process.Start(Environment.GetFolderPath(Environment.SpecialFolder.System) + Path.DirectorySeparatorChar + "osk.exe");

从这里得到帮助: link 1 link 2

答案 1 :(得分:6)

我发布了一个示例,说明当用户点击文本框时如何在WPF应用程序中触发触控键盘,其位于:

http://code.msdn.microsoft.com/Enabling-Windows-8-Touch-7fb4e6de

这是我多年来一直在努力的事情,我很高兴最终为我们的社区贡献这个榜样。如果示例Q& A窗格中有任何问题,建议,问题等,请告诉我们

答案 2 :(得分:3)

此解决方案非常简单: http://code.msdn.microsoft.com/windowsapps/Enabling-Windows-8-Touch-7fb4e6de

上面的链接详细介绍了这些步骤,以下是简短版本:

  • 添加UIAutomationClient参考
  • 使用来自托管代码的IFrameworkInputPane(链接处的DLL或将inputpanelconfiguration.idl转换为DLL,请参阅以下步骤)
  • 创建新类InkInputHelper以禁用墨迹支持(下面的代码)
  • InkInputHelper.DisableWPFTabletSupport();构造函数或类似的
  • 调用MainWindow
  • 添加using System.Windows.Interop;
  • 添加到MainWindow_Loaded或类似名称:

        System.Windows.Automation.AutomationElement asForm =
        System.Windows.Automation.AutomationElement.FromHandle(new WindowInteropHelper(this).Handle);
        InputPanelConfigurationLib.InputPanelConfiguration inputPanelConfig = new InputPanelConfigurationLib.InputPanelConfiguration();
        inputPanelConfig.EnableFocusTracking();
    

将inputpanelconfiguration.idl转换为DLL

在Windows 8.1上: c:\ Program Files(x86)\ Windows Kits \ 8.1 \ Include \ um \ inputpanelconfiguration.idl

要从IDL构建DLL,请使用以下步骤:

  • 启动命令提示符
  • 使用MIDL编译器工具构建类型库TLB文件
    • 示例:midl /tbld {filename}
  • 使用TLBIMP工具将上面生成的类型库(TLB文件)转换为.NET可以通过运行以下命令使用的DLL
    • 示例:TLBIMP.exe InputpanelConfiguration.tlb /publickey:{pathToKey} /delaysign

InkInputHelper类:

using System;
using System.Reflection;
using System.Windows.Input;

namespace ModernWPF.Win8TouchKeyboard.Desktop
{
public static class InkInputHelper
{
    public static void DisableWPFTabletSupport()
    {
        // Get a collection of the tablet devices for this window.  
        TabletDeviceCollection devices = System.Windows.Input.Tablet.TabletDevices;

        if (devices.Count > 0)
        {
            // Get the Type of InputManager.
            Type inputManagerType = typeof(System.Windows.Input.InputManager);

            // Call the StylusLogic method on the InputManager.Current instance.
            object stylusLogic = inputManagerType.InvokeMember("StylusLogic",
                        BindingFlags.GetProperty | BindingFlags.Instance | BindingFlags.NonPublic,
                        null, InputManager.Current, null);

            if (stylusLogic != null)
            {
                //  Get the type of the stylusLogic returned from the call to StylusLogic.
                Type stylusLogicType = stylusLogic.GetType();

                // Loop until there are no more devices to remove.
                while (devices.Count > 0)
                {
                    // Remove the first tablet device in the devices collection.
                    stylusLogicType.InvokeMember("OnTabletRemoved",
                            BindingFlags.InvokeMethod | BindingFlags.Instance | BindingFlags.NonPublic,
                            null, stylusLogic, new object[] { (uint)0 });
                }
            }
        }
    }
}
}

这应该有效。同样,更好的信息和链接中的可下载示例。我只复制粘贴基础知识以进行存档。

答案 3 :(得分:2)

我创建了一个库来自动化WPF应用程序中TabTip集成的所有内容。

你可以在nuget上获得它,然后你需要的只是你的应用启动逻辑中的简单配置:

TabTipAutomation.BindTo<TextBox>();

您可以将TabTip自动化逻辑绑定到任何UIElement。当指定类型的任何元素将获得焦点时,虚拟键盘将打开,并且当元素将失去焦点时,它将关闭。不仅如此,TabTipAutomation还会将UIElement(或Window)移动到视图中,这样TabTip就不会阻止聚焦元素。

有关详细信息,请参阅project site

答案 4 :(得分:1)

我在TechEd会话中看到了这一点,您需要首先禁用Inking支持(DisableWPFTabletSupport),然后您可以创建一个InputPanelConfiguration(AutomationElement.FromHandle(新的WindowsInteropHelper(this).Handle)并调用EnableFocusTracking。

DisableWPFTabletSupport:http://msdn.microsoft.com/en-us/library/ee230087.aspx

EnableFocusTracking:http://msdn.microsoft.com/en-us/library/windows/desktop/jj126268(v=vs.85).aspx

答案 5 :(得分:1)

答案 6 :(得分:0)

 public static class InkInputHelper
    {
        public static void DisableWPFTabletSupport()
        {
            // Get a collection of the tablet devices for this window.  
            TabletDeviceCollection devices = System.Windows.Input.Tablet.TabletDevices;

            if (devices.Count > 0)
            {
                // Get the Type of InputManager.
                Type inputManagerType = typeof(System.Windows.Input.InputManager);

                // Call the StylusLogic method on the InputManager.Current instance.
                object stylusLogic = inputManagerType.InvokeMember("StylusLogic",
                            BindingFlags.GetProperty | BindingFlags.Instance | BindingFlags.NonPublic,
                            null, InputManager.Current, null);

                if (stylusLogic != null)
                {
                    //  Get the type of the stylusLogic returned from the call to StylusLogic.
                    Type stylusLogicType = stylusLogic.GetType();

                    // Loop until there are no more devices to remove.
                    while (devices.Count > 0)
                    {
                        // Remove the first tablet device in the devices collection.
                        stylusLogicType.InvokeMember("OnTabletRemoved",
                                BindingFlags.InvokeMethod | BindingFlags.Instance | BindingFlags.NonPublic,
                                null, stylusLogic, new object[] { (uint)0 });
                    }
                }
            }
        }
    }

使用该类来确定是否存在可能更适合您需求的物理键盘或类似方式。

我用这个类打开和关闭键盘,无论我想要什么。

 class KeyboardManager
    {

        public static void LaunchOnScreenKeyboard()
        {
            var processes = Process.GetProcessesByName("osk").ToArray();
            if (processes.Any())
                return;
            string keyboardManagerPath = "KeyboardExecuter.exe";
           Process.Start(keyboardManagerPath);
        }

        public static void KillOnScreenKeyboard()
        {
            var processes = Process.GetProcessesByName("osk").ToArray();
            foreach (var proc in processes)
            {
                proc.Kill();
            }
        }
        public static void killTabTip()
        {
            var processes = Process.GetProcessesByName("TabTip").ToArray();
            foreach (var proc in processes)
            {
                proc.Kill();
            }
        }

        public static void LaunchTabTip()
        {
            Process.Start("TabTip.exe");
        }
    }

请记住以下内容: 我添加了osk.exe和tabtip.exe的副本。 在我的程序中添加这个解决了tabtip或osk无法在32/64位上工作的问题。

osk是键盘,tabtip是它的停靠版本。 keyboardexecuter是我制作的一个程序,用作后备方法。

注意*我目前无法在触摸屏设备上进行测试。你必须自己尝试。

为了这一切正常工作我在我的主窗口中使用了这段代码:

public int selectedTableNum;
        public MainWindow()
        {
            InitializeComponent();

            Loaded += MainWindow_Loaded;

            // Disables inking in the WPF application and enables us to track touch events to properly trigger the touch keyboard
            InkInputHelper.DisableWPFTabletSupport();
            //remove navigationbar
            Dispatcher.BeginInvoke(DispatcherPriority.Loaded, new Action(() =>
            {
                var navWindow = Window.GetWindow(this) as NavigationWindow;
                if (navWindow != null) navWindow.ShowsNavigationUI = false;
            }));


            KeyboardManager.LaunchTabTip();

        }

        void MainWindow_Loaded(object sender, RoutedEventArgs e)
        {
            //Windows 8 API to enable touch keyboard to monitor for focus tracking in this WPF application
            InputPanelConfiguration cp = new InputPanelConfiguration();
            IInputPanelConfiguration icp = cp as IInputPanelConfiguration;
            if (icp != null)
                icp.EnableFocusTracking();
            mainFrame.Content = new LoginPage();
        }
        //public bool HasTouchInput()
        //{
        //    foreach (TabletDevice tabletDevice in Tablet.TabletDevices)
        //    {
        //        //Only detect if it is a touch Screen not how many touches (i.e. Single touch or Multi-touch)
        //        if (tabletDevice.Type == TabletDeviceType.Touch)
        //            return true;
        //    }

        //    return false;
        //}

我包含了评论,因为如果出现错误,可能对某人有用。

inputpanel配置:

[Guid("41C81592-514C-48BD-A22E-E6AF638521A6")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IInputPanelConfiguration
{
    /// <summary>
    /// Enables a client process to opt-in to the focus tracking mechanism for Windows Store apps that controls the invoking and dismissing semantics of the touch keyboard.
    /// </summary>
    /// <returns>If this method succeeds, it returns S_OK. Otherwise, it returns an HRESULT error code.</returns>
    int EnableFocusTracking();
}

[ComImport, Guid("2853ADD3-F096-4C63-A78F-7FA3EA837FB7")]
class InputPanelConfiguration
{
}

我希望这可以帮助未来的访问者解决这个问题。

答案 7 :(得分:-2)

不需要SecureString输出时最简单的选择是使用TextBox并使用类似Wingdings的字体作为字体。