How to use OnKeyDown in a tab page in Xamarin Forms

jstuardojstuardo Member ✭✭
edited July 4 in Xamarin.Forms

Hello,

I have created a Xamarin Forms project in Visual Studio 2019. Used project template is contains tabs.

That works but I need to do some task when a key is pressed.

That task should be done by a page because it accesses some data that only exist in tab page content.

This is the MainPage.xaml:

<?xml version="1.0" encoding="utf-8" ?>
<TabbedPage xmlns="http://xamarin.com/schemas/2014/forms"
            xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
            xmlns:views="clr-namespace:FinningApp.Views"
            x:Class="FinningApp.Views.MainPage">

    <TabbedPage.Children>
        <NavigationPage Title="Capturas">
            <NavigationPage.Icon>
                <OnPlatform x:TypeArguments="FileImageSource">
                    <On Platform="iOS" Value="tab_feed.png"/>
                </OnPlatform>
            </NavigationPage.Icon>
            <x:Arguments>
                <views:ItemsPage />
            </x:Arguments>
        </NavigationPage>

        <NavigationPage Title="Acerca de">
            <NavigationPage.Icon>
                <OnPlatform x:TypeArguments="FileImageSource">
                    <On Platform="iOS" Value="tab_about.png"/>
                </OnPlatform>
            </NavigationPage.Icon>
            <x:Arguments>
                <views:AboutPage />
            </x:Arguments>
        </NavigationPage>
    </TabbedPage.Children>

</TabbedPage>

The page that should receive the OnKeyDown is ItemsPage whose definition is this:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="FinningApp.Views.ItemsPage"
              Title="{Binding Title}"
             x:Name="BrowseItemsPage">

    <StackLayout>
        <Button x:Name="ReadTags"
                Text="Leer Códigos"
                BackgroundColor="Green"
                TextColor="White"
                FontAttributes="Bold"
                VerticalOptions="Start"
                HorizontalOptions="Fill"
                Clicked="ReadTags_Clicked" />

        <ListView x:Name="ItemsListView"
                ItemsSource="{Binding Items}"
                VerticalOptions="FillAndExpand"
                HasUnevenRows="true"
                RefreshCommand="{Binding LoadItemsCommand}"
                IsPullToRefreshEnabled="true"
                IsRefreshing="{Binding IsBusy, Mode=OneWay}"
                CachingStrategy="RecycleElement"
                ItemSelected="OnItemSelected">
            <ListView.ItemTemplate>
                <DataTemplate>
                    <ViewCell>
                        <StackLayout Padding="10">
                            <Label Text="{Binding Id}" 
                                LineBreakMode="NoWrap" 
                                Style="{DynamicResource ListItemTextStyle}" 
                                FontSize="16" />
                            <Label Text="{Binding Text}" 
                                LineBreakMode="NoWrap"
                                Style="{DynamicResource ListItemDetailTextStyle}"
                                FontSize="13" />
                        </StackLayout>
                    </ViewCell>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
    </StackLayout>

</ContentPage>

I have seen that OnKeyDown exists only in MainActivity.

How can I accomplish this?

Regards
Jaime

Answers

  • LandLuLandLu Member, Xamarin Team Xamurai

    OnKeyDown is a method of Android so you can only see it in the MainActivity.
    What do you want it to be used for? Maybe I can recommend you some alternative ways to achieve it on Forms.

  • jstuardojstuardo Member ✭✭

    Hello,

    First, I created a Xamarin Forms project that has tab pages. The first tab page has a ListView. That tab has also a button with the click event attached:

            private void ReadTags_Clicked(object sender, EventArgs e)
            {
                if (MainPage.Device.IsReading)
                    MainPage.Device.StopReading();
                else
                {
                    MessagingCenter.Send(this, "Clear");
                    MainPage.Device.StartReading();
                }
    
                ReadTags.Text = MainPage.Device.IsReading ? "Stop reading" : "Read tags";
                ReadTags.BackgroundColor = MainPage.Device.IsReading ? Color.Red : Color.Green;
            }
    

    This is not a mobile phone, but a device that capture data by mean of an RFID antenna.

    When the button in the tab page is pressed, the button text is changed and the antenna is activated to start reading RFID tags. If that button is pressed again, antenna is deactivated and button text is changed again to the original value.

    This device has also a keyboard. I need the same functionality explained above but by pressing a key in the keyboard. For instance, if the key in the keyboard is pressed, the ListView in the tab should be cleared, the button change its text and start reading tags.

    List is cleared by mean of a message that is sent to the view. I subscribed to that event by mean of this code in the view model associated to that tab:

                MessagingCenter.Subscribe<ItemsPage>(this, "Clear", async (obj) =>
                {
                    Items.Clear();
                    await DataStore.ClearAsync();
                });
    

    I was thinking about the same but subscribing MainActivity to an event that is to be received by the tab content page, but I don't think it is a good solution.

    For example, I think I could add a code similar to this in ItemsPage constructor:

                    MessagingCenter.Subscribe<MainActivity>(this, "StartReading", async (obj) =>
                    {
                if (MainPage.Device.IsReading)
                    MainPage.Device.StopReading();
                else
                {
                    MessagingCenter.Send(this, "Clear");
                    MainPage.Device.StartReading();
                }
    
                ReadTags.Text = MainPage.Device.IsReading ? "Stop reading" : "Read tags";
                ReadTags.BackgroundColor = MainPage.Device.IsReading ? Color.Red : Color.Green;                        
                    });
    

    Of course I could create a new function so that no code is duplicated, but that is the idea.

    Is that approach correct or there is something else to try?

    Thanks
    Jaime

  • jstuardojstuardo Member ✭✭

    I have just seen that the above solution is not feasible, because I should add that code not in the .Android project, but in the code that is shared with iOS project also.

  • LandLuLandLu Member, Xamarin Team Xamurai

    If it is platform related, you have to create a custom renderer for your main page.
    Receive the event in your custom renderer. Then notify the main page. Both event and messaging center can help you communicate between custom renderer and forms page.
    But please notice that iOS doesn't have such a method to detect the key down event. This thread may be helpful for you: https://stackoverflow.com/questions/3717141/how-to-detect-keyboard-events-on-hardware-keyboard-on-iphone-ios.

  • jstuardojstuardo Member ✭✭

    That OnKeyDown is only for the Android device. For iOS, user will press the on screen button.

    As you know, when creating a project in Visual Studio, 3 projects are actually created, for example, MyApp, MyApp.Android, MyApp.iOS.

    MyApp contains presentation and models. Other projects contains logic depending the platform.

    For MyApp.Android, there is a MainActivity that can receive the OnKeyDown event.

    On the other hand, in MyApp there is the ItemsPage.xaml and ItemsPage.xaml.cs. This view has the button that when clicked, an action is taken. That action reads some data and populates a ListView belonging to the same view.

    What I need to do sounds simple, but I don't know how can be achieved. It can be stated this way: "By pressing a key in the device will be equivalent to press the on-screen button". That's all.

    So, if OnKeyDown is received in the MainActivity, how can I transmit that event to the target view? Is there a way?

    Regards
    Jaime

  • LandLuLandLu Member, Xamarin Team Xamurai

    @jstuardo The easiest way is MessagingCenterhttps://docs.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/messaging-center. Subscribe it on your target page. When OnKeyDown is triggered send a message to notify the target view.

  • jstuardojstuardo Member ✭✭

    Thanks @LandLu.

    I have thought about that, but, in order to subscribe to the event, I will need to do it in the shared project. To subscribe, I need to pass the object type which will send the message. In case of Android, it will be the MainActivity.

    Regards
    Jaime

Sign In or Register to comment.