

Embedding Xamarin.Forms in Native Apps – .NET Development Addict
source link: https://dotnetdevaddict.co.za/2017/06/21/embedding-xamarin-forms-in-native-apps/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

.NET Development Addict
Home is where the [.net] compiler is.
Xamarin.Forms is really cool! It allows you to almost write your app once and then compile for many platforms. With Xamarin.Forms, you can quickly produce multiple apps, but, you can also take advantage of some awesome features – such as cross-platform UIs in XAML, data binding, sharing code and much more.
Xamarin.iOS, Xamarin.Android and UWP are also fantastic! You can get 100% of the platform APIs and you can produce apps that are super fast and polished.
Most of the time you have to choose between one or the other. Sure, you can do custom renderers or effects in Xamarin.Forms to get more platform API access. And sure, you can use frameworks that help you share code with native Xamarin and Windows apps. Before today, you had one of two choices:
- Xamarin.Forms for 100% shared code and UI
- Xamarin/Windows Native for polished, platform-specific APIs and UIs
But… why not have both? Recently Xamarin/Microsoft shared on the blog that Xamarin.Forms can be embedded into native apps. This means that you can take your existing (or new) native app and just drop in a Xamarin.Forms page without doing anything special. You lose nothing, and gain a whole lot more. You can still use XAML, data binding, converters, effects and everything else that comes with Xamarin.Forms – but now from within you native app code and UI.
I have a nice sample app that you can pull from GitHub. Be sure to check it out and let me know what you think of this new functionality. I will try and keep that repository up to date with any new developments.
Getting the Bits
To embed Xamarin.Forms into your native app, you just need to install a preview NuGet from the Xamarin.Forms pre-release feed:
Then, you want to install the 3.0.0.100-embeddingpreview
NuGet into any Xamarin.Forms projects as well as into the native app projects.
That is it! Now you should be able to create your shared page.
If you have any questions or comments you can do this using the Xamarin discussion (Preview: Xamarin.Forms Embedding) on the forums.
It is important to note that this is a pre-release and functionality may change with subsequent releases.
Creating Shared Pages
Let’s take an example of an existing app that you want to add the ability to register and/or login to save user preferences on some cloud service – such as Azure. Your app is out and in the wild, users are loving it, and, you have just received feedback that they want to login across devices and keep their preferences.
What do you do? Well you could create a few screens for each platform and then share some code. But, as all the login screens are going to look the same and work the same, why not do everything in shared XAML?
So, the first thing we can do is to either create a shared project, a .NET Standard library or even a PCL. We then just need to install the pre-release Xamarin.Forms NuGet. Finally, we can go ahead an add a new XAML page. Just right-click and do “Add” > “New Item…” > “Content Page (XAML)” and then you have a new page.
In this page below, I am using data binding, converters, resource dictionaries and good old XAML markup:
<?
xml
version
=
"1.0"
encoding
=
"utf-8"
?>
xmlns:app
=
"clr-namespace:EmbeddedFormsDemo.Converters"
x:Class
=
"EmbeddedFormsDemo.Views.LoginPage"
>
<
ContentPage.Resources
>
<
ResourceDictionary
>
<
app:NegateConverter
x:Key
=
"Negate"
/>
<
app:NullInvisibilityConverter
x:Key
=
"NullInvisibility"
/>
</
ResourceDictionary
>
</
ContentPage.Resources
>
<
ScrollView
>
<
Grid
>
<
Grid.RowDefinitions
>
<
RowDefinition
Height
=
"*"
/>
<
RowDefinition
Height
=
"Auto"
/>
<
RowDefinition
Height
=
"*"
/>
</
Grid.RowDefinitions
>
<
StackLayout
Spacing
=
"12"
Grid.Row
=
"1"
>
<
StackLayout.Padding
>
<
OnPlatform
x:TypeArguments
=
"Thickness"
Android
=
"24"
iOS
=
"24"
WinPhone
=
"0"
/>
</
StackLayout.Padding
>
<
Label
Text
=
"Enter any username/password:"
HorizontalTextAlignment
=
"Center"
FontSize
=
"12"
/>
<
Entry
Keyboard
=
"Email"
Placeholder
=
"username or email"
Text
=
"{Binding UserName}"
HorizontalTextAlignment
=
"Center"
IsEnabled
=
"{Binding IsBusy, Converter={StaticResource Negate}}"
/>
<
Entry
IsPassword
=
"True"
Placeholder
=
"password"
Text
=
"{Binding Password}"
HorizontalTextAlignment
=
"Center"
IsEnabled
=
"{Binding IsBusy, Converter={StaticResource Negate}}"
/>
<
Button
Text
=
"Log In"
Command
=
"{Binding LoginCommand}"
IsEnabled
=
"{Binding IsBusy, Converter={StaticResource Negate}}"
/>
<
Label
Text
=
"{Binding ErrorMessage}"
HorizontalTextAlignment
=
"Center"
FontSize
=
"12"
TextColor
=
"Red"
IsVisible
=
"{Binding ErrorMessage, Converter={StaticResource NullInvisibility}}"
/>
<
ActivityIndicator
IsRunning
=
"{Binding IsBusy}"
IsVisible
=
"{Binding IsBusy}"
/>
</
StackLayout
>
</
Grid
>
</
ScrollView
>
</
ContentPage
>
Then, in our code-behind, we can write out code to work with the UI. Here we have made use of several features such as binding, commands, messaging and async/await:
[XamlCompilation(XamlCompilationOptions.Compile)]
public
partial
class
LoginPage : ContentPage
{
public
const
string
LoginMessage =
"login"
;
private
readonly
JsonPlaceholderApi api;
private
string
errorMessage;
public
LoginPage()
{
InitializeComponent();
// initialize our fake services
api =
new
JsonPlaceholderApi();
// set up the data binding
LoginCommand =
new
Command(OnLogin);
BindingContext =
this
;
}
private
async
void
OnLogin()
{
IsBusy =
true
;
// reset errors
ErrorMessage =
""
;
// try logging in with our fake services
var
user =
await
api.LoginAsync(UserName, Password);
if
(user ==
null
) {
// there was an error
ErrorMessage =
"There was a problem logging in."
;
}
else
{
// let the app know we are finished
MessagingCenter.Send(user, LoginMessage);
}
IsBusy =
false
;
}
public
string
ErrorMessage
{
get
{
return
errorMessage; }
set
{ errorMessage = value; OnPropertyChanged(); }
}
// we don't want to save this as the user types
public
string
UserName {
get
;
set
; }
// we don't want to save this at all
public
string
Password {
get
;
set
; }
// the login button uses this
public
ICommand LoginCommand {
get
; }
}
That is basically all we need to do in order to create our UI. The JsonPlaceholderApi
type just makes use of http://jsonplaceholder.typicode.com
to get some random data, the User
type is just a simple POCO object and the converters are basic IValueConverter
implementations.
Displaying Shared Pages in Native Apps
Once we have created our shared Xamarin.Forms page, we can just instantiate out Xamarin.Forms page and then ask for the native version.
On Android, the CreateFragment
extension method will return a native Android Fragment
, which we can then use as we would any other fragment. On iOS, we use the CreateViewController
extension method and we will get out a native UIViewController
that, again, we can use as we would any other view controller. And finally, on Windows, we use the CreateFrameworkElement
extension method to get out a native FrameworkElement
that we can also uses as any other element.
There are two steps to obtaining this native container, first we make sure Xamarin.forms is initialized:
// Android
Xamarin.Forms.Forms.Init(
this
,
null
);
// iOS
Xamarin.Forms.Forms.Init();
// Windows
// the `e` from `Application.OnLaunched(LaunchActivatedEventArgs e)`
Xamarin.Forms.Forms.Init(e);
Once that is done, we can then get the native page:
// create the Xamarin.Forms page for all platforms
var
formsPage =
new
MyFormsPage();
// Android - get the native Fragment
var
nativeFragment = formsPage.CreateFragment(
this
);
// iOS - get the native UIViewController
var
nativeController = formsPage.CreateViewController();
// Windows - get the native FrameworkElement
var
nativeElement = formsPage.CreateFrameworkElement();
Now that we have the native view, we can just go ahead and use it as if it was created using the traditional mechanisms.
Xamarin.Android and Xamarin.Forms
When using Xamarin.Forms with an Android app, we are going to need to handle the native Fragment
that represents the page. To this end, our Android app is using a native .axml
layout with a FrameLayout
that will hold all our fragments:
<?
xml
version
=
"1.0"
encoding
=
"utf-8"
?>
android:layout_width
=
"fill_parent"
android:layout_height
=
"fill_parent"
>
<!-- the other bits of UI -->
<
FrameLayout
android:layout_width
=
"fill_parent"
android:layout_height
=
"fill_parent"
android:id
=
"@+id/frameLayout"
/>
<!-- some more UI -->
</
RelativeLayout
>
Then, in our main activity code, we load this UI as normal and everything works as it usually does. When we want to show our new XAML page at some point, all we need to do is to just make sure Xamarin.Forms is initialized and then instantiate the page before navigating to it:
using
Xamarin.Forms.Platform.Android;
public
void
DisplayLogin()
{
if
(!Xamarin.Forms.Forms.IsInitialized)
{
// initialize Xamarin.Forms before we use it
Xamarin.Forms.Forms.Init(
this
,
null
);
// we want to listen to the messaging center
Xamarin.Forms.MessagingCenter.Subscribe(
this
, LoginPage.LoginMessage, (User user) =>
{
// update the app
CurrentUser = user;
// go back to the main page
FragmentManager.PopBackStack();
});
}
// create the login page (Xamarin.Forms ContentPage)
var
loginPage =
new
LoginPage();
// get hold of the native Android fragment that represents the Xamarin.Forms page
var
loginFragment = loginPage.CreateFragment(
this
);
// show the login screen (native Xamarin.Android)
FragmentManager
.BeginTransaction()
.AddToBackStack(
null
)
.Replace(Resource.Id.frameLayout, loginFragment)
.Commit();
}
Xamarin.iOS and Xamarin.Forms
If we want to use Xamarin.Forms in our iOS app, we will be showing a new UIViewController
. We first need to make sure that Xamarin.Forms is initialized and then we can just go ahead and create the desired page. We then get the native view controller that can be presented using all the existing means:
using
Xamarin.Forms;
partial
void
OnLoginClicked(UIButton sender)
{
if
(!Xamarin.Forms.Forms.IsInitialized)
{
// initialize Xamarin.Forms before we use it
Xamarin.Forms.Forms.Init();
// we want to listen to the messaging center
Xamarin.Forms.MessagingCenter.Subscribe(
this
, LoginPage.LoginMessage, (User user) =>
{
// update the app
User = user;
// go back to the main page
NavigationController.PopViewController(
true
);
});
}
// create the login page (Xamarin.Forms ContentPage)
var
loginPage =
new
LoginPage();
// show the login screen
var
viewController = loginPage.CreateViewController();
NavigationController.PushViewController(viewController,
true
);
}
Windows UWP and Xamarin.Forms
When we want to show a Xamarin.Forms page within our native UWP app, we will work with a FrameworkElement
. Like with all the other platforms, we have to make sure that Xamarin.Forms is initialized and then just create the page. Once we have obtained the native element, we can just place it anywhere we need it to be. In this example, I am placing my view in a Flyout
as the it is being opened:
using
Xamarin.Forms;
private
void
OnLoginFlyoutOpening(
object
sender,
object
e)
{
var
flyout = sender
as
Flyout;
if
(!Xamarin.Forms.Forms.IsInitialized)
{
// initialize Xamarin.Forms before we use it
Xamarin.Forms.Forms.Init(App.LastLaunchEventArgs);
// we want to listen to the messaging center
Xamarin.Forms.MessagingCenter.Subscribe(
this
, LoginPage.LoginMessage, (User user) =>
{
// update the app
User = user;
// show some message for some random reason
WelcomeText = $
"Welcome back {user.Name}!"
;
// hide the login screen
flyout.Hide();
});
}
// create the login page (Xamarin.Forms ContentPage)
var
loginPage =
new
LoginPage();
// set the native dialog to contain the shared login
var
loginElement = loginPage.CreateFrameworkElement();
flyout.Content =
new
Frame
{
Content = loginElement,
Width = 300,
Height = 200
};
}
Summary
In this fairly long post, we looked at how to quickly embed a Xamarin.Forms page into an existing native app. The process is easy and painless, and will only get better.
You can download the full code from my GitHub repository and try it out for yourself. And maybe have a look at your app and see if some of those screens that are exactly the same could use Xamarin.Forms.
You can also check out some links:
Some other people also have blogs:
And, then there is code:
Related
Recommend
-
5
Forum› Xamarin.Forms We are excited to announce that the Xamarin Forums are moving to the new
-
5
Introducción Cuando tratamos el desarrollo de aplicaciones Xamarin hay algunas preguntas importantes a resolver. Entr...
-
7
Embedding a JavaScript Interpreter Into Xamarin Apps With Jint Jan 05, 2021 Posted by: Matthew Robbins Adding JavaScript support to your Xamarin...
-
8
#XamarinEssentials #Maps #XamarinFormsOpen Native Maps Apps with Xamarin.Essentials and Xamarin.Forms
-
7
Beware of C# 8 Using Statements – .NET Development Addict Let’s be honest here, C# 8 is crazy cool. It has such a big set of new features to make developers more productive and write even better code. There are some awesome things, li...
-
14
.NET Development Addict Home is where the [.net] compiler is. Recently, I have been doing more and more work with PowerShell, which...
-
6
Turning Events into Commands – .NET Development Addict Have you ever used some control in Xamarin.Forms that appears to have an event instead of a command? You are working the MVVM love and then you come across that annoying control....
-
8
Contents The Control – creating the templated control
-
15
.NET Development Addict Home is where the [.net] compiler is. I am just putting this in a blog for now so I have it some...
-
5
Who cares about the view anyway? – .NET Development Addict While working on an issue, I discovered a cool way in which to draw using SkiaSharp –...
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK