wpfelementhostinputbinding

How to use input bindings for commands when WPF content is hosted in WinForms


I have Windows Forms windows with tab control and one of its tab hosts ElementHost with ContentControl as child element. This control has collection of input bindings which work only when any child element has input focus but if focus is lost they no longer react. Is it possible to define these input bindings on a higher level in such situation?


Solution

  • One solution might be to pass (tunnel) keyboard and/or mouse events from Win Forms to WPF host. I made the following proof of concept. It works but has limitations and requires more work. Firstly you will need a class derived from ElementHost. You should use it in your application instead of the standard ElementHost. This new custom class will have only one additional method ProcessWinFormsKeys which will map WinForms specific keys to those used by WPF. Then it will find a proper input binding and execute it.

        public class CustomElementHost : ElementHost
        {
            public void ProcessWinFormsKeys(Keys keys, Keys modifiers)
            {
                var key = KeyInterop.KeyFromVirtualKey((int)keys);
    
                var modifier = System.Windows.Input.ModifierKeys.None;
    
                if ((modifiers & Keys.Control) != 0)
                    modifier |= System.Windows.Input.ModifierKeys.Control;
    
                if ((modifiers & Keys.Shift) != 0)
                    modifier |= System.Windows.Input.ModifierKeys.Shift;
    
                if ((modifiers & Keys.Alt) != 0)
                    modifier |= System.Windows.Input.ModifierKeys.Alt;
    
                foreach (InputBinding inputBinding in Child.InputBindings)
                {
                    var keyGesture = inputBinding.Gesture as KeyGesture;
    
                    if (keyGesture == null) 
                        continue;
    
                    if(keyGesture.Key == key && keyGesture.Modifiers == modifier)
                        if(inputBinding.Command.CanExecute(inputBinding.CommandParameter))
                            inputBinding.Command.Execute(inputBinding.CommandParameter);
                }
            }
        }
    

    Then in your Form that contains an instance of CustomElementHost you should subscribe KeyDown event and call ProcessWinFormsKeys method within a handler:

        public Form()
        {
            InitializeComponent();
    
            KeyPreview = true;
            KeyDown += Form_KeyDown;
            ...
        }
    
        void Form_KeyDown(object sender, KeyEventArgs e)
        {
           elementHost.ProcessWinFormsKeys(e.KeyCode, e.Modifiers);
        }
    

    Another solution might be to utilize global hot keys. It will require to use RegisterHotKey function from user32.dll. However, I'm not sure if it will work with ElementHost. If you want to try there are a few questions on stackoverflow and dozens of article in Internet.