how to make a accelerator key for Xamarin.Forms button ?

lihuipeng49lihuipeng49 Member ✭✭✭
edited June 30 in Xamarin.Forms

I want make a accelerator key for my Xamarin.Forms button on UWP.
My app is a chat app, on Android the user like to press the Send Button.
But on UWP when it run on desktop, the user like to use the accelerator key to trigger the Send Button event.
Can I do this for UWP in Xamarin.Forms ?

Best Answers

  • lihuipeng49lihuipeng49 ✭✭✭
    Accepted Answer

    This is the final solution.

    MainPage.xaml

    <local:MyEditor Placeholder="输入聊天信息" VerticalOptions="StartAndExpand" HorizontalOptions="FillAndExpand"
                        HeightRequest="50" MaxLength="2000"
                       x:Name="sendText"/>
    

    MyEditor.cs

    namespace ChannelChat
    {
        public class MyEditor : Editor
        {
        }
    }
    

    MyEditorRenderer.cs

    namespace ChannelChat.UWP
    {
        public class MyEditorRenderer : EditorRenderer
        {
            protected override void OnElementChanged(ElementChangedEventArgs<Editor> e)
            {
                base.OnElementChanged(e);
    
                if (Control == null)
                {
                    return;
                }
    
                if (e.OldElement != null)
                {
                    Control.PreviewKeyDown -= Control_PreviewKeyDown;
                }
    
                if (e.NewElement != null)
                {
                    Control.PreviewKeyDown += Control_PreviewKeyDown;
                }
            }
    
            private void Control_PreviewKeyDown(object sender, Windows.UI.Xaml.Input.KeyRoutedEventArgs e)
            {
                if (e.Key == Windows.System.VirtualKey.Enter)
                {
                    e.Handled = true;
                    MainCtrl.SendChatMessage(Control.Text, false);
                    Control.Text = "";
                }
            }
        }
    }
    

Answers

  • Amar_BaitAmar_Bait DZMember ✭✭✭✭✭

    Create a custom renderer for Button in the UWP project and implement the Accelerator functionality

  • JohnHardmanJohnHardman GBUniversity mod
    edited June 30

    Or a custom renderer implementing https://docs.microsoft.com/en-us/windows/uwp/design/input/access-keys (this is how I did it - I just wanted Alt+key combinations)

  • lihuipeng49lihuipeng49 Member ✭✭✭

    To take care of user habits, the accelerator key need be 'Ctrl + Enter'.
    I think use custom renderer for a ContentPage maybe is OK like Button.
    I am trying the method of @Amar_Bait .
    Because I am new to Xamarin, so I need to think how to write the code.

    My app named ChannelChat.
    I think I need write code to 2 project, ChannelChat and ChannelChat.UWP.

  • JohnHardmanJohnHardman GBUniversity mod

    @lihuipeng49 said:
    My app named ChannelChat.
    I think I need write code to 2 project, ChannelChat and ChannelChat.UWP.

    Yes, that's correct. The custom renderer will be in ChannelChat.UWP. You will also want to subclass Button in ChannelChat to add one or more properties that the custom renderer will access to get the key combination (key + modifier) to use,. You might want to add further properties for specifying the method to invoke, if not just triggering the Button's Command.

  • Amar_BaitAmar_Bait DZMember ✭✭✭✭✭
    edited June 30

    If you're doing a custom renderer for your whole ContentPage instead of the send button, then no need to write code in the shared project, just UWP.

    Xamarin docs have exactly this use case, check it, try to implement it, and if you have any question don't hesitate.

  • lihuipeng49lihuipeng49 Member ✭✭✭

    @Amar_Bait
    I successfully create a custom renderer.
    And the program running can hit my break point.
    But the next , I don't how to detect the 'Enter' or 'Ctrl+Enter' key press at the custom renderer.

  • lihuipeng49lihuipeng49 Member ✭✭✭

    This is worked:

                            Modifiers = VirtualKeyModifiers.Control,
                            Key = VirtualKey.R,
    

    This is not:

                            Modifiers = VirtualKeyModifiers.Control,
                            Key = VirtualKey.Enter,
    

    I think the Editor catch the Enter key first caught the problem.

    My final need is press 'Ctrl+Enter' in the Editor can do the send operate.

  • Amar_BaitAmar_Bait DZMember ✭✭✭✭✭
    edited July 1

    In that case you need to create a custom renderer for the Editor and implement the same code (this.Control. KeyboardAccelerators instead of this.KeyboardAccelerators), or maybe just use Control.KeyDown event instead of KeyboardAccelerators

  • lihuipeng49lihuipeng49 Member ✭✭✭

    I like to use Control.KeyDown with PageRenderer for ContentPage.
    I this this simple than create a custom renderer for Editor.
    So, can you give me a code sample for the Control.KeyDown?
    The final, when user press Enter key in Editor, the program do the send operate, is OK.

  • Amar_BaitAmar_Bait DZMember ✭✭✭✭✭
    edited July 1

    Sorry I can't give you any more code, I gave you more than enough so you can understand the basics of custom renderers and how to write platform specific code. I can help you, not write code for you. So you need to actually write code before asking questions.

    Just Google how to create a custom renderer for a control (Xamarin documentation is very good) and there are tons of articles and forum topics on this subject. Same thing for KeyDown implementation (it didn't change from the year I started programming for Windows on VB5) just Google for eg. "how to capture enter key in textbox uwp" I didn't check the results, but I'm sure you will find something.

  • lihuipeng49lihuipeng49 Member ✭✭✭

    Thanks!
    I know the google keyword is ok.

  • lihuipeng49lihuipeng49 Member ✭✭✭
    namespace ChannelChat
    {
        public class MyEditor : Editor
        {
        }
    }
    
    
    [assembly: ExportRenderer(typeof(MyEditor), typeof(MyEditorRenderer))]
    namespace ChannelChat.UWP
    {
        public class MyEditorRenderer : EditorRenderer
        {
            protected override void OnElementChanged(ElementChangedEventArgs<Editor> e)
            {
                base.OnElementChanged(e);
    
                if (Control == null)
                {
                    return;
                }
    
                if (e.OldElement != null)
                {
                    Control.KeyDown -= Control_KeyDown;
                }
    
                if (e.NewElement != null)
                {
                    Control.KeyDown += Control_KeyDown;
                }
            }
    
            private void Control_KeyDown(object sender, Windows.UI.Xaml.Input.KeyRoutedEventArgs e)
            {
                System.Diagnostics.Debug.WriteLine(e.Key);
    
                if (e.Key == Windows.System.VirtualKey.Enter)
                {
                    // only the Enter key can't go here
                }
            }
        }
    }
    

    I find the way to create custom renderer for the Editor, and I success!
    But the Enter problem also.
    KeyDown event for any key can catch by the Control_KeyDown , only Enter key can't.

  • lihuipeng49lihuipeng49 Member ✭✭✭

    The accelerator key for the Editor I had try too.
    Result is also only Enter key event can't catch.

  • Amar_BaitAmar_Bait DZMember ✭✭✭✭✭
    edited July 2
    Try VirtualKey.Return instead of Enter if it exists? Also try to listening to Control.PreviewKeyDown instead of Control.KeyDown event
  • lihuipeng49lihuipeng49 Member ✭✭✭

    There is no VirtualKey.Return in Xamarin.
    I use Control.PreviewKeyDown, it can catch the Enter press event.

            private void Control_PreviewKeyDown(object sender, Windows.UI.Xaml.Input.KeyRoutedEventArgs e)
            {
                if (e.Key == Windows.System.VirtualKey.Enter)
                {
                    MainCtrl.SendChatMessage(Control.Text, false);
                    Control.Text = "";
                }
            }
    

    The code upon can finish the work.
    But there is another thing need to fix.

    The Enter press also do the line break.
    After the run of my code, the Editor will have 2 empty lines.

    I need find some way to block the Enter event post to the default process system.
    I had study Xamarin just 2 month, I am not use C# before.
    Even I don't know where to find the Xamarin official document for the EditorRenderer and PreviewKeyDown.

    I had use MFC and C++ to develop for years.
    The MFC use windows message pump to send event, so it can block the key press event at the PreKeyDown event process function.
    But in Xamarin can't do this.
    The PreviewKeyDown function have no return param, so I think it can't use the function return value to do some work to block the event post to next system.

  • lihuipeng49lihuipeng49 Member ✭✭✭

    Yes, use e.Handled = true it worked.
    Thank your for help me.
    Thanks Amar_Bait help me step by step.

  • lihuipeng49lihuipeng49 Member ✭✭✭
    Accepted Answer

    This is the final solution.

    MainPage.xaml

    <local:MyEditor Placeholder="输入聊天信息" VerticalOptions="StartAndExpand" HorizontalOptions="FillAndExpand"
                        HeightRequest="50" MaxLength="2000"
                       x:Name="sendText"/>
    

    MyEditor.cs

    namespace ChannelChat
    {
        public class MyEditor : Editor
        {
        }
    }
    

    MyEditorRenderer.cs

    namespace ChannelChat.UWP
    {
        public class MyEditorRenderer : EditorRenderer
        {
            protected override void OnElementChanged(ElementChangedEventArgs<Editor> e)
            {
                base.OnElementChanged(e);
    
                if (Control == null)
                {
                    return;
                }
    
                if (e.OldElement != null)
                {
                    Control.PreviewKeyDown -= Control_PreviewKeyDown;
                }
    
                if (e.NewElement != null)
                {
                    Control.PreviewKeyDown += Control_PreviewKeyDown;
                }
            }
    
            private void Control_PreviewKeyDown(object sender, Windows.UI.Xaml.Input.KeyRoutedEventArgs e)
            {
                if (e.Key == Windows.System.VirtualKey.Enter)
                {
                    e.Handled = true;
                    MainCtrl.SendChatMessage(Control.Text, false);
                    Control.Text = "";
                }
            }
        }
    }
    
Sign In or Register to comment.