Xamarin Forms - txgz999/Mobile GitHub Wiki

Activity Indicator

Tried to find counterpart of the progress bar in Android. First tried the program bar in Xamarin Forms. That is not want I want since it is displayed as a line that I need to calculate the progress but I have no idea when a login call will finish and just want an indication that the call is executing. The answer is the ActivityIndicator control. It looks and behaves quite similar to the ProgressBar in Android.

<ActivityIndicator x:Name="LoadingIndicator" Color="Orange" Margin="16" />

But instead of toggling IsVisible property in progress bar in Android, here we toggle the IsRunning property.

Load Image

Images can be embedded in the shared project, or in platform-specific folder. See https://docs.microsoft.com/en-us/xamarin/xamarin-forms/user-interface/images?tabs=macos#using-xaml. In the following I want to use the same xml image file used in Native Android, so I use the second approach:

<Image Source="ic_new.xml" />

This image is stored in the Resources/drawable folder of the Android project.

HasUnevenRows

I have a ListView that uses vertical-oriented StackLayout for each item. It did not display the whole content of the StackLayout, only the top part. The solution is to set the HasUnevenRows attribute to True for the ListView.

XAML Hot Reload

Noticed that when I make a change to the XAML layout file and save it, the emulator refreshes the screen immediately. I see a message "XAML Hot Reload Successful" on the bottom-left corner of the Visual Studio. This is a nice feature.

Xamarin Android vs Xamarin Forms

Converting Xamarin Android project to Xamarin Forms projects takes some effort. For every feature in Xamarin Android, we need to figure out if it can be implemented in the shared project or in the Android project. The latter is more straightforward, but the former is the preference since then it can be shared by platform specific projects. It requires some research to see what is the counterpart of an Android feature in Xamarin Forms, and normally they are not identically.

Xamarin Android Xamarin Forms
SQLiteDatabase sqlite-net-pcl package
PreferenceManager Preferences
LocalBroadcastManager MessagingCenter
AlertDialog DisplayAlert

The Xamarin Android features mostly provided in Mono.Android.dll. The Xamarin Forms features mostly provided in Xamarin.Essentials.dll.

Certain features can be implemented in the Android project only, such as sending local notification. But if part of the feature can be implemented in the shared project, then we better do as much as possible there. One example is the receiving Firebase message. Once we receive a message in the Android project, we call a service class in the shared project to pass the message. Then it is totally in the shared project to implement how to handle the message.

CSS

Xamarin Forms support CSS style sheets, see https://www.youtube.com/watch?v=va-Vb7vtan8.

String Localization

In Native Android and Xamarin Android, we can store string constants in xml resource files. There is similar support in Xamarin Forms. Create a Resource file and enter name-value pairs there. The file extension is .resx and is in xml format. Make sure to select either Internal or Public as the Access Modifier of the Resource file. I guess Internal means it can be used within the shared project and Public means the value can be used in the Xamarin Android project. A Resource .resx file generates a .designer.cs file, which provides grammatical access to those string values defined in teh Resource file, e.g.

internal static string MainPageTitle {
    get {
        return ResourceManager.GetString("MainPageTitle", resourceCulture);
    }
}

The following is an example of using string values in a layout .xaml file:

<ContentPage ...
             xmlns:resx="clr-namespace:xfapp1"
             Title="{x:Static resx:Resource.MainPageTitle}"
             ... >

where the word Resource is used because it the file name of the Resource file. The word resx can be replaced by any word as long as it appears in both xmlns declaration and in the use of the string constants.

See https://docs.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/localization/text?pivots=windows for details.

Dependency Service

Xamarin Forms template creates a shared project, plus platform-specific projects say an Xamarin.Android project, and the latter has project reference to the former. How can these two share data? More specifically, my problem is I need to do something in the Android project, and display some information on screen, but the screen is defined in the shared project. The answer is the dependency service.

  • define an interface in the shared project (states what you want)
    public interface IFCMService
    {
        string GetRegistrationToken();
    }
  • implement the interface in the Android project
    [assembly: Xamarin.Forms.Dependency(typeof(xf200229.Droid.FCMService))]
    namespace xf200229.Droid
    {
        public class FCMService: IFCMService
        {
            public string GetRegistrationToken()
            {
                return FirebaseInstanceId.Instance.Token;
            }
        }
    }
  • finally use dependency service to call the implemented method in the shared project
    var token = DependencyService.Get<IFCMService>().GetRegistrationToken();

For mode details, see the Xamarin Forms Succinctly book Chapter 8 Accessing Platform-Specific APIs.

The following is a good explanation found in https://forums.xamarin.com/discussion/158329/android-specific-event-in-event-handler:

DependencyService allows apps to call into platform-specific functionality from shared code. This functionality enables Xamarin.Forms apps to do anything that a native app can do.

Xamarin.Forms apps need four components to use DependencyService:

  • Interface – The required functionality is defined by an interface in shared code.
  • Implementation Per Platform – Classes that implement the interface must be added to each platform project.
  • Registration – Each implementing class must be registered with DependencyService via a metadata attribute. Registration enables DependencyService to find the implementing class and supply it in place of the interface at run time.
  • Call to DependencyService – Shared code needs to explicitly call DependencyService to ask for implementations of the interface.
Navigation

To make an app to contain multiple pages and support navigation among these pages:

  • in App.xaml.cs, change
    MainPage = new MainPage();
    to
    MainPage = new NavigationPage(new MainPage());
  • set title for each page
  • call Navigation.PushAsync to navigate
    Navigation.PushAsync(new LoginPage());

How to make a label clickable and take user to a different page, like a hyperlink?

The answer is to use a TapGesture

<ListView ItemsSource="{Binding}">
    <ListView.ItemTemplate>
        <DataTemplate>
            <ViewCell>
                <Label Text="{Binding}">
                    <Label.GestureRecognizers>
                        <TapGestureRecognizer Tapped="OnTapped" />
                    </Label.GestureRecognizers>
                </Label>
            </ViewCell>                    
        </DataTemplate>                
    </ListView.ItemTemplate>            
</ListView>
public async void OnTapped(object sender, EventArgs args)
{
    var lbl = sender as Label;
    await Navigation.PushAsync(new DetailPage(lbl.Text));
}
Asynchronous loading in data binding

To data binding to support async loading of data, we need to let the view model class to implement INotifyPropertyChanged, and use ObservableCollection for collection.

public class TimeZoneDetail: INotifyPropertyChanged
{
   private string _datetime;

   [JsonProperty(PropertyName= "datetime")]
   public string Datetime { 
       get
       {
           return _datetime;
       }
       set
       {
           _datetime = value;
           if (PropertyChanged != null)
           {
               PropertyChanged(this, new PropertyChangedEventArgs("Datetime"));
           }
       }
   }

   public event PropertyChangedEventHandler PropertyChanged;
}
FCM

Is it possible we can install FCM in the shared project?

Neither Xamarin.GooglePlayServices.Base nor Xamarin.Firebase.Messaging can be installed there. The error for Xamarin.GooglePlayServices.Base is

Package Xamarin.GooglePlayServices.Base 71.1610.0 is not compatible with netstandard2.0 (.NETStandard,Version=v2.0). Package Xamarin.GooglePlayServices.Base 71.1610.0 supports: monoandroid90 (MonoAndroid,Version=v9.0)

I guess the reason it does not make sense to have Xamarin.GooglePlayServices.Base in the shared project because Google Play Service exists only in Android.

Mac

I installed Visual Studio for MAC on my iMac machine over the weekend, and start to create Xamarin Forms projects. I need to install XCode, which includes iOS SDKs, from Apple Store. After rebooting the machine, now a list of iPhone’s appear in the Simulators drop down, where the default one is iPhone 11 iOS 13.3. Then I can hit hit Run to run the app in the iPhone simulator. Quite cool. The IDE look good, but the build is a little slow, it takes over a minute to build my simple Xamarin Forms app.

It seems that we cannot deploy the app to an iPhone device, unless spending $99 on a developer license.

It seems that we cannot run iOS simulator on Windows, which means if we develop Xamarin for iOS, we need to have a paired mac machine, so we can run the app remotely on the iOS simulator on that Mac machine.

What is the difference between simulate and emulate?

The iOS simulators mimic iOS and run the required application inside it, by sitting on top of the computer's Operating System. Simulators unlike emulators, do not mimic hardware. Thus one cannot investigate certain functionalities like battery usage, cellular interrupts, etc. while using simulators for testing.

Entry Flow
  1. LoadApplication(new App()); MainActivity.OnCreate in Android project
  2. MainPage = new MainPage(); App.App in Shared Project
  3. InitializeComponent(); MainPage.MainPage in Shared Project
Documentation
⚠️ **GitHub.com Fallback** ⚠️