web-dev-qa-db-fra.com

Comment faire en sorte que le contrôle d'entrée WPF affiche le clavier virtuel lorsqu'il est mis au point sur l'écran tactile

Pour notre application WPF, lorsqu'elle s'exécute sur écran tactile (Surface Pro .etc), le contrôle TextBox/PasswordBox ne peut pas afficher clavier virtuel = quand ils se concentrent.

Une bonne façon d'implémenter cette fonctionnalité dans WPF?


Mis à jour:

ce que nous voulons réaliser enfin, c'est quelque chose comme ça:

Si l'utilisateur exécute l'application sur PC, nous ne nous soucions pas de cette fonctionnalité, ce qui signifie que l'utilisateur dispose d'un clavier physique, nous ne faisons rien comme une application WPF normale exécutée sur PC.

Si l'utilisateur s'exécute sur Surface Pro, lorsqu'il clique sur TextBox, le clavier virtuel intégré peut apparaître, et qui devrait être convivial, tel que le clavier ne couvrirait jamais jusqu'à l'élément d'entrée.


Mise à jour 2:

Donc, WPF ne peut pas facilement définir une propriété pour implémenter cette fonctionnalité? À mon avis, cette fonctionnalité devrait être intégrée à WPF, je ne comprends pas pourquoi je ne peux pas trouver un moyen facile d'y parvenir.

27
user1031200

Essaye ça,

Vérifiez d'abord la présence d'un clavier physique:

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

Si vous ne trouvez pas de clavier physique, utilisez le clavier virtuel intégré de Windows:

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

Vous avez de l'aide à partir d'ici: lien 1lien 2

26
Savaratkar

J'ai publié un exemple sur la façon de déclencher le clavier tactile dans les applications WPF lorsqu'un utilisateur clique dans une zone de texte, c'est ici:

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

C'est quelque chose sur lequel je travaille depuis de nombreux mois, je suis heureux de pouvoir enfin contribuer cet exemple à notre communauté. Veuillez me faire savoir s'il y a des questions, suggestions, problèmes, etc. dans l'exemple de volet Q&R

6
Dmitry Lyalin

Cette solution est très simple: http://code.msdn.Microsoft.com/windowsapps/Enabling-Windows-8-Touch-7fb4e6de

Les étapes sont détaillées dans le lien ci-dessus, voici la version courte:

  • Ajouter une référence UIAutomationClient
  • Utilisez IFrameworkInputPane à partir du code managé (DLL au lien ou convertissez inputpanelconfiguration.idl en DLL, voir les étapes ci-dessous)
  • Créez une nouvelle classe InkInputHelper pour désactiver la prise en charge de l'encrage (code ci-dessous)
  • Appelez InkInputHelper.DisableWPFTabletSupport(); depuis MainWindow constructeur ou similaire
  • Ajouter using System.Windows.Interop;
  • Ajouter à MainWindow_Loaded ou similaire:

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

Pour convertir inputpanelconfiguration.idl en DLL

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

Pour créer un DLL à partir de l'IDL, procédez comme suit:

  • Lancer une invite de commande
  • Utilisez l'outil de compilation MIDL pour créer un fichier TLB de bibliothèque de types
    • Exemple: midl /tbld {filename}
  • Utilisez l'outil TLBIMP pour convertir la bibliothèque de types générée ci-dessus (fichier TLB) en un DLL que .NET peut utiliser en exécutant la commande suivante
    • Exemple: TLBIMP.exe InputpanelConfiguration.tlb /publickey:{pathToKey} /delaysign

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

Cela devrait fonctionner. Encore une fois, de bien meilleures informations et un échantillon téléchargeable dans le lien. Je copie uniquement les éléments de base à des fins d'archivage.

3
gakera

J'ai créé une bibliothèque pour automatiser tout ce qui concerne l'intégration TabTip dans l'application WPF.

Vous pouvez l'obtenir sur nuget , et après cela, tout ce dont vous avez besoin est une simple configuration dans la logique de démarrage de vos applications:

TabTipAutomation.BindTo<TextBox>();

Vous pouvez lier la logique d'automatisation TabTip à n'importe quel UIElement. Le clavier virtuel s'ouvrira lorsqu'un élément du type spécifié obtiendra le focus et se fermera lorsque l'élément perdra le focus. Non seulement cela, mais TabTipAutomation déplacera UIElement (ou Window) en vue, de sorte que TabTip ne bloquera pas l'élément focalisé.

Pour plus d'informations, reportez-vous au site du projet .

2

J'ai vu cela fait dans une session TechEd, vous devez d'abord désactiver la prise en charge de l'encrage (DisableWPFTabletSupport), puis vous pouvez créer une InputPanelConfiguration (AutomationElement.FromHandle (nouveau WindowsInteropHelper (this) .Handle)) et appeler 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

1
user895440
1
itsho
 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 });
                    }
                }
            }
        }
    }

utilisez cette classe pour déterminer s'il existe un clavier physique ou une méthode similaire qui pourrait mieux répondre à vos besoins.

j'ai utilisé cette classe pour ouvrir et fermer le clavier où je voulais.

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

gardez à l'esprit ce qui suit: j'ai ajouté une copie de osk.exe ET tabtip.exe. l'ajout de cela dans mon programme a résolu un problème où tabtip ou osk ne fonctionnerait pas sur 32/64 bits.

osk est le clavier, tabtip en est la version ancrée. keyboardexecuter est un programme que j'ai créé qui est utilisé comme méthode de secours.

note * je ne peux actuellement pas tester cela sur un appareil à écran tactile. vous devez l'essayer par vous-même.

pour que tout fonctionne correctement, j'ai utilisé ce code dans ma fenêtre principale:

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

j'ai inclus les commentaires car cela pourrait être utile à quelqu'un s'il y a une erreur.

la configuration du panneau d'entrée:

[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
{
}

j'espère que cela pourrait aider les futurs visiteurs de cette question.

0
ThrowingDwarf