Xamarin Forms Entry Focus When Containing ContentView is Shown - xamarin.forms

I have a MyView.xaml.cs and MyView.xaml which is a ContentView. It has an Entry field.
How do I focus on that Entry field each time MyView is shown on screen?

I think you can use Focus method on your PAGE when your View will be appearing like :
protected override void OnAppearing()
{
base.OnAppearing();
Entry entry = this.FindByName<Entry>("YourEntryName");
entry.Focus();
}

Related

How can I detect focus on child view inside a Tabbed Page in Xamarin.Forms?

I have a TabbedPage, which includes 3 pages (A,B,C). I need to detect (using some override method) when a page is active/selected from tabbed control. I tried some override methods such us OnAppearing with no result, because during debugging process I noticed OnAppearing was fired when TabbedPage was firstly initialized, so when I selected for example the second page (page B) this method was not fired. Is there any optimal way to detect switching between tabs inside child view?
Just like
ToolmakerSteve sayed, the tabbedpage has the CurrentPageChanged event, so you can override the OnCurrentPageChanged() method of the TabbedPage. Such as:
public partial class TabbedPage1 : TabbedPage
{
public TabbedPage1()
{
InitializeComponent();
}
protected override void OnCurrentPageChanged()
{
if(CurrentPage == Children[0])//Children[0] is the page A
{
....
}else if(CurrentPage == Children[1])//Children[1] is the page B
{
.....
}
else
{
......
}
base.OnCurrentPageChanged();
}
}

Update OnPropertyChanged on a Parent View from a child view

In Xamarin for mac, I decided to make multiple views to be used within my main view using the MVVM pattern.
The thing is that I have a ListView within my MainPage which pulls a List of items from a model, and the list is populated within a child view, with its own ViewModel.
When I add a new service from the child view, I would like for the OnPropertyChanged event on the parent view model to trigger.
It is working by navigating to the parent view and setting the animation to false, but this is not really nice looking. It worked though when I had all code within one ViewModel.
How I tried to achieve this, and the errors I got:
0 - Accessing the command within the child model from the parent model, and passing the propertychanged event handler along.
I Couldn't do it. I tried this by making a bindable command like below, but this is not doable for me as I don't think it is possible for the command to know when the property will be changed, which is the whole point of this problem.
If it is doable, I don't know how.
//public static readonly BindableProperty SaveServiceClickedCommandProperty =
// BindableProperty.Create(
// "SaveServiceClicked",
// typeof(Command),
// typeof(NewServiceViewModel),
// null);
1 - Passing the parent view model on the child view model, and put a OnPropertyChanged(nameof(parentModel.List)) at the clicked event handler.
public class ChildViewModel : INotifyPropertyChanged
{
public ICommand AddEntryClickedCommand { get; private set; }
private MainModel mainModel;
// property changed handler
public event PropertyChangedEventHandler PropertyChanged;
void OnPropertyChanged(string name)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
public NewServiceViewModel()
{
Navigation = MainPage;
//async void execute() => await OpenPage();
//OpenPageCommand = new Command(execute, () => !IsBusy);
//async Task OpenPage()
//{
// await Navigation.PushAsync(new MainPage());
//}
// Here I tried to access the data from within the main model.
mainModel = new MainModel(Navigation);
InitMainModel();
void InitMainModel()
{
MainPage mainView = new MainPage();
mainView.BindingContext = mainModel;
}
async void c1() => await AddEntryClicked();
AddEntryClickedCommand = new Command(c1);
}
public async Task<bool> AddEntryClicked()
{
OnPropertyChanged(nameof(mainModel.List))
}
The attempt above created some errors as the object is already populated.
Leading to me thinking that I don't have the right approach altogether.
My solution being to re-introduce the child view within the parent view, and change IsVisible according to the button being clicked or not, as I already did with other smaller component.
I have thought about pulling the list from the child view, but that's raises the same issue of non-null collection.
Of course, the code has been modified to show only the gist.
Thanks in advance.

FreshMvvm - Closing the child page of a page in FreshTabbedNavigationContainer

I have set up a FreshTabbedNavigationContainer with 5 pages.
Within the 5th tabbed page which is a SettingsPage where there is a way to display and AboutPage that is displayed via the SettingsPageModel like this
public Command AboutCommand
{
get
{
return new Command(() =>
{
CoreMethods.PushPageModel<AboutPageModel>();
});
}
}
When the user navigates away by selecting another tab, this other tab is displayed correctly.
If the user selects the SettingsPage via the tab, then the child AboutPage is automatically displayed.
I want to remove AboutPage from the navigation stack when another tab page is selected.
I have tried this in the AboutPage.xaml.cs
protected override void OnDisappearing()
{
base.OnDisappearing();
((AboutPageModel)BindingContext).CoreMethods.RemoveFromNavigation();
}
This works BUT if the back button is pressed on the app when in the AboutPage then it has already been removed from the navigation stack, and the app crashes.
How can I check if a PageModel is still in the navigation stack?
I have managed to resolve the problem :)
In the App.xaml.cs file in the App constructor where I create the FreshTabbedNavigationContainer, after setting the MainPage
MainPage = tabbedNavigation;
I then add the following code
tabbedNavigation.CurrentPageChanged += (sender, e) => {
tabbedNavigation.PopToRoot();
};
It works perfectly.

Tabbed Page OnAppearing()

I have a Tabbed Page Xamarin Form application that I am trying to customize. I am migrating from an IOs only app to all platforms. In iOS there are a couple function that I used ViewDidDisappear(), ViewDidAppear() and ViewDidLoad();
The application today loads the tabbed page as follows:
{
Children.Add(new MyPage1());
Children.Add(new MyPage2());
Children.Add(new MyPage3());
Children.Add(new MyPage4());
}
Each of the child pages are declared as follows all inheriting from ContentPage.
class MyPage1: ContentPage
{
…
protected override void OnAppearing()
{
base.OnAppearing();
Content = SomeContentPage;
}
}
The problem that I am running into is that the OnAppearing() is called for all pages when only MyPage1 is currently displayed. I need to know when each child page is loaded.
I have read about message center but I am not sure how to implement it in this particular case. Would the message center be the best solution for this?
How do I implement a solution that will allow me to know which of the four pages is displayed?
Possible workaround would be to override OnCurrentPageChanged in your TabbedPage.
protected override void OnCurrentPageChanged()
{
base.OnCurrentPageChanged();
if ( CurrentPage is YourContentPage page)
{
page.YourCustomCode();
}
}
On the main TabbedPage, after you've added child pages, setting the CurrentPage property to null should fix the problem.

CaliburnMicro StackOverflowException when ActivateItem function is invoked

I have two VM - View (inherited from Screen) and Edit (inherited from Screen). View is used to display grid with data and Edit - add/edit new items into grid.
In my ShellViewModel I have the following code to activate View.
public void WorkstationView()
{
this.ActivateItem(ServiceLocator.Current.GetInstance<WorkstationViewModel>());
}
In WorkstationViewModel when user clicks on the Create button the following code is invoked
public void CreateAction()
{
EditableObject = new WorkstationDto();
TryClose(true);
}
And there is a listener to Deactivated event property, see code below (InitViewModels is invoked in ShellViewModel constructor).
private void InitViewModels()
{
#region Init
WorkstationViewModel = ServiceLocator.Current.GetInstance<WorkstationViewModel>();
WorkstationEditViewModel = ServiceLocator.Current.GetInstance<WorkstationEditViewModel>();
#endregion
#region Logic
WorkstationViewModel.Deactivated += (o, args) =>
{
if (WorkstationViewModel.EditableObject == null)
{
return;
}
WorkstationEditViewModel.EditableObject = WorkstationViewModel.EditableObject;
ActivateItem(WorkstationEditViewModel);
};
#endregion
}
The problem here is a StackOverflow exception when I close Edit view (see create action).
“Since the Conductor does not maintain a “screen collection,” the activation of each new item causes both the deactivation and close of the previously active item.” Caliburn.Micro documentation
If you are using Conductor<T>, then ActivateItem(WorkstationEditViewModel); inside of the Deactivated handler is implicitly re-triggering the deactivation of the previous viewmodel - giving you an infinite loop. Try changing your conductor to inherit from Conductor<IScreen>.Collection.OneActive instead. However, you will still have two deactivations: the one from the original TryClose operation, and a second one when you activate the new screen. Overriding DetermineNextItemToActivate can help you avoid that.

Resources