Prism and Xamarin.Forms: IApplicationLifecycle - xamarin

I have a viewmodel that inherits from BindableBase and implements IApplicationLifecycle. However, IApplicationLifecycle.OnResume() and IApplicationLifecycle.OnSleep() is never called on neither iOS nor android.
How do you use IApplicationLifecycle? I cant seem to find any documentation for it. Thanks in advance!
In my App.xaml.cs i have:
NavigationService.NavigateAsync("NavigationPage/MainPage");
and my MainPage.xaml looks like this:
<TabbedPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:PrismApp.Views;assembly=PrismApp"
xmlns:prism="clr-namespace:Prism.Mvvm;assembly=Prism.Forms"
prism:ViewModelLocator.AutowireViewModel="True"
x:Class="PrismApp.Views.MainPage"
Title="MainPage">
<TabbedPage.Children>
<local:APage Icon="tabicon_mapspage.png" />
<local:BPage Icon="tabicon_profilepage.png" />
<local:CPage Icon="tabicon_statuspage.png" />
</TabbedPage.Children>
Finally my MainPageViewModel looks like this:
public class MainPageViewModel : BindableBase, IApplicationLifecycle
{
private string _title;
public string Title
{
get { return _title; }
set { SetProperty(ref _title, value); }
}
public void OnResume()
{
var debug = 42;
}
public void OnSleep()
{
var debug = 42;
}
}
I have put a minimal project of it here: https://github.com/RandomStuffAndCode/PrismApp

Since you are in a TabbedPage the IApplicationAware methods are only being invoked on the TabbedPage.CurrentPage (SelectedTab), as that is the current active page.
By the way, you can change this behavior by overriding the OnResume and OnSleep methods in your app class to achieve your goal. Use the existing code as a guide: https://github.com/PrismLibrary/Prism/blob/master/Source/Xamarin/Prism.Forms/PrismApplicationBase.cs#L171

Related

Xamarin access to entry in other view

I'm developing Multiplatform app through Xamarin.
I'm using custom entry in a separate view and I'm using in some pages of my app
This is my simple code for entry
<ContentView
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="prova.MyView">
<ContentView.Content>
<Entry x:Name="MyEntry"
TextChanged="MyEntry_TextChanged"
Margin="100"/>
</ContentView.Content>
and cs file
public partial class MyView : ContentView
{
public MyView()
{
InitializeComponent();
}
void MyEntry_TextChanged(System.Object sender, Xamarin.Forms.TextChangedEventArgs e)
{
}
}
in my pages I insert entry with this simple code
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="prova.MainPage"
xmlns:pages="clr-namespace:prova">
<StackLayout>
<pages:MyView/>
</StackLayout>
I wonder how can I get when MyEntry_TextChanged is fired in my ContentPage?
one solution is to use MessaggingCenter but I wonder if there's a better and more elegant solution
There are two ways I can think of to do this.
1. Inherit from the Entry class as Jason commented.
public class MyView : Entry
{
public MyView()
{
InitializeComponent();
}
}
This will expose the bindable TextChanged property which you can reference in XAML like you want to do.
2. Create the binding yourself
You can create the binding to a custom "TextChanged" property yourself, but this is more complicated and may achieve the same result with extra effort. You will also need to create a bindable "Text" property. The code below is untested, but uses the bindings I found in the Xamarin.Forms InputView class (which is what Entry derives from). This will be along the lines of what you need to do if you do not do it the way of #1. Exposing bindable properties to XAML will look like this:
public class MyView : ContentView
{
public MyView()
{
InitializeComponent();
}
public string Text
{
get
{
return (string)GetValue(TextProperty);
}
set
{
SetValue(TextProperty, value);
}
}
public static readonly BindableProperty TextProperty = BindableProperty.Create("Text", typeof(string), typeof(MyView), defaultValue: "", propertyChanged:
(bindable, oldValue, newValue) => ((MyView)bindable).OnTextChanged((string)oldValue, (string)newValue));
public event EventHandler<TextChangedEventArgs> TextChanged;
protected virtual void OnTextChanged(string oldValue, string newValue)
{
TextChanged?.Invoke(this, new TextChangedEventArgs(oldValue, newValue));
}
}
I hope my more comprehensive answer helps you choose the direction you want to go for this. If you want to learn more about Bindable Properties, check out Edward's link.

Xamarin binding EventHandler

How can I bind event handler from xaml to ViewModel
in my xamal:
<Entry Text="{Binding SecondName , Mode=TwoWay}" Focused="{Binding FocusedEventhandler}" Completed="{Binding Compleated}">
How can i get that event handler actions in my viewModel?
Try this way
public class TestViewModel
{
public ICommand FocusedEventhandler { get; private set; }
public TestViewModel()
{
FocusedEventhandler = new Command(async () => await ShowContactList());
}
async Task ShowContactList()
{
//your code here
}
}
Call your ViewModel from your page
public partial class TestPage: ContentPage {
public AddContact() {
InitializeComponent();
BindingContext = new TestViewModel();
}
This is just overview, to give you an idea how we can do it.
I believe the proper answer to this question is now to use Behaviors to map from Event Handler to Behavior to Command, in the case that the UI Control's XAML property, e.g. SearchBar.TextChanged, expects an event handler. Please see the documentation here: https://learn.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/behaviors/creating
and here: https://devblogs.microsoft.com/xamarin/turn-events-into-commands-behaviors/

If I use ContentPage.BindingContext in XAML to define my binding context then how do I access that in the C# back end?

In my XAML I define the binding context like this:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:Japanese;assembly=Japanese"
             xmlns:template="clr-namespace:Japanese.Templates"
             xmlns:viewModels="clr-namespace:Japanese.ViewModels; assembly=Japanese"
             x:Class="Japanese.Cards" Title="{Binding Title}">
<ContentPage.BindingContext>
     <viewModels:CardsViewModel />
    </ContentPage.BindingContext>
</ContentPage>
What I would like to know is how can I access this context in my C# back end.
public partial class Cards : ContentPage
{
public Cards()
    {
     InitializeComponent();
        NavigationPage.SetBackButtonTitle(this, "Back");
    }
    protected override void OnAppearing()
    {
     // I want to set some properties of the view here
It seems you cannot give it an x:Name attribute like other elements in your XAML. In that case, your options are limited to declaring the object for your binding context in the code-behind, or referencing it from the BindingContext property.
For the latter approach, do it like this:
protected override void OnAppearing()
{
var cardsViewModel = BindingContext as CardsViewModel;
if (cardsViewModel == null)
return;
cardsViewModel.Property = Value;
}
Earlier answer for reference:
You should be able to give it a name like so:
<ContentPage.BindingContext>
<viewModels:CardsViewModel x:Name="cardsViewModel" />
</ContentPage.BindingContext>
This will effectively just create a declaration like this in generated code:
private CardsViewModel cardsViewModel;
You can now access it in your code-behind:
protected override void OnAppearing()
{
cardsViewModel.Property = Value;
}

How can I make a ViewModel for a Xamarin Forms template?

I have Template1 that inherits from ContentView. For the purpose of this question I removed a lot of things in the template to make it simple.
<?xml version="1.0" encoding="UTF-8"?>
<ContentView xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:local="clr-namespace:Japanese;assembly=Japanese" x:Class="Japanese.Template1" x:Name="this">
<Label Grid.Column="0" Text="{Binding Text, Source={x:Reference this}}" />
</ContentView>
and the Template1 C# back end
namespace Japanese
{
public partial class Template1 : ContentView
{
public CardOrderTemplate()
{
InitializeComponent();
}
}
}
I would like this template to share bindings in this class and so I tried some different ways to do this but none seem to work. Here's what I was trying. Not sure but I guess I need something like a ViewModel for the template but I am not sure how I could go about implementing this.
namespace Japanese
{
public class SegBase : ContentView
{
public static readonly BindableProperty TextProperty = BindableProperty.Create(nameof(Text), typeof(string), typeof(SegTemplate), default(string));
public string Text
{
get { return (string)GetValue(TextProperty); }
set { SetValue(TextProperty, value); }
}
}
}
Does anyone know how I can do this? I tried making the Template1 class inherit from SegBase but it gives me an error because the XAML is a type ContentView and the C# is not inheriting from ContentView.

PrismDryIoc.Forms AutowireViewModel not working

I created a Prism Unity App (from the prism extension pack - really nice), added 2 new views and set up basic navigation between the views. This all worked fine without any hiccups.
What I really want is to use DryIoc (company policy). So I proceeded to remove the unity packages (Unity and Prism.Unity.Forms) and installed the DryIoc Packages (DryIoc and Prism.DryIoc.Forms). Fixed the App.xaml to use the correct namespace (xmlns:prism="clr-namespace:Prism.DryIoc;assembly=Prism.DryIoc.Forms") and alos fixed all the other references to use DryIoc and not the Unity References.
This all compiles and runs without any exceptions. But when I debug it is clear that the AutoWireup does not work as expected (at least as I expect it to). The breakpoint in the ViewModel's constructor (or any other place) is not hit and the Title bindings does not pull through.
Is there a Configuration/Setup or reference that I am missing?
My Code:
App.xaml:
<?xml version="1.0" encoding="utf-8" ?><prism:PrismApplication xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:prism="clr-namespace:Prism.DryIoc;assembly=Prism.DryIoc.Forms"
x:Class="XamFormsPrism.App"></prism:PrismApplication>
App.xaml.cs:
public partial class App : Prism.DryIoc.PrismApplication
{
public App(IPlatformInitializer initializer = null) : base(initializer) { }
protected override void ConfigureContainer()
{
base.ConfigureContainer();
}
protected override void OnInitialized()
{
this.InitializeComponent();
this.NavigationService.NavigateAsync(NavigationLinks.MainPage);
}
protected override void RegisterTypes()
{
this.Container.RegisterTypeForNavigation<MainPage>();
this.Container.RegisterTypeForNavigation<ViewA>();
this.Container.RegisterTypeForNavigation<ViewB>();
}
}
MainPage.xaml:
<?xml version="1.0" encoding="utf-8" ?><ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:prism="clr-namespace:Prism.Mvvm;assembly=Prism.Forms"
prism:ViewModelLocator.AutowireViewModel="True"
x:Class="XamFormsPrism.Views.MainPage"
Title="MainPage"><StackLayout HorizontalOptions="Center" VerticalOptions="Center">
<Label Text="{Binding Title}" />
<Button Text="{Binding NavigateText}" Command="{Binding NavigateCommand}" /> </StackLayout></ContentPage>
MainPageViewModel.cs:
public class MainPageViewModel : BindableBase, INavigationAware
{
private INavigationService navigationService = null;
private string _title = "Jose Cuervo";
public string Title
{
get { return _title; }
set { SetProperty(ref _title, value); }
}
public DelegateCommand NavigateCommand { get; private set; }
public MainPageViewModel(INavigationService navigationService)
{
this.navigationService = navigationService;
this.NavigateCommand = new DelegateCommand(this.navigate, this.canNavigate);
}
private void navigate()
{
this.navigationService.NavigateAsync("ViewA");
}
private bool canNavigate()
{
return true;
}
public void OnNavigatedFrom(NavigationParameters parameters)
{
}
public void OnNavigatedTo(NavigationParameters parameters)
{
if (parameters.ContainsKey("title"))
Title = (string)parameters["title"] + " and Prism";
}
}
As seen above I use the standard naming convention of PageName & PageNameViewModel with the AutoWireUp set to True.
This all worked fine with Unity but I am missing something in DryIoc...but what escapes me.
I have searched the entire project, there is no reference or trace left of Unity.
Any help is much appreciated.
I finally had time again to have a look at this. If I explicit register the ViewModels in the container everything works fine. So I am guessing that there is either a rule missing for the DryIoC container or when using DryIoC you have to explicitly register the ViewModels.

Resources