lemunk
lemunk

Reputation: 2646

Xamarin set focus MVVM

Using a Portable project in Xamarin.

The ScannerPage.xaml file in the Portable project directory

<?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="StockCheckApp.Views.ScannerPage"
         xmlns:ViewModels="clr-namespace:StockCheckApp.ViewModels;assembly=StockCheckApp"
         FocusManager.FocusedElement="{Binding ElementName=}">
    <Label Text="{Binding MainText}" VerticalOptions="Center" HorizontalOptions="Center" />
    <ContentPage.BindingContext>
        <ViewModels:MainViewModel />
    </ContentPage.BindingContext>

    <StackLayout Orientation="Vertical">
        <Entry Text="{Binding UserInput, Mode=TwoWay}" />
        <Button Text="Check Stock" Command="{Binding PostCommand}"/>

        <ListView ItemsSource="{Binding StockList}" HasUnevenRows="True">
            <ListView.ItemTemplate>
                <DataTemplate>
                    <ViewCell>
                        <StackLayout Orientation="Vertical" Padding="12,6">
                            <Label Text="{Binding St_Code}" FontSize="24" />
                            <Label Text="{Binding St_Desc}" />
                            <Label Text="{Binding Sl_Loc}" />
                            <Label Text="{Binding Sa_Datetime}" />
                            <Label Text="{Binding Sa_Qty}" />
                        </StackLayout>
                    </ViewCell>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
    </StackLayout> 
</ContentPage>

The MainViewModel.cs class inside the Portable directory.

namespace StockCheckApp.ViewModels
{
    public class MainViewModel : INotifyPropertyChanged
    {
        private List<Stock> _stockList;
        private string _userInput;
        public List<Stock> StockList
        {
            get { return _stockList; }
            set
            {
                _stockList = value;
                OnPropertyChanged();
            }
        }

        public string UserInput
        {
            get { return _userInput; }
            set
            {
                _userInput = value;
                OnPropertyChanged();
            }         
        }

        public MainViewModel()
        {
        }

        public Command PostCommand
        {
            get
            {
                return new Command(async () =>
                {
                    var stockService = new StockService();
                    StockList = await stockService.GetStockAsync(UserInput);
                });
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

What I need to do is set the <Entry Text="{Binding UserInput, Mode=TwoWay}" /> to be selected when the app starts and again after the button is clicked.

How is this achieved in my example?

Upvotes: 2

Views: 2722

Answers (1)

Yuri S
Yuri S

Reputation: 5370

Few changes.

  1. Remove in xaml
<ContentPage.BindingContext>
    <ViewModels:MainViewModel />
</ContentPage.BindingContext>

You will need a parameter to constructor of MainViewModel later.

  1. Give a name to your box:
<Entry x:Name="myBox" Text="{Binding UserInput, Mode=TwoWay}" />
  1. The ScannerPage code behind file
public ScannerPage()    
{
    InitializeComponent();
    BindingContext = new MainViewModel(this);
}
        
protected override void OnAppearing()
{
    base.OnAppearing();
    myBox.Focus(); //select when apprears
}        

public Entry MyBox
{
    get
    {
        return myBox;
    }        
}
  1. MainViewModel file
public class MainViewModel : INotifyPropertyChanged
{
    private string _userInput;

    ScannerPage page;
    
    public MainViewModel(ScannerPage parent)
    {
        page = parent;
    }
    
    public string UserInput
    {
        get { return _userInput; }
        set
        {
            _userInput = value;
            OnPropertyChanged();
        }
    }  
    
    public Command PostCommand
    {
        get
        {
            return new Command( () =>
            {
                page.MyBox.Focus(); //set focus when button clicked
            });
        }
    }
     
    public event PropertyChangedEventHandler PropertyChanged;
    
    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

Upvotes: 3

Related Questions