Gestire comportamenti specifici della View in Xamarin.Forms

La chiara e netta separazione tra la UI e l’application logic è il concetto che sta alla base del pattern MVVM. Molte volte, però, non è semplice capire distinguere le responsabilit , almeno in termini di rappresentazione della UI. Se devo cambiare un colore in base al contenuto, è il ViewModel che lo decide? Dove indico il colore?

Tendenzialmente saremo portati ad aggiungere una propriet nel ViewModel con l’indicazione del colore da visualizzare. E magari definiamo come tipo della propriet l’enum Xamarin.Forms.Color. Sebbene semplice, questo approccio è sbagliato perchè assegna al ViewModel una responsabilit della View, oltre al rischio di non rendere il ViewModel compatibile se questo deve essere reso riutilizzabile in diverse piattaforme (non Xamarin.Forms).

Quindi?

Il ViewModel si deve limitare a riportare il dato, senza avere conoscenza del modo in cui esso verr rappresentato dalla View. Se in una lista di persone dobbiamo mostrare un colore diverso a seconda del sesso, blu per i maschietti e rosa per le femminucce, allora il ViewModel si limiter a indicare il sesso del contatto visualizzato. Sar poi responsabilit della View decidere cosa deve essere visualizzato e in che forma.

Una soluzione decisamente elegante e che ci viene incontro in questo contesto è l’utilizzo del DataTrigger.

La via elegante: il Data Trigger

In Xamarin.Forms un trigger permette di definire un’azione al verificarsi di un’evento o al cambio del valore di una propriet . La sua peculiarit ? Possiamo definire tutto in XAML, a livello dichiarativo, senza scrivere una riga di codice. Esistono quattro diverse tipologie di Triggers:

  • Property Trigger: attivato quando la propriet di un controllo viene impostata su un particolare valore;
  • Event Trigger: attivato quando da un controllo viene generato un particolare evento;
  • Multi Trigger: consente l’attivazione del trigger sulla base della valutazione di più condizioni;
  • Data Trigger: consente di verificare la condizione del trigger, su una specifica propriet , utilizzando il binding;

Nello specifico scenario, ovviamente, il DataTrigger è il tipo di trigger che fa al caso nostro. Il codice è decisamente semplice. Dobbiamo aggiungere alla collection Triggers di un controllo Xamarin.Forms, ad esempio BoxView, e definire la propriet del ViewModel da controllare e il valore che quella propriet deve avere per attivare il trigger. Se la condizione si verifica, viene utilizzato il Setter definito nel trigger per impostare la propriet BackgroundColor del BoxView su un nuovo colore, Pink in questo caso:

<BoxView.Triggers>
	<DataTrigger TargetType="BoxView" Binding="{Binding Gender}" Value="{x:Static vm:GenderType.Female}" >
		<Setter Property="BackgroundColor" Value="Pink" />
	</DataTrigger>
</BoxView.Triggers>

 

Questo il codice completo del ListView:

<ListView ItemsSource="{Binding Contacts}" Margin="0,50,0,0">
	<ListView.ItemTemplate>
		<DataTemplate>
			<ViewCell>
				<StackLayout Orientation="Horizontal">
					<BoxView WidthRequest="5" BackgroundColor="Blue">
						<BoxView.Triggers>
							<DataTrigger TargetType="BoxView" Binding="{Binding Gender}" Value="{x:Static vm:GenderType.Female}" >
  								<Setter Property="BackgroundColor" Value="Pink" />
							</DataTrigger>
						</BoxView.Triggers>
					</BoxView>
					<Label Text="{Binding Name}" VerticalOptions="Center" />
				</StackLayout>
			</ViewCell>
		</DataTemplate>
	</ListView.ItemTemplate>
</ListView>

e questo il risultato finale:

Semplice!

Optimizing performance in your Xamarin app

Performance are one of the key features in the app development. If your app is too slow, the users will close it immediately. In this post, you can find some interesting videos from Channel9 about performance optimization of apps builded with Xamarin.

Xamarin.Forms Performance Tips and Tricks

Optimizing App Performance with Xamarin.Forms

Performance Adventures

The Xamarin Show 11: Xamarin Profiler with Nina Vyedin

Additionally, you can check out some tips and tricks links:

Enjoy!

Keep It Simple!

Antoine de Saint-Exupéry wrote in his book The Little Prince the following phrase:

“Perfection is Achieved Not When There Is Nothing More to Add, But When There Is Nothing Left to Take Away”

Thinking about this small sentence, I would like to share with you some small considerations applying it in software development.

Simplicity is the most complex thing {.headline.hover-highlight.entry-title.js_entry-title}

Think about software development. Many developers tend to create complex architectures, adding unnecessary patterns or over engineered code. Why they do that? Because they are trying to set the path for future changes that is gonna happen almost…never!

For example: you choose to abstract a component usage – by using IoC, for example – because, maybe one day, you must be able to use a different component and you don’t wont to change every time your code. Nice and good practice! But, it is really necessary in a iOS app? Maybe yes but, really, how many times you’ll change that component in the app lifetime? Except for really rare case, from zero to one time.

So, in that case, abstraction it’s like to take “a sledgehammer to crack a nut“.

Lets evolve your architecture {.headline.hover-highlight.entry-title.js_entry-title}

When your requirements are really not clear at first, write the most simpler code. If you need to read data from database, try to create a simple interface with direct read. This is not so bad at all. When you need to access to the database from another point or view, change your architecture by refactoring your code to create your data access layer.

The idea is simple: introduce changes in your architecture as late as possibile and only if it is strictly necessary. You can’t predict the future, so don’t do unnecessary things.

Obviously, if your requirements are clear, keep in mind your architecture while developing!

ASP.NET Core Mobile Service with Visual Studio for Mac

With Visual Studio for Mac, a lot of new project templates are now available to macOS developers. For example, you can now create an ASP.NET Core or a .NET Core console project directly on your Mac. Wow! But, in my opinion, one of the most interesting project template is the Connected App. With this template you’ll be able to create a complete solution with a Mobile app (iOS, Android and Windows or Xamarin.Forms) and a Backend app, an ASP.NET Core mobile project that will be hosted in an Azure Mobile Services app.

In this post we’ll see how we can create a Connected App and publish our backend to Azure by using GitHub as source control host. Yes, it is a Continuos Delivery system.

Step 1 | Create a GitHub Repository

First of all, you need to create a new GitHub repository. If you already have a GitHub repository, please go ahead. So, navigate to your GitHub page and on Repository tab click on New. After that, create a README.md file to initialize your repository and, on desktop side, clone the repository by using your git client (like GitHub Desktop).

For a full guide, follow these steps: https://help.github.com/articles/creating-a-new-repository/

Step 2 | Create a Connected App solution

After you have created and cloned the repository, open Visual Studio for Mac and create a new project in the local repository folder by using the Connected App template:

Now we have a complete solution, from frontend, the mobile apps, to backend, the web api app:

By using your git client, commit and push the project on GitHub.

Step 3 | Publish to Azure via GitHub

Finally we are now ready to publish the service to Azure. So, go to the Microsoft Azure portal, log-in into your account and create a new Mobile App.

Set up the Mobile Service with your preferred settings:

To connect our Mobile Service to GitHub, go to Deployment Options and choose GitHub as source.

Then you’ll be requested to authorize access to the GitHub account.

Finally, select the repository and the branch you’d like to use.

And you have done! Now Azure automatically start the deployment process and … BOOM!

Yes! You got the following error:

Command: "D:\home\site\deployments\tools\deploy.cmd"
Handling ASP.NET Core Web Application deployment.
D:\home\site\repository\XConn\Droid\XConn.Droid.csproj(137,3): error MSB4019: The imported project "D:\Program Files (x86)\dotnet\sdk\1.0.0-preview3-004056\Xamarin\Android\Xamarin.Android.CSharp.targets" was not found. Confirm that the path in the <Import> declaration is correct, and that the file exists on disk.
D:\home\site\repository\XConn\iOS\XConn.iOS.csproj(163,3): error MSB4019: The imported project "D:\Program Files (x86)\dotnet\sdk\1.0.0-preview3-004056\Xamarin\iOS\Xamarin.iOS.CSharp.targets" was not found. Confirm that the path in the <Import> declaration is correct, and that the file exists on disk.
Failed exitCode=1, command=dotnet restore "XConn\XConn.sln"
An error has occurred during web site deployment.
\r\nD:\Program Files (x86)\SiteExtensions\Kudu\59.51212.2600\bin\Scripts\starter.cmd "D:\home\site\deployments\tools\deploy.cmd"

Step 4 | Publish with a Custom Deployment script

What happen? Just some background info. The deployment process is governed by Kudu, “the engine behind git/hg deployments, WebJobs, and various other features in Azure Web Sites”. In small words, Kudu scan the repository to find a project to publish. When done, it will generate a deployment script which first step is restoring NuGet packages from the solution.

Ah, the solution! The Connected App solution also include the Xamarin.iOS and Xamarin.Android project. Bingo! The deployment process is trying to solve and build the Xamarin packages on Azure Mobile Service, which is not allowed!

So, what we’ll do is to create a custom deployment script to restore, build and publish only the Mobile Service project. To do that we’ll use a .deployment file (check instruction here):

[config]
command = deploy.cmd

And this is the custom deployment script that you can customize by only replacing the project name:

@if "%SCM_TRACE_LEVEL%" NEQ "4" @echo off

:: ----------------------
:: KUDU Deployment Script
:: Version: 1.0.10
:: ----------------------

:: Prerequisites
:: -------------

:: Verify node.js installed
where node 2>nul >nul
IF %ERRORLEVEL% NEQ 0 (
  echo Missing node.js executable, please install node.js, if already installed make sure it can be reached from current environment.
  goto error
)

:: Setup
:: -----

setlocal enabledelayedexpansion

SET ARTIFACTS=%~dp0%..\artifacts

IF NOT DEFINED DEPLOYMENT_SOURCE (
  SET DEPLOYMENT_SOURCE=%~dp0%.
)

IF NOT DEFINED DEPLOYMENT_TARGET (
  SET DEPLOYMENT_TARGET=%ARTIFACTS%\wwwroot
)

IF NOT DEFINED NEXT_MANIFEST_PATH (
  SET NEXT_MANIFEST_PATH=%ARTIFACTS%\manifest

  IF NOT DEFINED PREVIOUS_MANIFEST_PATH (
    SET PREVIOUS_MANIFEST_PATH=%ARTIFACTS%\manifest
  )
)

IF NOT DEFINED KUDU_SYNC_CMD (
  :: Install kudu sync
  echo Installing Kudu Sync
  call npm install kudusync -g --silent
  IF !ERRORLEVEL! NEQ 0 goto error

  :: Locally just running "kuduSync" would also work
  SET KUDU_SYNC_CMD=%appdata%\npm\kuduSync.cmd
)
IF NOT DEFINED DEPLOYMENT_TEMP (
  SET DEPLOYMENT_TEMP=%temp%\___deployTemp%random%
  SET CLEAN_LOCAL_DEPLOYMENT_TEMP=true
)

IF DEFINED CLEAN_LOCAL_DEPLOYMENT_TEMP (
  IF EXIST "%DEPLOYMENT_TEMP%" rd /s /q "%DEPLOYMENT_TEMP%"
  mkdir "%DEPLOYMENT_TEMP%"
)

IF DEFINED MSBUILD_PATH goto MsbuildPathDefined
SET MSBUILD_PATH=%ProgramFiles(x86)%\MSBuild\14.0\Bin\MSBuild.exe
:MsbuildPathDefined
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:: Deployment
:: ----------

echo Handling ASP.NET Core Web Application deployment.

:: 1. Restore nuget packages
call :ExecuteCmd dotnet restore "XConn\MobileAppService\XConn.MobileAppService.csproj"
IF !ERRORLEVEL! NEQ 0 goto error

:: 2. Build and publish
call :ExecuteCmd dotnet publish "XConn\MobileAppService\XConn.MobileAppService.csproj" --framework netcoreapp1.0 --configuration Release --output "%DEPLOYMENT_TEMP%"
IF !ERRORLEVEL! NEQ 0 goto error

:: 3. KuduSync
call :ExecuteCmd "%KUDU_SYNC_CMD%" -v 50 -f "%DEPLOYMENT_TEMP%" -t "%DEPLOYMENT_TARGET%" -n "%NEXT_MANIFEST_PATH%" -p "%PREVIOUS_MANIFEST_PATH%" -i ".git;.hg;.deployment;deploy.cmd"
IF !ERRORLEVEL! NEQ 0 goto error

::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
goto end

:: Execute command routine that will echo out when error
:ExecuteCmd
setlocal
set _CMD_=%*
call %_CMD_%
if "%ERRORLEVEL%" NEQ "0" echo Failed exitCode=%ERRORLEVEL%, command=%_CMD_%
exit /b %ERRORLEVEL%

:error
endlocal
echo An error has occurred during web site deployment.
call :exitSetErrorLevel
call :exitFromFunction 2>nul

:exitSetErrorLevel
exit /b 1

:exitFromFunction
()

:end
endlocal
echo Finished successfully.

Finally, you can publish the .deployment and deploy.cmd files to the root of the repository. Once done, the deployment process restart and now … the Mobile Service is up and running!

Happy coding!

Change the iOS Status Bar color in Xamarin.Forms

Xamarin.Forms is a great way to abstract the local implementation. But, you know, sometimes you need to perform some small adjustments based on the underlying OS. Is this the case of the iOS Status Bar style.

Xamarin.Forms implements, in the NavigationRenderer, a way to automatically set the style (dark/default or light) by checking the Luminosity value of the BarTextColor property. Check the following code:

if (statusBarColorMode == StatusBarTextColorMode.DoNotAdjust || barTextColor.Luminosity <= 0.5)
{
	// Use dark text color for status bar
	UIApplication.SharedApplication.StatusBarStyle = UIStatusBarStyle.Default;
}
else
{
	// Use light text color for status bar
	UIApplication.SharedApplication.StatusBarStyle = UIStatusBarStyle.LightContent;
}

For full code, check the NavigationRenderer source on github Xamarin.Forms project.

Now, if in your code you set the BarTextColor to black, then the status bar style will be the Default (dark). Otherwise, the status bar style will be light (white).

So, if we want to set the BarTextColor, in a classic Xamarin.Forms App class constructor, we’ll have something like this:

public App()
{
	InitializeComponent();

	MainPage = new NavigationPage(new MainPage())
	{
		BarBackgroundColor = Color.FromHex("#043596"),
		BarTextColor = Color.White
	};
}

But, this is not enough.

In iOS, we have two ways to set the StatusBarStyle:

  • at application level
  • at view controller level

The default behavior is at view controller level. Since Xamarin.Forms sets the StatusBarStyle at application level, we need to set the related property in the Info.plist. So, open the info.plist file, go in the Source tab and add a new entry with this values:

Name = UIViewControllerBasedStatusBarAppearance

Type – boolean

Value – No

And we have done! Now start the app and check the result:

Nice and simple!

What’s new in Windows Communication Foundation 4.5

Windows Communication Foundation (WCF), the Microsoft framework for message exchange between systems, has come a long way since when it was called Indigo, about ten years ago.

In the last versions, all the efforts have gone in the direction to optimize and simplify development:

  • Simplified Generated Configuration Files
  • Contract-First Development
  • Add Service Reference From a Portable Subset Project
  • ASP.NET Compatibility Mode Default Changed
  • Streaming Improvements
  • New Transport Default Values
  • XmlDictionaryReaderQuotas
  • WCF Configuration Validation
  • XML Editor Tooltips
  • BasicHttpBinding Improvements

You can find all the details about this topics on the following page: WCF Simplification Features. If you are curious about what’s new in WCF 4.5, check this page.

In the next posts we’ll see some of the improvements and the impact in the everyday development.

A little and simple Bindable (Horizontal) Scroll View – Add Command pattern

This is the third post of the A little and simple Bindable (Horizontal) Scroll View saga. In the first post we saw how to implement a horizontal view with data binding capability. Then, in the second post, we have seen how to add an event to handle the tap gesture on list items.

In this post, we’ll see how to add the Command pattern to the TLScrollView and get working one of the most used way to catch the user UI interaction directly into the ViewModel.

Adding the Command and CommandParameter properties to the TLScrollView

The first step is to add two bindable properties: SelectedCommand and SelectedCommandParameter.

public static readonly BindableProperty SelectedCommandProperty =
	BindableProperty.Create("SelectedCommand", typeof(ICommand), typeof(TLScrollView), null);

public ICommand SelectedCommand
{
	get { return (ICommand)GetValue(SelectedCommandProperty); }
	set { SetValue(SelectedCommandProperty, value); }
}

public static readonly BindableProperty SelectedCommandParameterProperty =
	BindableProperty.Create("SelectedCommandParameter", typeof(object), typeof(TLScrollView), null);

public object SelectedCommandParameter
{
	get { return GetValue(SelectedCommandParameterProperty); }
	set { SetValue(SelectedCommandParameterProperty, value); }
}

The first one will be used to reference the Command object instance, the event handler into the view model, while the second one is the instance parameter that will be passed to the event handler.

After that, we need to modify the TLScrollView Render method to use the new SelectedCommand and SelectedCommandParameter properties, if used:

var command = SelectedCommand ?? new Command((obj) =>
{
	var args = new ItemTappedEventArgs(ItemsSource, item);
	ItemSelected?.Invoke(this, args);
});
var commandParameter = SelectedCommandParameter ?? item;

var viewCell = ItemTemplate.CreateContent() as ViewCell;
viewCell.View.BindingContext = item;
viewCell.View.GestureRecognizers.Add(new TapGestureRecognizer
{
	Command = command,
	CommandParameter = commandParameter,
	NumberOfTapsRequired = 1
});

Use the Command pattern to get the selected item

To use the Command pattern in our solution, we need to add a property in our viewmodel that will be binded to the UI control:

public ICommand ItemSelected { get; set; }

and then initialize it with an event handler in the viewmodel’s constructor:

public MyViewModel()
{
	ItemSelected = new Command(arg => DoSomething());
}

finally we can bind the SelectedCommand property to the ItemSelected property:

<controls:TLScrollView Orientation="Horizontal" ItemsSource="{Binding Items}" SelectedCommand="{Binding ItemSelected}" HeightRequest="100">

Use my ViewModelBase

One step further is to minimize coding by using my ViewModelBase implementation. After extending your custom ViewModel with my ViewModelBase, you can simply write a method with the name ItemSelected and the _ExecuteCommand suffix:

public void ItemSelected_ExecuteCommand(object args)
{
}

After that, you need to add square brackets around the ItemSelected name in your XAML SelectedCommand assignment definition:

SelectedCommand="{Binding [ItemSelected]}"

Nice and really simple. As usual, you can find full code with sample on my github repository.

A little and simple Bindable (Horizontal) Scroll View – Handling item tap gesture

A long time ago, in the first post, I wrote about the TLScrollView, a way to create a simple, horizontal and bindable list of items in Xamarin.Forms. The final result is something like the horizontal views on Apple App Store app.

After receiving some feedback, users ask for a way to handle the tap gesture on the items. We have two possible approaches: the first one is by using the classic ItemSelected event handlers, and the second one by using the Command pattern, typical solution in MVVM.

In this post we’ll explore the first approach.

Adding an ItemSelected handler to the TLScrollView

So, first of all, we need to add an ItemSelected event, a delegate of type EventHandler to the TLScrollView:

public event EventHandler<ItemTappedEventArgs> ItemSelected;

Now, in the Render method, we can add the following line in the for..each cycle, just after settings the BindingContext of the ViewCell:

viewCell.View.GestureRecognizers.Add(new TapGestureRecognizer
{
	Command = new Command((obj) =>
	{
		var args = new ItemTappedEventArgs(ItemsSource, item);
		ItemTapped?.Invoke(this, args);
	}),
	NumberOfTapsRequired = 1
});

Now, in your XAML, you can define the handler in this way:

<controls:XScrollView Orientation="Horizontal" ItemsSource="{Binding Items}" ItemSelected="Handle_ItemSelected" HeightRequest="100">

then you can implement your handle:

void Handle_ItemSelected(object sender, Xamarin.Forms.ItemTappedEventArgs e)
{
	// your code
}

That’s really simple! But if you want build a code in line with the Separation of Concern, typical principles of MVVM, a SelectedCommand property should be the best way.

I’ll show the step neeeded to add the command pattern to the TLScrollView in the next post of this series.

Full code is available here

Xamarin Dev Days @ Bari

Last Friday in Bari, DotNetSide has hosted one stop of the Xamarin Dev Days tour in Italy. It was really an amazing day spent with very passionate people talking about Xamarin and how is funny to develop with their tools.

During the day, we talked about Xamarin development with Xamarin.Forms combined with Cognitive Services, Mobile Apps, remote APIs and so on. In the afternoon, a great hands-on lab was made by around 40 people with the intention to share their knowledge (and win a Xamarin monkey! 😀 ).

cygf4_iwgaabjx5

After the announcements made by Microsoft at Connect(); conference last week, we decided to include an extra slot to talk about Visual Studio for Mac, Visual Studio Mobile Center and .NET Standard.

cyghtedxeaafjq5

It was a really great day. I like to see how many people loves their job and try to improve with great passion.

Thanks to all and thanks to the DotNetSiders! You rocks!

Solve the “May Slow Down Your iPhone” message on simulator

With Xcode 8.1 and the iOS 10.1 simulator you may encounter the following message:

schermata-2016-11-15-alle-14-59-04

Don’t worry. This happens because you are running a 32-bit app on a 64-bit architecture (the iPhone/iPad simulator). Change the Supported architecture to x86_64 for the Debug configuration and the iPhoneSimulator platform and the problem goes away.

schermata-2016-11-15-alle-14-54-30

That’s all!