2
votes

I have two entries, one for username and the other for password.

<customEntry:EmailEntry Placeholder="Your email address" x:Name="Email" Keyboard="Email" WidthRequest="50" Text="{Binding UserName}"/>

<customEntry:PwdEntry Placeholder="Your password" x:Name="Password" IsPassword="true" Text="{Binding Password}"/>       

The two entries (EmailEntry and PwdEntry) are of type ContentView not ContentPage. I am trying to get the Completed event on the EmailEntry but couldn't. Once the user hits the "Next" button on the keyboard, the focus should shift to PwdEntry.

If these were normal entries, I know that I can use,

Email.Completed += (object sender, EventArgs e) => Password.Focus();

As the two entries are ContentViews, I cannot change the focus to next entry as soon as the user hits "Next".

This is my CustomEntry...

<?xml version="1.0" encoding="UTF-8"?><ContentView xmlns="http://xamarin.com/schemas/2014/forms"
         xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
         x:Class="Ecommerce.Mobile.Core.EmailEntry"
         xmlns:local="clr-namespace:Ecommerce.Mobile.Core.CustomViews"
         xmlns:fr="clr-namespace:Ecommerce.Mobile.Core.Controls">

<ContentView.Content>
    <fr:MyFrame CornerRadius="5" 
           OutlineColor="{StaticResource MocoWhite}" 
           BackgroundColor="Blue" 
           HasShadow="false" Padding="15,0">    

        <Grid ColumnSpacing="16">
                <Grid.RowDefinitions>
                    <RowDefinition Height="50"/>
                    <RowDefinition Height="1"/>
                </Grid.RowDefinitions>

                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="Auto"/>
                    <ColumnDefinition Width="*"/>
                </Grid.ColumnDefinitions>

                <Grid Grid.Column="0" Padding="0,10,0,0" HeightRequest="30" WidthRequest="20">
                    <Image Source="icons_envelope_white1x.png" HorizontalOptions="Start" />
                </Grid>

                <Grid Grid.Column="1" HeightRequest="65" WidthRequest="20">
                    <Label x:Name="HiddenLabel" Font="ProximaNovaRegular" FontSize="12" IsVisible="False" Margin="0" FontAttributes="Bold"/>
                    <fr:MyKeyboardEntry x:Name="EntryField" FontSize="15" TextColor="White" Keyboard="Email" ReturnType="Next" Text="{Binding Text, Mode=TwoWay}" PlaceholderColor="White" Margin="0,12,0,0"/>
                </Grid>
         </Grid>
     </fr:MyFrame>  
</ContentView.Content>

How can I achieve this?

1
@DiegoRafaelSouza, I have now added the custom entry... Please have a look - Krishna Shinde
Expose Completed method in your EmailEntry and TakeFocus method on MyKeyboardEntry. That you could use both accordingly. - EvZ
Sure, go ahead. - EvZ
@EvZ, thanks for your comments. Your suggestion gives me an idea of what should be done but just not clear on how to do it. Do you have a link or sample to which I can refer to. Thanks - Krishna Shinde

1 Answers

2
votes

As I could see you have a lot of nested components wrapped in your own class (a ViewCell in this case).

I bet eventually you'll have a base component, that provides the events you want to expose in your top-level component.

Let's take the Completed event, for example. Supposing you have the bellow structure:

- EmailEntry _inherites from_
   └ MyKeyboardEntry _inherites from_
      └ ...
         └ Entry (provides the `Completed` event)   

So you can subscribe and expose the event on each wrapper:

public class MyKeyboardEntry : View
{
    ...
    // Expose the event
    public event EventHandler<TextChangedEventArgs> TextChanged;

    ...
    // Subscribe the original one with your own handler
    public MyKeyboardEntry()
    {
        ...
        // Its your wrapped Entry object
        entry.TextChanged += OnTextChanged;
        ...
    }

    ...
    // Implementing the @EvZ suggestion
    public void TakeFocus()
    {
        entry.Focus();
    }
    ...
    // Finally, throw up your event notification 
    protected virtual void OnTextChanged(object sender, TextChangedEventArgs args)
    {
        ... // Handle something if you need

        TextChanged?.Invoke(this, args); // invoking the event this class owns using the C# 6 syntax

        /*
        // Using the C# <6
        var hdlr = TextChanged;

        if(hdlr != null) 
            hdlr.Invoke(this, args);
        */
    }

    ...
}

Now you're able to handle the MyKeyboardEntry.TextChanged event outside the class.

You have to do this to each specific class that wraps another more generic (EmailEntry and so on).

I hope it helps.