<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:media="http://search.yahoo.com/mrss/"><channel><title><![CDATA[AdenEarnshaw.com]]></title><description><![CDATA[Xamarin, Mobile and Web development tips and tricks]]></description><link>https://adenearnshaw.com/</link><image><url>https://adenearnshaw.com/favicon.png</url><title>AdenEarnshaw.com</title><link>https://adenearnshaw.com/</link></image><generator>Ghost 4.32</generator><lastBuildDate>Sun, 21 Dec 2025 02:56:28 GMT</lastBuildDate><atom:link href="https://adenearnshaw.com/rss/" rel="self" type="application/rss+xml"/><ttl>60</ttl><item><title><![CDATA[Configuring an IoC Container in a MAUI app]]></title><description><![CDATA[Want to use an IoC container in a .NET MAUI app? Here I demonstrate how we can use the Configure the Container from the MauiProgram.cs]]></description><link>https://adenearnshaw.com/configuring-an-ioc-container-in-maui/</link><guid isPermaLink="false">631511f179f90e1d994cf014</guid><category><![CDATA[MAUI]]></category><category><![CDATA[MVVM]]></category><dc:creator><![CDATA[Aden Earnshaw]]></dc:creator><pubDate>Mon, 05 Sep 2022 15:45:00 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1590610123854-cff24ee40cf3?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8c2VhcmNofDU4fHxDb250YWluZXIlMjBjb2ZmZWV8ZW58MHx8fHwxNjYyMzI1Nzcy&amp;ixlib=rb-1.2.1&amp;q=80&amp;w=2000" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="https://images.unsplash.com/photo-1590610123854-cff24ee40cf3?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8c2VhcmNofDU4fHxDb250YWluZXIlMjBjb2ZmZWV8ZW58MHx8fHwxNjYyMzI1Nzcy&amp;ixlib=rb-1.2.1&amp;q=80&amp;w=2000" alt="Configuring an IoC Container in a MAUI app"><p>I&apos;ve always been a fan of MvvmLight&apos;s SimpleIoc and was really pleased to see it mature and make its way into the <a href="https://docs.microsoft.com/en-us/windows/communitytoolkit/mvvm/ioc">CommunityToolkit</a> after MvvmLight&apos;s deprecation.</p>
<p>In <a href="https://twitter.com/msicc">Marco Siccardi&apos;s</a> blog post <a href="https://msicc.net/make-the-iserviceprovider-of-your-maui-application-accessible-with-the-mvvm-communitytoolkit/">&quot;Make the IServiceProvider of your MAUI application accessible with the MVVM CommunityToolkit&quot;</a> he walks through how this Container can be configured by extending the Maui App&apos;s Application class and calling <code>Ioc.Default.ConfigureServices()</code> from the construct of the resulting sub-class.</p>
<p>As highlighted in Marco&apos;s post, there are many ways to achieve this, however Sub-classing Application seemed a little too hard work for me :)</p>
<h2 id="alternative-approach">Alternative Approach</h2>
<p>The <code>IServiceProvider</code> is exposed from the MauiApp object created in the <code>MauiProgram.CreateMauiApp()</code> method.</p>
<p>Rather than sub-class, we can simply extend the last line of <code>CreateMauiApp()</code>:</p>
<p><strong>MauiProgram.cs</strong></p>
<pre><code class="language-csharp">public static class MauiProgram
{
    public static MauiApp CreateMauiApp()
    {
        var builder = MauiApp.CreateBuilder();
        builder
            .UseMauiApp&lt;App&gt;()
            .ConfigureFonts(fonts =&gt;
            {
                fonts.AddFont(&quot;OpenSans-Regular.ttf&quot;, &quot;OpenSansRegular&quot;);
                fonts.AddFont(&quot;OpenSans-Semibold.ttf&quot;, &quot;OpenSansSemibold&quot;);
            });

        builder.Services.AddTransient&lt;MainViewModel&gt;();

        var mauiApp = builder.Build();
        Ioc.Default.ConfigureServices(mauiApp.Services);
        return mauiApp;
    }    
}
</code></pre>
<p><s>A cleaner approach would be to create an extension method, allowing us to keep it to a single line and configure the IoC Container elsewhere. <a href="https://github.com/adenearnshaw/maui-configure-ioc-sample/tree/init-via-extension-method">Old Sample</a></s></p>
<p>Thanks to Allan Ritchie&apos;s <a href="https://twitter.com/allanritchie911/status/1581457898898485250">suggestion</a>, a cleaner approach is to wrap the <code>Ioc.Default.ConfigureServices()</code> in a Service which is automatically initialized by the Maui App Builder during initialization using the <code>IMauiInitializerService</code> interface.</p>
<p><strong>MauiAppExtensions.cs</strong></p>
<pre><code class="language-csharp">public class IocConfigurationService : IMauiInitializeService
{
    public void Initialize(IServiceProvider services)
    {
        Ioc.Default.ConfigureServices(services);
    }
}
</code></pre>
<p><strong>MauiProgram.cs</strong></p>
<pre><code class="language-csharp">public static class MauiProgram
{
    public static MauiApp CreateMauiApp()
    {
        ...
        builder.Services.AddSingleton&lt;IMauiInitializeService&gt;(new IocConfigurationService());

        builder.Services.AddTransient&lt;MainViewModel&gt;();

        return builder.Build();
    }    
}
</code></pre>
<p>A sample app for context is provided <a href="https://github.com/adenearnshaw/maui-configure-ioc-sample">here</a></p>
<p>Thanks again to Marco for the inspiration, this is in no way intended to put down his approach, only to highlight that there&apos;s always more than one approach and to choose the one you feel most comfortable with.</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Icons Made Easy for .NET MAUI App Actions]]></title><description><![CDATA[App Actions allow developers to add shortcuts to an App's launch icon to invoke custom functionality or deep link into the app. 

AppActions.Icons.Maui provides developers with a set of Icons you can easily add to an AppAction.]]></description><link>https://adenearnshaw.com/icons-made-easy-for-net-maui-app-actions/</link><guid isPermaLink="false">62a664a279f90e1d994cef01</guid><category><![CDATA[MAUI]]></category><category><![CDATA[iOS]]></category><category><![CDATA[Shortcuts]]></category><category><![CDATA[UWP]]></category><category><![CDATA[Android]]></category><dc:creator><![CDATA[Aden Earnshaw]]></dc:creator><pubDate>Mon, 13 Jun 2022 10:30:00 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1506729623306-b5a934d88b53?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8c2VhcmNofDF8fGljb25zfGVufDB8fHx8MTY1NTA3MTkxMg&amp;ixlib=rb-1.2.1&amp;q=80&amp;w=2000" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="https://images.unsplash.com/photo-1506729623306-b5a934d88b53?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8c2VhcmNofDF8fGljb25zfGVufDB8fHx8MTY1NTA3MTkxMg&amp;ixlib=rb-1.2.1&amp;q=80&amp;w=2000" alt="Icons Made Easy for .NET MAUI App Actions"><p>App Actions allow developers to add shortcuts to an App&apos;s launch icon to invoke custom functionality or deep link into the app.</p>
<p>As part of MAUI Essentials, a simple API is provided that allows the developer to declare App Actions. The API allows you to create the Action with a custom title, and sub-title and set an Icon for the action from the App&apos;s resources. However, creating Icons for App Actions can be quite finicky, as if they aren&apos;t the correct size and format, they will not render.</p>
<p>Enter <a href="https://www.nuget.org/packages/AppActions.Icons.Maui/">AppActions.Icons.Maui</a>. This nuget package provides a set of common icons that you can use in Android, iOS &amp; Windows platforms to quickly add icons to your AppActions with little ceremony.</p>
<p><img src="https://adenearnshaw.com/content/images/2022/06/IconDemo.png" alt="Icons Made Easy for .NET MAUI App Actions" loading="lazy"></p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h2 id="how-to-install">How to install</h2>
<ol>
<li>
<p>Follow the Microsoft .NET MAUI <a href="https://docs.microsoft.com/en-us/dotnet/maui/platform-integration/appmodel/app-actions?tabs=android">App actions Docs</a> on how to Configure AppActions in your Application.</p>
</li>
<li>
<p>Install the <a href="https://www.nuget.org/packages/AppActions.Icons.Maui/">AppActions.Icons.Maui</a> Nuget package into your MAUI project.</p>
</li>
<li>
<p>In the <code>ConfigureEssentials()</code> method, call <strong><code>essentials.UseAppActionIcons()</code></strong></p>
<pre><code class="language-csharp">using AppActions.Icons.Maui;

...

.ConfigureEssentials(essentials =&gt;
{
    essentials
        .UseAppActionIcons()
        .AddAppAction(&quot;shortcut_1&quot;, &quot;Shortcut&quot;)
        .OnAppAction(App.HandAppActions)
});
</code></pre>
</li>
</ol>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h2 id="how-to-use">How to use</h2>
<p>AppActions.Icons.Maui builds on top of the Essentials AppActions API to try and make life as easy as possible. This means that setting the icon to one of the provided Icons is as easy as passing in one of the options from the <code>AppActionIcon</code> class in place of a string name.</p>
<pre><code class="language-csharp">.ConfigureEssentials(essentials =&gt;
{
    essentials
        .UseAppActionIcons()
        .AddAppAction(&quot;shortcut_1&quot;, &quot;Shortcut&quot;, icon: AppActionIcon.Compose)
        .OnAppAction(App.HandAppActions)
});
</code></pre>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>This code snippet assigns the &quot;Compose&quot; icon and looks like this</p>
<p><img src="https://adenearnshaw.com/content/images/2022/06/ProvidedIconpng.png" alt="Icons Made Easy for .NET MAUI App Actions" loading="lazy"></p>
<h2 id="modify-icon-colors-on-android">Modify Icon Colors on Android</h2>
<p>On Android, the Icons provided are VectorDrawables, this means we can utilise the platform&apos;s native features and override the foreground and background colors of the icons.</p>
<ol>
<li>
<p>Open the <code>colors.xml</code> in <em>Platforms &gt; Android &gt; Resources &gt; values</em></p>
</li>
<li>
<p>Add the following two color resources and adjust the Hex codes to your desired colors.</p>
<pre><code class="language-xml">&lt;color name=&quot;appActionBackground&quot;&gt;#E6DFFC&lt;/color&gt;
&lt;color name=&quot;appActionForeground&quot;&gt;#512BD4&lt;/color&gt;
</code></pre>
<p><img src="https://adenearnshaw.com/content/images/2022/06/ProvidedIcon_Color.png" alt="Icons Made Easy for .NET MAUI App Actions" loading="lazy"></p>
</li>
</ol>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>And that&apos;s it! A simple way to add Icons to your AppActions.</p>
<p>As well as the 29 provided icons, this package also allows you to set SF Symbols for your iOS apps which give you even more flexibility. To see how to take advantage of this feature, please visit the Package&apos;s <a href="https://github.com/adenearnshaw/AppActions.Icons.Maui/blob/main/README.md">GitHub Readme</a></p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Open Xamarin Forms WebView links in external browser]]></title><description><![CDATA[Sometimes you'll use WebView to display a block of HTML in your app, but don't want users to navigate away if they click a link in the content.

Here we show how to add a simple Custom Behavior to the WebView to intercept the navigation and launch an external browser instead.]]></description><link>https://adenearnshaw.com/open-xamarin-forms-webview-links-in-external-browser/</link><guid isPermaLink="false">5f2aa43684292215cdf4bb29</guid><category><![CDATA[Xamarin Forms]]></category><category><![CDATA[Xamarin]]></category><category><![CDATA[iOS]]></category><category><![CDATA[Android]]></category><dc:creator><![CDATA[Aden Earnshaw]]></dc:creator><pubDate>Wed, 05 Aug 2020 22:43:08 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1516031391404-50a63b60f9f6?ixlib=rb-1.2.1&amp;q=80&amp;fm=jpg&amp;crop=entropy&amp;cs=tinysrgb&amp;w=2000&amp;fit=max&amp;ixid=eyJhcHBfaWQiOjExNzczfQ" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="https://images.unsplash.com/photo-1516031391404-50a63b60f9f6?ixlib=rb-1.2.1&amp;q=80&amp;fm=jpg&amp;crop=entropy&amp;cs=tinysrgb&amp;w=2000&amp;fit=max&amp;ixid=eyJhcHBfaWQiOjExNzczfQ" alt="Open Xamarin Forms WebView links in external browser"><p>On occasions you may find a need to display a block of HTML in your app, for a bit of legal blurb for example, and you&apos;ll reach for the trusty <code>WebView</code>.</p>
<p>The <code>WebView</code> control is great for displaying a page of HTML, however it comes &quot;as is&quot;. If a user clicks on a link within the WebView, it opens the link within the same view, but the user is unable to go back, as the WebView has no navigation controls.</p>
<p>By intercepting the <code>WebView.Navigating</code> event, we can block the WebView from opening the url and instead take advantage of Xamarin.Essentials <code>Browser.OpenAsync</code> method. In order to make this re-usable, I&apos;ve wrapped it in a Behavior so it can be easily applied to any WebViews that require it.</p>
<p>View the sample code for this on <a href="https://github.com/adenearnshaw/xam-webview-external-links"><strong>GitHub</strong></a></p>
<h2 id="webviewbrowserlinkbehavior">WebViewBrowserLinkBehavior</h2>
<pre><code class="language-csharp">public class WebViewBrowserLinkBehavior : BehaviorBase&lt;WebView&gt;
{
    protected override void OnAttachedTo(WebView webView)
    {
		base.OnAttachedTo(webView);
		webView.Navigating += WebViewOnNavigating;
	}

	protected override void OnDetachingFrom(WebView webView)
	{
		base.OnDetachingFrom(webView);
		webView.Navigating -= WebViewOnNavigating;
	}

	private void WebViewOnNavigating(object sender, WebNavigatingEventArgs e)
	{
		if (!e.Url.StartsWith(&quot;http&quot;, StringComparison.InvariantCultureIgnoreCase))
			return;

        e.Cancel = true;
		_ = Browser.OpenAsync(e.Url, this.LaunchOptions);
	}
}
</code></pre>
<p>In the behavior we subscribe and unsubscribe to the WebView&apos;s Navigating() event via the OnAttachedTo and OnDetachingFrom methods respectively.</p>
<p>In the event handler, we check to see if the url that&apos;s been clicked starts with &quot;http&quot; and if so, we cancel the WebView&apos;s navigation and call Browser.OpenAsync with the url.</p>
<blockquote>
<p>You could omit the check to see if the url starts with Http if you want, and use the Launcher.OpenAsync method instead.</p>
</blockquote>
<h2 id="usingthebehavior">Using the behavior</h2>
<p>As with most other Xamarin Forms controls, WebView contains a <code>Behaviors</code> property and so we can just add our behavior to that:</p>
<pre><code class="language-xml">&lt;ContentPage x:Class=&quot;PrivacyPolicyLinks.MainPage&quot;
             xmlns=&quot;http://xamarin.com/schemas/2014/forms&quot;
             xmlns:x=&quot;http://schemas.microsoft.com/winfx/2009/xaml&quot;
             xmlns:behaviors=&quot;clr-namespace:PrivacyPolicyLinks.Behaviors&quot;&gt;
    ...
    
    &lt;WebView&gt;
        &lt;WebView.Source&gt;
            &lt;HtmlWebViewSource Html=&quot;{Binding DocumentText}&quot; /&gt;
        &lt;/WebView.Source&gt;
    
        &lt;WebView.Behaviors&gt;
            &lt;behaviors:WebViewBrowserLinkBehavior /&gt;
        &lt;/WebView.Behaviors&gt;
    &lt;/WebView&gt;
&lt;/ContentPage&gt;
</code></pre>
<p>And there we have it a simple behavior that will automatically launch hyperlinks in an external browser, leaving the original content of the webview in tact.</p>
<h2 id="source">Source</h2>
<p>You can find a full working sample of the code with some additional properties for cusomization on <a href="https://github.com/adenearnshaw/xam-webview-external-links"><strong>GitHub</strong></a></p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Set ASPNETCORE_ENVIRONMENT in web.config using .NET Core CLI]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p>In an ideal world, your lovely ASP Core application would be hosted in its own container in a sandboxed environment and separating Environmental Variables for different apps would be trivial. In the real world things are sometimes a bit muddier.</p>
<h2 id="problem">Problem:</h2>
<p>Allow multiple ASP.NET Core apps to run in</p>]]></description><link>https://adenearnshaw.com/set-environment-in-web-config/</link><guid isPermaLink="false">5f21013f84292215cdf4ba55</guid><category><![CDATA[AspNetCore]]></category><category><![CDATA[DevOps]]></category><category><![CDATA[Web]]></category><dc:creator><![CDATA[Aden Earnshaw]]></dc:creator><pubDate>Wed, 29 Jul 2020 05:28:53 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1522735338363-cc7313be0ae0?ixlib=rb-1.2.1&amp;q=80&amp;fm=jpg&amp;crop=entropy&amp;cs=tinysrgb&amp;w=2000&amp;fit=max&amp;ixid=eyJhcHBfaWQiOjExNzczfQ" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="https://images.unsplash.com/photo-1522735338363-cc7313be0ae0?ixlib=rb-1.2.1&amp;q=80&amp;fm=jpg&amp;crop=entropy&amp;cs=tinysrgb&amp;w=2000&amp;fit=max&amp;ixid=eyJhcHBfaWQiOjExNzczfQ" alt="Set ASPNETCORE_ENVIRONMENT in web.config using .NET Core CLI"><p>In an ideal world, your lovely ASP Core application would be hosted in its own container in a sandboxed environment and separating Environmental Variables for different apps would be trivial. In the real world things are sometimes a bit muddier.</p>
<h2 id="problem">Problem:</h2>
<p>Allow multiple ASP.NET Core apps to run in IIS on the same server but each have their own <code>ASPNETCORE_ENVIRONMENT</code> value that is generated via a CI pipeline.</p>
<h2 id="solution">Solution:</h2>
<p>Pass the <strong>EnvironmentName</strong> parameter into the <code>dotnet publish</code> command. This will generate a <code>web.config</code> file for the application and include the  <strong>ASPNETCORE_ENVIRONMENT</strong> property.</p>
<pre><code>dotnet publish --configuration Release /p:EnvironmentName=Staging
</code></pre>
<p>The generated web.config file will look something similar to this:</p>
<pre><code class="language-xml">&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;configuration&gt;
  &lt;system.webServer&gt;
    ...
      
    &lt;aspNetCore ...&gt;
      &lt;environmentVariables&gt;
        &lt;environmentVariable name=&quot;ASPNETCORE_ENVIRONMENT&quot; value=&quot;Staging&quot; /&gt;
      &lt;/environmentVariables&gt;
    &lt;/aspNetCore&gt;
  &lt;/system.webServer&gt;
&lt;/configuration&gt;
</code></pre>
<blockquote>
<p>If you already have a web.config in the root of your web app for other things (adding/removing certain headers), then this will edit that file rather than replace it.</p>
</blockquote>
<h3 id="azuredevopspipeline">Azure Devops Pipeline</h3>
<p>If you&apos;re looking to do this within an AzDO Yaml Pipeline, here&apos;s a sample of the code required:</p>
<pre><code class="language-yaml">  - task: DotNetCoreCLI@2
    displayName: &apos;Publish Web Project&apos;
    inputs:
      command: publish
      publishWebProjects: True
      arguments: &apos;--configuration $(BuildConfiguration) --output $(build.artifactstagingdirectory) /p:EnvironmentName=Staging&apos;
      zipAfterPublish: true
</code></pre>
<h3 id="sample">Sample</h3>
<p>You can find a Hosted Blazor WebAssembly sample over at my <a href="https://github.com/adenearnshaw/web-blazor-environmentname">GitHub</a></p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[How to focus on another field when user presses Return in a Xamarin Forms app]]></title><description><![CDATA[Whilst most people are familiar with the concept of pressing the tab key to allow users to move between fields on a Desktop or Web form, the same isn't as true for mobile devices. A more useable flow for Mobile Users is to jump to the next field when a user presses enter on the keyboard.  ]]></description><link>https://adenearnshaw.com/focus-next-element-on-enter/</link><guid isPermaLink="false">5f175d8aadd0ae0db6dcd4ea</guid><category><![CDATA[Xamarin]]></category><category><![CDATA[Xamarin Forms]]></category><category><![CDATA[iOS]]></category><category><![CDATA[Android]]></category><category><![CDATA[UWP]]></category><dc:creator><![CDATA[Aden Earnshaw]]></dc:creator><pubDate>Thu, 23 Jan 2020 15:30:00 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1566694271355-9ead56467fd0?ixlib=rb-1.2.1&amp;q=80&amp;fm=jpg&amp;crop=entropy&amp;cs=tinysrgb&amp;w=1080&amp;fit=max&amp;ixid=eyJhcHBfaWQiOjExNzczfQ" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="https://images.unsplash.com/photo-1566694271355-9ead56467fd0?ixlib=rb-1.2.1&amp;q=80&amp;fm=jpg&amp;crop=entropy&amp;cs=tinysrgb&amp;w=1080&amp;fit=max&amp;ixid=eyJhcHBfaWQiOjExNzczfQ" alt="How to focus on another field when user presses Return in a Xamarin Forms app"><p>Whilst most people are familiar with the concept of pressing the tab key to allow users to move between fields on a Desktop or Web form, the same isn&apos;t as true for mobile devices. A more useable flow for mobile users is to jump to the next field when they press Return on the keyboard.</p>
<p>In Xamarin Forms, <a href="https://docs.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/accessibility/keyboard#setting-the-tab-order">TabIndex</a> is supported, but is only really useful for devices connected to a keyboard. For those more conventional touch devices, we need a different approach...Behaviors.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p><img height="22" width="22" style="margin: 0 4px 0 0 " src="https://unpkg.com/simple-icons@latest/icons/github.svg" alt="How to focus on another field when user presses Return in a Xamarin Forms app"> <a href="https://github.com/adenearnshaw/xam-focus-next-element">Sample source code</a></p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>Using a custom behavior we can subscribe to an Entry&apos;s <code>Completed</code> event and assign focus to a new <a href="https://github.com/xamarin/Xamarin.Forms/blob/master/Xamarin.Forms.Core/VisualElement.cs"><code>VisualElement</code></a>.</p>
<h3 id="thebehaviorcode">The Behavior code:</h3>
<pre><code class="language-csharp">public class SetFocusOnEntryCompletedBehavior : Behavior
{
    public static readonly BindableProperty TargetElementProperty
       = BindableProperty.Create(nameof(TargetElement), typeof(VisualElement), typeof(SetFocusOnEntryCompletedBehavior));

    public VisualElement TargetElement
    {
        get =&gt; (VisualElement)GetValue(TargetElementProperty);
        set =&gt; SetValue(TargetElementProperty, value);
    }
        
    protected override void OnAttachedTo(BindableObject bindable)
    {
        base.OnAttachedTo(bindable);
        
        if (bindable is Entry entry)
            entry.Completed += Entry_Completed;
    }

    protected override void OnDetachingFrom(BindableObject bindable)
    {
        if (bindable is Entry entry)
            entry.Completed -= Entry_Completed;

        base.OnDetachingFrom(bindable);
    }

    private void Entry_Completed(object sender, EventArgs e)
    {
        TargetElement?.Focus();
    }
}
</code></pre>
<p>We create a BindableProperty called TargetElement, this will hold a reference to the Element we want to focus on next when Return is pressed. Then, when the behavior is attached to its parent Entry, we hook up the Entry&apos;s Completed event and invoke the <code>Focus()</code> method when it&apos;s fired, remembering to detach the event when we&apos;re done.</p>
<h3 id="theimplementation">The implementation</h3>
<pre><code class="language-xml">&lt;ContentPage x:Class=&quot;NextFormFieldSample.Forms.MainPage&quot;
             xmlns=&quot;http://xamarin.com/schemas/2014/forms&quot;
             xmlns:x=&quot;http://schemas.microsoft.com/winfx/2009/xaml&quot;
             xmlns:behaviors=&quot;clr-namespace:NextFormFieldSample.Forms.Behaviors&quot;&gt;
    &lt;StackLayout Margin=&quot;20&quot;&gt;   
        
        &lt;Entry Placeholder=&quot;Field 1&quot;&gt;
            &lt;Entry.Behaviors&gt;
                &lt;behaviors:SetFocusOnEntryCompletedBehavior TargetElement=&quot;{x:Reference Entry2}&quot; /&gt;
            &lt;/Entry.Behaviors&gt;
        &lt;/Entry&gt;

        &lt;Entry x:Name=&quot;Entry2&quot; Placeholder=&quot;Field 2&quot;/&gt;  
        
    &lt;/StackLayout&gt;
&lt;/ContentPage&gt;
</code></pre>
<p>This adds the behavior to listen to the Return key being pressed when the user is focused on the first Entry. The behavior&apos;s <code>TargetElement</code> property is set using <code>{x:Reference}</code> and uses the <code>x:Name</code> assigned to the second Entry as the reference point.</p>
<p>Now, when a user taps the Return key on their keyboard whilst in the first entry, the app will automatically move the cursor to the second field.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>View the code within a sample app over on my <a href="https://github.com/adenearnshaw/xam-focus-next-element">GitHub</a>.</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Adding static shortcuts to your app]]></title><description><![CDATA[Using my AppShortcuts plugin, you can add Dynamic shortcuts to your Xamarin Apps. 

Android and iOS also provide Static shortcuts which require much less code and can be useful in certain scenarios.

Learn how to add Static shortcuts to your Xamarin Forms iOS or Android apps.]]></description><link>https://adenearnshaw.com/adding-static-shortcuts/</link><guid isPermaLink="false">5f175d8aadd0ae0db6dcd4e8</guid><category><![CDATA[Xamarin]]></category><category><![CDATA[Xamarin Forms]]></category><category><![CDATA[Shortcuts]]></category><category><![CDATA[Android]]></category><category><![CDATA[iOS]]></category><dc:creator><![CDATA[Aden Earnshaw]]></dc:creator><pubDate>Tue, 08 Jan 2019 16:35:00 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1492500318351-274a118407c2?ixlib=rb-1.2.1&amp;q=80&amp;fm=jpg&amp;crop=entropy&amp;cs=tinysrgb&amp;w=1080&amp;fit=max&amp;ixid=eyJhcHBfaWQiOjExNzczfQ" medium="image"/><content:encoded><![CDATA[<img src="https://images.unsplash.com/photo-1492500318351-274a118407c2?ixlib=rb-1.2.1&amp;q=80&amp;fm=jpg&amp;crop=entropy&amp;cs=tinysrgb&amp;w=1080&amp;fit=max&amp;ixid=eyJhcHBfaWQiOjExNzczfQ" alt="Adding static shortcuts to your app"><p>In a <a href="https://adenearnshaw.com/adding-app-shortcuts">previous post</a> I showed how you could use my <a href="https://www.nuget.org/packages/Plugin.AppShortcuts/">AppShortcuts plugin</a> to add Dynamic shortcuts to your Xamarin Apps. Along with Dynamic shortcuts, both iOS and Android also provide Static shortcuts which can be added declaratively.</p><p>Static shortcuts are declared via the app&apos;s manifests, added automatically during installation and can&apos;t be manipulated via the app. Dynamic and Static shortcuts both have their uses and can be used in combination with each other.</p><p>A full sample app that demo&apos;s how to add and use Static shortcuts can be found here: <a href="https://github.com/adenearnshaw/xam-static-shortcuts">github.com/adenearnshaw/xam-static-shortcuts</a></p><!--kg-card-begin: markdown--><h2 id="handlingapplinksinxamarinforms">Handling AppLinks in Xamarin Forms</h2>
<p>The Xamarin Forms Application class has a built in method for handling Shortcuts. This method is the <em>OnAppLinkRequestReceived()</em> and is called once the App&apos;s constructor has completed. This allows us to handle any navigation we may wish to occur.</p>
<p>In the <a href="https://github.com/adenearnshaw/xam-static-shortcuts/blob/master/src/AppShortcutsSample/AppShortcutsSample/App.xaml.cs">sample</a>, I remove the uri&apos;s base and then check to see if what remains matches one of the known keys. It&apos;s crude and would never see production, but it gives you an idea.</p>
<pre><code class="language-csharp">public partial class App : Xamarin.Forms.Application
{
    private const string AppShortcutUriBase = &quot;stc://staticshortcuts/&quot;;
    private const string ShortcutKey_Favorite = &quot;favorites&quot;;
    ...
    
    protected override async void OnAppLinkRequestReceived(Uri uri)
    {
        var shortcutKey = uri.ToString().Replace(AppShortcutUriBase, &quot;&quot;);

        if (shortcutKey == ShortcutKey_Favorite)
            await NavigationService.Instance.Navigate(new FavoritesPage());
        else
            base.OnAppLinkRequestReceived(uri);
    }
}
</code></pre>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h2 id="iosimplementation">iOS implementation</h2>
<p>To add shortcuts (or <a href="https://developer.apple.com/design/human-interface-guidelines/ios/extensions/home-screen-actions/">Quick Actions</a> as Apple call them) to iOS, is relatively trivial. Firstly declare the shortcuts in the Info.plist and then override <strong>AppDelegate</strong>.<em>PerformActionForShortcutItem()</em> to martial the data to the Xamarin Forms App.</p>
<h3 id="updatingtheinfoplist">Updating the Info.plist</h3>
<p>Shortcuts are declared as a dictionary item within an array with the key <strong>UIApplicationShortcutItems</strong>. Each dictionary item within the array must include keys for <strong>UIApplicationShortcutItemTitle</strong> and <strong>UIApplicationShortcutItemType</strong>. Optional properties for a Subtitle, Icon and additional data can also be added.</p>
<p>Sample:</p>
<pre><code class="language-xml">&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;!DOCTYPE plist PUBLIC &quot;-//Apple//DTD PLIST 1.0//EN&quot; &quot;http://www.apple.com/DTDs/PropertyList-1.0.dtd&quot;&gt;
&lt;plist version=&quot;1.0&quot;&gt;
&lt;dict&gt;
  ...
  &lt;key&gt;UIApplicationShortcutItems&lt;/key&gt;
    &lt;array&gt;
      &lt;dict&gt;
        &lt;key&gt;UIApplicationShortcutItemType&lt;/key&gt;
        &lt;string&gt;stc://staticshortcuts/favorites&lt;/string&gt;
        &lt;key&gt;UIApplicationShortcutItemTitle&lt;/key&gt;
        &lt;string&gt;My favorites&lt;/string&gt;
        &lt;key&gt;UIApplicationShortcutItemSubtitle&lt;/key&gt;
        &lt;string&gt;View favorited monkeys&lt;/string&gt;            
        &lt;key&gt;UIApplicationShortcutItemIconType&lt;/key&gt;
        &lt;string&gt;UIApplicationShortcutIconTypeFavorite&lt;/string&gt;
        &lt;key&gt;UIApplicationShortcutItemUserInfo&lt;/key&gt;
          &lt;dict&gt;
            &lt;key&gt;dataKey1&lt;/key&gt;
            &lt;string&gt;dataValue1&lt;/string&gt;
          &lt;/dict&gt;
      &lt;/dict&gt;
    &lt;/array&gt;
&lt;/dict&gt;
&lt;/plist&gt;
</code></pre>
<p>Here we&apos;ve declared one shortcut to allow users to jump straight to the Favorites page of an app. The <strong>UIApplicationShortcutItemType</strong> can be any string, but I recommend following a URL format so that the Xamarin.Forms.Application identifies the AppLink correctly.</p>
<p>We&apos;re also leveraging the built in <em>Favorites</em> icon provided by iOS. A list of the icons can be found in Apple&apos;s <a href="https://developer.apple.com/design/human-interface-guidelines/ios/icons-and-images/system-icons#home-screen-quick-action-icons">Human Interface Guidelines</a> and the corresponding Constant values are listed in Apple&apos;s <a href="https://developer.apple.com/documentation/uikit/uiapplicationshortcuticontype">Developer Documentation</a>. Custom icons can be declared using <strong>UIApplicationShortcutItemIconFile</strong>, but that&apos;s beyond the scope of this.</p>
<h3 id="handlingthequickaction">Handling the quick action</h3>
<p>App links should be handled by <strong>Application</strong>.<em>OnAppLinkRequestReceived()</em>. However, we need to add some additional code to our AppDelegate in order for the Forms Application to know about the shortcuts.</p>
<p>Add this into the AppDelegate within the iOS project:</p>
<pre><code class="language-csharp">public override void PerformActionForShortcutItem(UIApplication application, UIApplicationShortcutItem shortcutItem, UIOperationHandler completionHandler)
{
    if (!string.IsNullOrEmpty(shortcutItem?.Type))
    {
        Xamarin.Forms.Application.Current.SendOnAppLinkRequestReceived(new Uri(shortcutItem.Type));
    }
}
</code></pre>
<p>The <em>PerformActionForShortcutItem()</em> method is called automatically when a user clicks through from a Shortcut. Here we check if the shortcutItem&apos;s Type property has a value and then pass this as a Uri to the Xamarin Forms App.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h2 id="androidimplementation">Android implementation</h2>
<p>Implementing shortcuts on Android is almost as simple as iOS, but there&apos;s just a little more ceremony involved.</p>
<h3 id="updatingtheactivity">Updating the Activity</h3>
<p>Firstly, find the Activity where you decare <strong>MainLauncher = true</strong> and add the properties <code>Exported = true</code> and <code>Name = &quot;com.mycompany.myapp.mainlauncher&quot;</code> to the Activity attribute. <em>Exported</em> needs to be set in order for the shortcut to see the activity, and <em>Name</em> must be set in order for a user-friendly version of activity name to be shown (otherwise you&apos;ll have to deal with unsightly guids).</p>
<p>Underneath this, add a new MetaDataAttribute to the class to inform the app where the shortcut data is located.</p>
<pre><code class="language-csharp">[MetaData(&quot;android.app.shortcuts&quot;, Resource = &quot;@xml/shortcuts&quot;)]
</code></pre>
<p>Now you need to create your shortcut data.</p>
<h3 id="creatingshortcutmetadata">Creating Shortcut metadata</h3>
<p>In your <strong>Resources</strong> folder, if one doesn&apos;t exist, create an <strong>xml</strong> folder and within that create a <strong>shortcuts.xml</strong>. This is where you will declare your shortcuts. Unfortunately, it&apos;s a bit more verbose than iOS.</p>
<pre><code class="language-xml">&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot; ?&gt; 
&lt;shortcuts xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;&gt;
  &lt;shortcut
    android:shortcutId=&quot;favorites&quot;
    android:enabled=&quot;true&quot;
    android:icon=&quot;@drawable/ic_sc_favorite&quot;
    android:shortcutShortLabel=&quot;@string/sc_favorites_short&quot;
    android:shortcutLongLabel=&quot;@string/sc_favorites_long&quot;
    android:shortcutDisabledMessage=&quot;@string/sc_favorites_disabled&quot;&gt;
    &lt;intent
      android:action=&quot;android.intent.action.VIEW&quot;
      android:targetPackage=&quot;com.mycompany.myapp&quot;
      android:targetClass=&quot;com.mycompany.myapp.mainlauncher&quot;
      android:data=&quot;stc://staticshortcuts/favorites&quot; /&gt;
    &lt;categories android:name=&quot;android.shortcut.conversation&quot; /&gt;
  &lt;/shortcut&gt;
&lt;/shortcuts&gt;
</code></pre>
<p>Here again we&apos;ve declared a shortcut that will navigate users to the app&apos;s Favorites page.</p>
<p>Things to note:</p>
<ul>
<li>Labels and messages must come from the strings.xml and can&apos;t be hardcoded - this produces a build error.</li>
<li>The icon can be any png or android vector stored in your Resources/Drawable folder - Some useful images can be found within my <a href="https://github.com/adenearnshaw/AppShortcutsPlugin/tree/master/src/Plugin.AppShortcuts/Resources/drawable">AppShortcuts Plugin Repo</a></li>
<li>The value for <strong>android:targetClass</strong> must match the <strong>Name</strong> declared in the Activity attribute earlier.</li>
<li>The <strong>android:data</strong> value must be able to be parsed to a Uri in order for Xamarin Forms to handle it correctly.</li>
</ul>
<p>Providing the <strong>android:data</strong> value is a Uri format and the Activity which calls LoadApplication(new App()) has the data within it&apos;s Intent. Then Xamarin Forms will automatically call <strong>Application</strong>.<em>OnAppLinkRequestReceived()</em> without you doing anything further.</p>
<blockquote>
<p>If your MainLauncher Activity is not the same as the one that creates the XamarinForms application (e.g. you&apos;ve got a SplashScreenActivity), then you&apos;ll need to pass the shortcut data into the new Intent.</p>
<pre><code class="language-csharp">protected override void OnResume()
{
    base.OnResume();
    var intent = new Intent(Application.Context, typeof(MainActivity));
    
    intent.SetAction(Intent.ActionView);
    intent.SetData(Intent?.Data);
    
    StartActivity(intent);
}
</code></pre>
<p>It&apos;s this data that Xamarin.Forms uses to see whether <em>OnAppLinkRequestReceived()</em> needs to be called</p>
</blockquote>
<p>For more detailed information on how to create shortcuts for Android, the <a href="https://developer.android.com/guide/topics/ui/shortcuts/creating-shortcuts">developer docs</a> have a derth of information.</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Utilising Autofill in an Xamarin Forms Android App]]></title><description><![CDATA[With the introduction of Oreo, Android announced a new feature called Autofill which allows form elements to be supplied with user data from system wide data providers. 

Learn how to use this within your Xamarin Forms apps by creating a Platform Specific Effect which can update your Android label.]]></description><link>https://adenearnshaw.com/android-autofill-in-xamarin-forms/</link><guid isPermaLink="false">5f175d8aadd0ae0db6dcd4e6</guid><category><![CDATA[Xamarin]]></category><category><![CDATA[Xamarin Forms]]></category><category><![CDATA[Android]]></category><dc:creator><![CDATA[Aden Earnshaw]]></dc:creator><pubDate>Sat, 01 Sep 2018 23:29:00 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1526045612212-70caf35c14df?ixlib=rb-0.3.5&amp;q=80&amp;fm=jpg&amp;crop=entropy&amp;cs=tinysrgb&amp;w=1080&amp;fit=max&amp;ixid=eyJhcHBfaWQiOjExNzczfQ&amp;s=cf3bf63ed8e3f78e4a18867bbf183aa8" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><h2 id="whatisandroidautofill">What is Android Autofill?</h2>
<img src="https://images.unsplash.com/photo-1526045612212-70caf35c14df?ixlib=rb-0.3.5&amp;q=80&amp;fm=jpg&amp;crop=entropy&amp;cs=tinysrgb&amp;w=1080&amp;fit=max&amp;ixid=eyJhcHBfaWQiOjExNzczfQ&amp;s=cf3bf63ed8e3f78e4a18867bbf183aa8" alt="Utilising Autofill in an Xamarin Forms Android App"><p>Account creation, login, and credit card transactions take time and are prone to errors. Users can easily get frustrated with apps that require these types of repetitive tasks. Android 8.0 (API level 26) makes filling out forms, such as login and credit card forms, easier with the introduction of the <a href="https://developer.android.com/guide/topics/text/autofill">Autofill Framework</a>.</p>
<p>The framework is divided into two parts; Apps that can store autofill data (such as password managers or banking apps), and apps that can consume the data of a user&apos;s chosen Autofill service.</p>
<h2 id="xamarinformseffectsplatformspecifics">Xamarin Forms Effects &amp; Platform Specifics</h2>
<p>Back in the early days of Xamarin Forms, if you wanted to extend the functionality of an Element to provide additional properties to its underlying native control, you had to create Custom Renderers to replace substantial parts of the logic, sometimes with unexpected consequences.</p>
<p>Fast forward to mid-2016 and Xamarin introduced a new way to extend a native control&apos;s functionality: Effects. These allow the native controls on each platform to be customized in a similar way to Custom Renderers, but with much less faff. In most cases, if you only want to add a couple of minor styling changes to a control, they&apos;re the recommended approach.</p>
<p>As the Framework continues to evolve, Xamarin keep improving the ways in which developers can add custom functionality. <a href="https://docs.microsoft.com/en-us/xamarin/xamarin-forms/platform/platform-specifics/">Platform Specifics</a> provide a method of accessing features unique to certain platforms by utilising attached properties, which can be specified in Xaml or Code-behind.</p>
<h2 id="addinganautofilleffectintoyourapp">Adding an Autofill Effect into your app</h2>
<p>In order to incorporate the Autofill feature into an app, we&apos;ll first start with creating the PlatformSpecifics class in our Shared project which provide the AttachedProperties and store the  Autofill Type value for each control. Then we&apos;ll build an Effect, which we&apos;ll utilise to get the value from the AttachedProperty and use it to modify the Control.</p>
<p>A full sample of the code can be found here: <a href="https://github.com/adenearnshaw/xam-autofill-effect">GitHub</a></p>
<h3 id="autofillhinttypes">AutofillHintTypes</h3>
<p>The Autofill service works by matching keys which are stored as strings. Android recommend using the constants provided by the <a href="https://developer.android.com/reference/android/view/View.html#AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE">View</a>, however, as these are specific to Android, we&apos;ll create an enum which can expose these within the Shared Project.</p>
<pre><code class="language-csharp">public enum AutofillHintType
{
    [Description(&quot;&quot;)]
    None,
    [Description(&quot;creditCardExpirationDate&quot;)]
    CreditCardExpirationDate,
    [Description(&quot;creditCardExpirationDay&quot;)]
    CreditCardExpirationDay,
    [Description(&quot;creditCardExpirationMonth&quot;)]
    CreditCardExpirationMonth,
    [Description(&quot;creditCardExpirationYear&quot;)]
    CreditCardExpirationYear,
    [Description(&quot;creditCardNumber&quot;)]
    CreditCardNumber,
    [Description(&quot;creditCardSecurityCode&quot;)]
    CreditCardSecurityCode,
    [Description(&quot;emailAddress&quot;)]
    EmailAddress,
    [Description(&quot;name&quot;)]
    Name,
    [Description(&quot;password&quot;)]
    Password,
    [Description(&quot;phone&quot;)]
    Phone,
    [Description(&quot;postalAddress&quot;)]
    PostalAddress,
    [Description(&quot;postalCode&quot;)]
    PostalCode,
    [Description(&quot;username&quot;)]
    Username
}
</code></pre>
<p>We utilise the <strong>System.ComponentModel.DescriptionAttribute</strong> to specify the constant value consistent with Android.</p>
<h3 id="autofillplatformspecifics">Autofill PlatformSpecifics</h3>
<p>Next we&apos;ll add an AttachedProperty that can be used by the view and hook up its <strong>OnChanged</strong> event to add or remove the AutofillEffect (that we&apos;ll create later) to the Native Android control.</p>
<pre><code class="language-csharp">namespace XamAutofill.PlatformConfiguration.AndroidSpecific
{
    using System.Linq;
    using Xamarin.Forms;
    using FormsElement = Xamarin.Forms.Entry;

    public static class Entry
    {
        const string EffectName = &quot;com.adenearnshaw.AutofillEffect&quot;;

        public static readonly BindableProperty AutofillHintProperty =
            BindableProperty.CreateAttached(nameof(AutofillHint),
                                            typeof(AutofillHintType),
                                            typeof(Entry),
                                            AutofillHintType.None,
                                            propertyChanged: OnAutofillHintPropertyChanged);

        public static AutofillHintType GetAutofillHint(BindableObject element)
        {
            return (AutofillHintType)element.GetValue(AutofillHintProperty);
        }

        public static void SetAutofillHint(BindableObject element, AutofillHintType value)
        {
            element.SetValue(AutofillHintProperty, value);
        }

        private static void OnAutofillHintPropertyChanged(BindableObject element, object oldValue, object newValue)
        {
            if ((AutofillHintType)newValue != AutofillHintType.None)
            {
                AttachEffect(element as FormsElement);
            }
            else
            {
                DetachEffect(element as FormsElement);
            }
        }

        private static void AttachEffect(FormsElement element)
        {
            IElementController controller = element;
            if (controller == null || controller.EffectIsAttached(EffectName))
            {
                return;
            }
            element.Effects.Add(Effect.Resolve(EffectName));
        }

        private static void DetachEffect(FormsElement element)
        {
            IElementController controller = element;
            if (controller == null || !controller.EffectIsAttached(EffectName))
            {
                return;
            }

            var toRemove = element.Effects.FirstOrDefault(e =&amp;gt; e.ResolveId == Effect.Resolve(EffectName).ResolveId);
            if (toRemove != null)
            {
                element.Effects.Remove(toRemove);
            }
        }
    }
}
</code></pre>
<p>Now that we have the attached property, we&apos;ll add the second half of this class which is a couple of Extension methods which allow the AttachedProperty to be accessed via the PlatformConfiguration Fluent API.</p>
<pre><code class="language-csharp">namespace XamAutofill.PlatformConfiguration.AndroidSpecific
{
    using System.Linq;
    using Xamarin.Forms;
    using Xamarin.Forms.PlatformConfiguration;
    using FormsElement = Xamarin.Forms.Entry;

    public static class Entry
    {
        const string EffectName = &quot;com.adenearnshaw.AutofillEffect&quot;;

        ...

        public static AutofillHintType AutofillHint(this IPlatformElementConfiguration&amp;lt;Android, FormsElement&amp;gt; config)
        {
            return GetAutofillHint(config.Element);
        }

        public static IPlatformElementConfiguration&amp;lt;Android, FormsElement&amp;gt; SetAutofillHint(this IPlatformElementConfiguration&amp;lt;Android, FormsElement&amp;gt; config, AutofillHintType value)
        {
            SetAutofillHint(config.Element, value);
            return config;
        }
    }
}
</code></pre>
<h3 id="autofilleffect">AutofillEffect</h3>
<p>Now we have our PlatformSpecifics code, we&apos;ll add in the AutofillEffect so that we can apply our property to the Native control.</p>
<p>First, create a <strong>RoutingEffect</strong> in the Shared code. This is a shell, and allows the Shared code a link to the Platform&apos;s Effect that we&apos;ll create next.</p>
<pre><code class="language-csharp">namespace XamAutofill
{
    public class AutofillEffect : RoutingEffect
    {
        public AutofillEffect() : base(&quot;com.adenearnshaw.AutofillEffect&quot;)
        {
        }
    }
}
</code></pre>
<p>Second is to create the <strong>PlatformEffect</strong>. This is created in the <strong>Android Project</strong> and contains the logic to apply the property to the native control.</p>
<pre><code class="language-csharp">using Xamarin.Forms.Platform.Android;
using Xamarin.Forms;
using System;
using System.Reflection;
using System.ComponentModel;
using XamAutofill.PlatformConfiguration.AndroidSpecific;
using Entry = Xamarin.Forms.Entry;

[assembly: ResolutionGroupName(&quot;com.adenearnshaw&quot;)] // Remember, only set this on one effect within your App, otherwise conflicts can occur.
[assembly: ExportEffect(typeof(XamAutofill.Droid.AutofillEffect), &quot;AutofillEffect&quot;)]
namespace XamAutofill.Droid
{
    public class AutofillEffect : PlatformEffect
    {
        protected override void OnAttached()
        {
            try
            {
                if (!IsSupported())
                    return;

                var control = Control as Android.Widget.EditText;

                var hint = GetAndroidAutofillHint();
                control.ImportantForAutofill = Android.Views.ImportantForAutofill.Yes;
                control.SetAutofillHints(hint);
            }
            catch (Exception ex)
            {
                Console.WriteLine(&quot;Cannot set property on attached control. Error: {0}&quot;, ex.Message);
            }
        }

        protected override void OnDetached()
        {
            if (!IsSupported())
                return;

            Control.SetAutofillHints(string.Empty);

            Control.ImportantForAutofill = Android.Views.ImportantForAutofill.Auto;
        }

        private bool IsSupported()
        {
            return Element as Entry != null &amp;amp;&amp;amp; 
                   Android.OS.Build.VERSION.SdkInt &amp;gt;= Android.OS.BuildVersionCodes.O;
        }

        private string GetAndroidAutofillHint()
        {
            var hint = ((Entry)Element).OnThisPlatform().AutofillHint();
            var constantValue = GetEnumDescription(hint);
            return constantValue;
        }

        private static string GetEnumDescription(Enum value)
        {
            FieldInfo fi = value.GetType().GetField(value.ToString());

            DescriptionAttribute[] attributes =
                (DescriptionAttribute[])fi.GetCustomAttributes(typeof(DescriptionAttribute), false);

            return attributes != null &amp;amp;&amp;amp; attributes.Length &amp;gt; 0 ? attributes[0].Description : value.ToString();
        }
    }
}
</code></pre>
<p>When the AttachedProperty in the SharedCode is declared and has a value other than <strong>AutofillHintType.None</strong>, then an Effect is attached to the Control. This then does the following:</p>
<ol>
<li>The PlatformEffect&apos;s <strong>OnAttached</strong> method checks to see if Autofill is supported</li>
<li>Then gets the enum value from the AutofillHint() extension method declared earlier and uses reflection to get the constant declared in the DescriptionAttribute.</li>
<li>The constant is then applied to the Control using the <strong>EditText.SetAutofillHints()</strong> method.</li>
</ol>
<p>The <strong>EditText.ImportantForAutofill</strong> property is also set to force the Autofill service to lookup and insert a value for the field.</p>
<h3 id="consumingthecode">Consuming the code</h3>
<p>Right, we&apos;ve got all the parts we need, we just need to use them now. Below are two examples of how the PlatformSpecifics can be used. In XAML, declare the namespace for at the top of the file, then add the AttachedProperty to your Entry element. In Code-Behind, use the OnPlatform Fluent API to set the property using the Extension method</p>
<h4 id="xaml">XAML</h4>
<pre><code class="language-xml">&lt;ContentPage xmlns=&quot;http://xamarin.com/schemas/2014/forms&quot;
             xmlns:x=&quot;http://schemas.microsoft.com/winfx/2009/xaml&quot;
             xmlns:android=&quot;clr-namespace:XamAutofill.PlatformConfiguration.AndroidSpecific;assembly=XamAutofill&quot;
             x:Class=&quot;XamAutofill.MainPage&quot; &gt;
    &lt;StackLayout Margin=&quot;12,12,12,12&quot;&gt;
        &lt;Entry HorizontalOptions=&quot;Fill&quot;
               Placeholder=&quot;Your name&quot;
               Keyboard=&quot;Text&quot;
               android:Entry.AutofillHint=&quot;Name&quot;/&gt;
        &lt;Entry x:Name=&quot;PhoneEntry&quot;
               HorizontalOptions=&quot;Fill&quot;
               Placeholder=&quot;Your phone&quot;
               Keyboard=&quot;Telephone&quot;/&gt;
    &lt;/StackLayout&gt;
&lt;/ContentPage&gt;
</code></pre>
<h4 id="codebehind">Code-behind</h4>
<pre><code class="language-csharp">public partial class MainPage : ContentPage
{
    public MainPage()
    {
        InitializeComponent();

        PhoneEntry.On&amp;lt;Android&amp;gt;().SetAutofillHint(AutofillHintType.Phone);
    }
}
</code></pre>
<h2 id="links">Links</h2>
<p>A full sample of the code can be found here: <a href="https://github.com/adenearnshaw/xam-autofill-effect">GitHub</a></p>
<p>More information on creating Effects &amp; Platform specifcs:<br>
Creating Effects: <a href="https://docs.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/effects/creating">docs.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/effects/creating</a><br>
Creating PlatformSpecifics: <a href="https://docs.microsoft.com/en-us/xamarin/xamarin-forms/platform/platform-specifics/creating">docs.microsoft.com/en-us/xamarin/xamarin-forms/platform/platform-specifics/creating</a><br>
Consuming PlatformSpecifics: <a href="https://docs.microsoft.com/en-us/xamarin/xamarin-forms/platform/platform-specifics/consuming/android">docs.microsoft.com/en-us/xamarin/xamarin-forms/platform/platform-specifics/consuming/android</a><br>
Testing Autofill: <a href="https://developer.xamarin.com/samples/monodroid/android-o/AutofillFramework/">developer.xamarin.com/samples/monodroid/android-o/AutofillFramework/</a></p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Adding shortcuts to your app's icon]]></title><description><![CDATA[App Shortcuts provide users with quick actions into our apps that enhance the UX. They can be static, where they're declared as part of the app's manifest, or can be added dynamically through code. Learn how to add App Shortcuts in a Xamarin Forms app, using the AppShortcuts Plugin.]]></description><link>https://adenearnshaw.com/adding-app-shortcuts/</link><guid isPermaLink="false">5f175d8aadd0ae0db6dcd4e5</guid><category><![CDATA[Xamarin]]></category><category><![CDATA[Xamarin Forms]]></category><category><![CDATA[Android]]></category><category><![CDATA[iOS]]></category><category><![CDATA[UWP]]></category><category><![CDATA[Shortcuts]]></category><dc:creator><![CDATA[Aden Earnshaw]]></dc:creator><pubDate>Thu, 30 Aug 2018 00:39:00 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1511075675422-c8e008f749d7?ixlib=rb-0.3.5&amp;q=80&amp;fm=jpg&amp;crop=entropy&amp;cs=tinysrgb&amp;w=1080&amp;fit=max&amp;ixid=eyJhcHBfaWQiOjExNzczfQ&amp;s=69e969fa57bab026e3bd5e902ee4278c" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><h2 id="abriefintro">A brief intro</h2>
<img src="https://images.unsplash.com/photo-1511075675422-c8e008f749d7?ixlib=rb-0.3.5&amp;q=80&amp;fm=jpg&amp;crop=entropy&amp;cs=tinysrgb&amp;w=1080&amp;fit=max&amp;ixid=eyJhcHBfaWQiOjExNzczfQ&amp;s=69e969fa57bab026e3bd5e902ee4278c" alt="Adding shortcuts to your app&apos;s icon"><p>In Windows 95, users were introduced to the paradigm of a shortcut context menus. These menus were limited, but provided the user with additional actions that could be achieved by other means, but took more effort. As Windows advanced, so did the functionality found in the context menus with extensibility options allowing third-parties to integrate custom actions too.</p>
<p>Fast forward a few years to the release of the iPhone 6s and the introduction of a feature called <a href="https://developer.apple.com/ios/3d-touch/">3D Touch</a> which brought shortcut context menus to the smartphone masses. Last year in 2017, Android also thought this may be a nice to have, and added the feature to their Nougat 7.1 release.</p>
<p>As developers, we can utilize this feature to provide the user with quick actions into our apps that enhance the UX. For example, many browsers like Chrome, Edge &amp; Safari have shortcuts to open a new incognito tab and the Shazam app includes the ability to initiate a search straight from the home screen, saving crucial seconds when you&apos;re trying to identify that snippet of a song.</p>
<div class="d-none d-sm-block">
<div class="d-flex justify-content-center" style="margin:10px 0 10px 0;">
	<img alt="Adding shortcuts to your app&apos;s icon" src="https://adenearnshaw.com/content/images/2018/09/plugin_appshortcuts_example_droid.jpg" style="height: 400px; margin-right:20px;">
	<img alt="Adding shortcuts to your app&apos;s icon" src="https://adenearnshaw.com/content/images/2018/09/plugin_appshortcuts_example_ios.jpg" style="height: 400px; margin-left:20px;">
    </div>
</div>
<p>App shortcuts can be static, where they&apos;re declared as part of the app&apos;s manifest, or can be added dynamically through code. This post is here to demonstrate how the latter can be done within a Xamarin Forms app, using the <a href="https://www.nuget.org/packages/Plugin.AppShortcuts">AppShortcuts Plugin</a>.</p>
<h2 id="addingtheplugintoyourapp">Adding the plugin to your app</h2>
<p>The AppShortcuts plugin can be installed via Nuget by searching for <strong>Plugin.AppShortcuts</strong> in the Nuget Explorer or via the Package Manager console with the command: <code>PM&gt; Install-Package Plugin.AppShortcuts</code></p>
<p>Install the plugin into the project where you&apos;ll be implementing the code and also each platform specific project.</p>
<p>Once installed, there is an extra step required for Android. In the <code>MainActivity.OnCreate()</code> before the <code>LoadApplication()</code> call, make a call to:</p>
<pre><code class="language-csharp">CrossAppShortcuts.Current.Init();
</code></pre>
<h2 id="addingashortcut">Adding a shortcut</h2>
<p>To add a shortcut to the app&apos;s icon, first you need to create a new instance of the <code>Shortcut</code> class and populate it with the information you wish to pin.</p>
<pre><code class="language-csharp">using Plugin.AppShortcuts;
using Plugin.AppShortcuts.Icons;

...

var shortcut = new Shortcut()
{
    Label = &quot;Shortcut 1&quot;,
    Description = &quot;My shortcut&quot;,
    Icon = new FavoriteIcon(),
    Uri = &quot;asc://AppShortcutsApp/Detail/shortcut_1_id&quot;
};
</code></pre>
<p>The plugin has a number of supplied icons built in that you can use, or you can provide your own by using the <strong>CustomIcon</strong> class</p>
<p>Once you have your shorcut object, to add it to the App Icons shortcuts you call:</p>
<pre><code class="language-csharp">await CrossAppShortcuts.Current.AddShortcut(shortcut);
</code></pre>
<p><em>Note; you can add as any shortcuts as you wish, but only four will ever be displayed on the homepage. This is not tracked by the plugin.</em></p>
<h2 id="handlingdeeplinkswhenashortcutsclicked">Handling deeplinks when a shortcut&apos;s clicked</h2>
<p>To provide a consistent UX when the user clicks a shortcut to launch the app, the code to handle what happens, should be done in the <code>App.cs</code> class&apos; <code>OnAppLinkReceived()</code> method. This passes in a Uri from the platform as a parameter. In order for each platform to pass the uri to this method, some additional work is required.</p>
<pre><code class="language-csharp">protected override void OnAppLinkRequestReceived(Uri uri)
{
    var itemId = uri.ToString().Replace(&quot;asc://AppShortcutsApp/Detail/&quot;, &quot;&quot;);
	var item = Repository.Instance.Items.FirstOrDefault(m =&gt; m.Id.Equals(itemId));

	if (item != null)
		MainPage.Navigation.PushAsync(new DetailsPage(item));
	else
		base.OnAppLinkRequestReceived(uri);
}
</code></pre>
<h3 id="android">Android</h3>
<p>In order for Android to launch your app from a shortcut, it needs to be told that the shortcut&apos;s uri can be handled by the app. This is done by adding an <strong><a href="https://developer.xamarin.com/guides/android/platform_features/app-linking/#configure-intent-filter">IntentFilter</a></strong> attribute to the <strong>MainActivity</strong>.</p>
<pre><code class="language-csharp">[Activity(Label = &quot;AppShortcuts Sample&quot;,
          Theme = &quot;@style/MainTheme&quot;)]
[IntentFilter(new[] { Intent.ActionView },
              Categories = new[] { Intent.CategoryDefault },
              DataScheme = &quot;asc&quot;,
              DataHost = &quot;AppShortcutsApp&quot;,
              AutoVerify = true)]
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
{
    ...
    
</code></pre>
<p>This is all that needs to be done for Android, the <code>FormsAppCompatActivity</code> will look to see if the app launched with a Uri and pass this through to the <code>App</code> class.</p>
<h3 id="ios">iOS</h3>
<p>iOS will automatically launch the app from a shortcut, however, the <code>FormsApplicationDelegate</code> is not setup to pass the data through to the <code>App</code> class. To do this, the AppDelegate&apos;s <code>PerformActionForShortcutItem()</code> needs to be overridden.</p>
<pre><code class="language-csharp">public override void PerformActionForShortcutItem(UIApplication application, UIApplicationShortcutItem shortcutItem, UIOperationHandler completionHandler)
{
    var uri = Plugin.AppShortcuts.iOS.ArgumentsHelper.GetUriFromApplicationShortcutItem(shortcutItem);
    if (uri != null)
    {
        Xamarin.Forms.Application.Current.SendOnAppLinkRequestReceived(uri);
    }
}
</code></pre>
<h3 id="uwp">UWP</h3>
<p>Similar to iOS, a UWP app will launch the app when the shortcut is clicked, but needs some additional setup to pass the Uri back to the Forms <code>App</code> class.</p>
<p>A restriction of UWP is that its implementation of shortcuts doesn&apos;t provide the ability to set multiple properties. In order for The Plugin to overcome this, the shortcut&apos;s ID and Uri are serialized into a JSON object.</p>
<p>Firstly, in the UWP <code>MainPage</code> call the helper method to split the NavigationArgs and pass this to the Forms <code>App</code>. Then override the <code>OnNavigatedTo()</code> to call it. Your UWP <code>MainPage</code> should look similar to this:</p>
<pre><code class="language-csharp">public sealed partial class MainPage : WindowsPage
{
    public MainPage()
    {
        this.InitializeComponent();
        LoadApplication(new App());
    }

    protected override void OnNavigatedTo(NavigationEventArgs e)
    {
        base.OnNavigatedTo(e);
        OnLaunchedEvent(e.Parameter.ToString());
    }

        public void OnLaunchedEvent(string arguments)
        {
            if (!string.IsNullOrEmpty(arguments))
            {
                var argsUri = JumplistArgumentsHelper.GetUriFromJumplistArguments(arguments);
                Xamarin.Forms.Application.Current.SendOnAppLinkRequestReceived(argsUri);
            }
        }
    }
</code></pre>
<p>Next, in the UWP <code>App</code> class, modify the <code>OnLaunched()</code> method so that if <code>rootFrame.Content</code> is not null, then it calls the MainPage&apos;s <code>OnLaunchedEvent()</code> directly:</p>
<pre><code class="language-csharp">protected override void OnLaunched(LaunchActivatedEventArgs e)
{
    ...

    if (rootFrame.Content == null)
    {
        rootFrame.Navigate(typeof(MainPage), e.Arguments);
    }
    else
    {
        var page = rootFrame.Content as MainPage;
        page?.OnLaunchedEvent(e.Arguments);
    }
    Window.Current.Activate();
}
</code></pre>
<p>To see how this plugin works within the context of a full application, a <a href="https://github.com/adenearnshaw/AppShortcutsPlugin/tree/master/samples">sample</a>  can be found on the Plugin&apos;s <a href="https://github.com/adenearnshaw/AppShortcutsPlugin">GitHub</a> repo, along with full <a href="https://adenearnshaw.github.io/AppShortcutsPlugin/">documentation</a> of the library&apos;s features.</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Animation in an Angular app]]></title><description><![CDATA[Animations, providing they are done right are an essential part of a good UX. Although CSS3 provides a rich animation library, Angular enriches this to provide a extensive array of effects.

See how you can use both Angular and CSS to animate a hamburger menu containing a dynamic list of menu items.]]></description><link>https://adenearnshaw.com/animation-in-an-angular-app/</link><guid isPermaLink="false">5f175d8aadd0ae0db6dcd4e4</guid><category><![CDATA[Angular]]></category><category><![CDATA[Web]]></category><dc:creator><![CDATA[Aden Earnshaw]]></dc:creator><pubDate>Tue, 28 Aug 2018 12:48:00 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="https://adenearnshaw.com/content/images/2018/09/ng_animation_full.gif" alt="Menu animations" align="right" style="margin-left: 20px; max-height:400px">
<p>Animations providing they are done right are an essential part of a good UX. Although CSS3 provides a rich animation library to suit most needs, Angular enriches this with its own api to provide a extensive array of effects.</p>
<p>Here is a demonstration of how you can use both Angular and CSS animations to animate a hamburger menu containing a dynamic list of menu items. This demo concentrates more on animations and therefore details on how the dynamic items are created won&apos;t be elaborated on here.</p>
<p>This post shows a lot of code-snippets which may be hard to follow in isolation. I recommend downloading the full sample project from GitHub and following the code within the context of an Angular application. The source can be found here: <a href="https://github.com/adenearnshaw/ng-animated-menu">GitHub</a></p>
<h2 id="usingangulartoanimatetheopenandcloseofthedrawer">Using Angular to animate the open and close of the drawer</h2>
<p>Angular has a variety of ways in which you can trigger animations, for this example we&apos;re going to use <a href="https://angular.io/api/animations/state">Animation States</a> to initiate the animation.</p>
<p>Before using animations in Angular, you need to declare a couple of modules that allow the animation declarations to be understood properly:</p>
<p><em>app.module.ts</em></p>
<pre><code class="language-typescript">import { BrowserModule } from &apos;@angular/platform-browser&apos;;
import { BrowserAnimationsModule } from &apos;@angular/platform-browser/animations&apos;;

@NgModule({
  imports: [ BrowserModule, BrowserAnimationsModule ],
  // ... more stuff ...
})
export class AppModule { }
</code></pre>
<p>Next, we&apos;ll define the animations in the component decorator of the main page:</p>
<p><em>home.component.ts</em></p>
<pre><code class="language-typescript">import { Component } from &quot;@angular/core&quot;;
import { trigger, state, style, transition, animate } from &quot;@angular/animations&quot;;

@Component({
    selector: &quot;app-home&quot;,
    templateUrl: &quot;./home.component.html&quot;,
    styleUrls: [&quot;./home.component.scss&quot;],
    animations: [
        trigger(&apos;slideInOut&apos;,[
            state(&apos;in&apos;, style({
                transform: &apos;translate3d(0,0,0)&apos;
            })),
            state(&apos;out&apos;, style({
                transform: &apos;translate3d(100%,0,0)&apos;
            })),
            transition(&apos;in =&gt; out&apos;, animate(&apos;400ms ease-in-out&apos;)),
            transition(&apos;out =&gt; in&apos;, animate(&apos;400ms ease-in-out&apos;))
        ])
    ]
})
export class HomeComponent { }
</code></pre>
<p>Here we define a trigger called <em>slideInOut</em>  and then add a couple of object states and define the transitions between those states.</p>
<p>Next we&apos;ll flesh out the component class, adding a boolean property to store whether the menu is open or not, a getter property to convert that to a state that the child component will be bound to, and a function that will allow us to toggle the boolean.</p>
<p><em>home.component.ts</em></p>
<pre><code class="language-typescript">export class HomeComponent {
    public isMenuOpen = false;

    get currentMenuState(): string{
        return this.isMenuOpen ? &apos;in&apos; : &apos;out&apos;;
    }

    public toggleMenu(): void {
        this.isMenuOpen = !this.isMenuOpen;
    }
}
</code></pre>
<p>Next we need to hook up the the animation in the page&apos;s HTML. Here we have a toggle button whose click event is bound to the component function, and a child component which holds our menu.</p>
<p><em>home.component.html</em></p>
<pre><code class="language-html">&lt;div&gt;
    &lt;div class=&quot;menu-toggle&quot;
        (click)=&quot;toggleMenu()&quot;&gt;
        &lt;div class=&quot;bar bar1&quot;&gt;&lt;/div&gt;
        &lt;div class=&quot;bar bar2&quot;&gt;&lt;/div&gt;
        &lt;div class=&quot;bar bar3&quot;&gt;&lt;/div&gt;
    &lt;/div&gt;
	
    ...
&lt;/div&gt;

&lt;app-menu-container [@slideInOut]=&quot;currentMenuState&quot;&gt;&lt;/app-menu-container&gt;
</code></pre>
<p>The key detail to note here is <code>[@slideInOut]=&quot;currentMenuState&quot;</code> this binds the animation to the child component using the trigger name and gets the current state value from the getter property we declared in the component&apos;s class.</p>
<p>Clicking on the hamburger button should ease the menu in from the right and</p>
<p><img src="https://adenearnshaw.com/content/images/2018/09/ng_animation_open_menu.gif" alt="Opening the menu" loading="lazy"></p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h2 id="hookingintoanimationevents">Hooking into animation events</h2>
<p>Angular also exposes <a href="https://angular.io/guide/animations#animation-callbacks">callbacks</a> on its animations so you can call functions when an animation starts or once it&apos;s completed (to reset fields, state, etc.).</p>
<p>The code below utilizes , we&apos;re binding to the animations <strong>done</strong> callback so that we can reset the underlying menu to page one. We don&apos;t want to trigger this as soon as the use clicks close, as it will cause the UX to look a bit odd.</p>
<p><em>home.component.ts</em></p>
<pre><code class="language-typescript">export class HomeComponent {
	...
	@ViewChild(&apos;menuContainer&apos;) menuContainer: MenuContainerComponent;

	public menuCloseAnimationComplete(event: AnimationEvent){
        if (!this.isMenuOpen){
            this.menuContainer.resetMenu();
        }
    }
}
</code></pre>
<p><em>home.component.html</em></p>
<pre><code class="language-html">&lt;app-menu-container #menuContainer
                    [@slideInOut]=&quot;currentMenuState&quot;
                    (@slideInOut.done)=&quot;menuCloseAnimationComplete()&quot;&gt;&lt;/app-menu-container&gt;

</code></pre>
<p>Here we&apos;ve added a reference to the child component declared in HTML to the code-behind using the <a href="https://angular.io/api/core/ViewChild">ViewChild</a> decorator. This allows us to access functions on that instance of the component and ensure that the logic to reset the menu is encapsulated to the <em>MenuComponent</em> itself.</p>
<h2 id="usingcsswithangularconditionalclass">Using css with Angular conditional class</h2>
<p>Angular can also help to trigger css animations by controlling the class&apos;s that appear on an HTML element.</p>
<p>Below you can see how we use the <a href="https://angular.io/api/common/NgClass">NgClass</a> directive to add a conditional class onto the toggle button. When the <em>isMenuOpen</em> boolean from the under-lying component is true, then the <em>.close</em> class is added to the button.</p>
<p><em>home.component.html</em></p>
<pre><code class="language-html">&lt;div class=&quot;menu-toggle&quot;
        [ngClass]=&quot;{&apos;close&apos;: isMenuOpen}&quot;
        (click)=&quot;toggleMenu()&quot;&gt;
    &lt;div class=&quot;bar bar1&quot;&gt;&lt;/div&gt;
    &lt;div class=&quot;bar bar2&quot;&gt;&lt;/div&gt;
    &lt;div class=&quot;bar bar3&quot;&gt;&lt;/div&gt;
&lt;/div&gt;
</code></pre>
<p>We then specify in the css that if the <em>.close</em> class is present, then modify each of the bars that make up the hamburger and animate them into a cross. As soon as the <em>.close</em> class is removed, the bars will return back to their normal position.</p>
<p><em>home.component.scss</em></p>
<pre><code class="language-scss">.menu-toggle {
    display: inline-block;
    cursor: pointer;

    .bar {
        width: 24px;
        height: 4px;
        background-color: #333;
        margin: 4px 0;
        transition: 0.1s;
    }

    &amp;.close {
        .bar1 {
            -webkit-transform: rotate(-45deg) translate(-6px, 6px);
            transform: rotate(-45deg) translate(-6px, 6px);
        }

        .bar2 {
            opacity: 0;
        }

        .bar3 {
            -webkit-transform: rotate(45deg) translate(-5px, -6px);
            transform: rotate(45deg) translate(-5px, -6px);
        }
    }
}
</code></pre>
<h2 id="usingcsswithangularpropertiestotriggeranimation">Using css with Angular properties to trigger animation</h2>
<p>The final way we&apos;re going to demonstrate how integrate css and angular animations is to bind the values of styles directly to properties on the Component&apos;s code-behind.</p>
<p><em>menu-container.component.ts</em></p>
<pre><code class="language-typescript">export class MenuContainerComponent {
	private readonly _menuWidth = 270;
    private readonly _animationDuration = 300;
	private _menuItemStack: MenuItemModel[] = []; // Each model in the stack represents a menu page
	private _pageListOffset = 0;

	get pageListWidth(): string { 
        return this._menuItemStack.length * this._menuWidth + &apos;px&apos;;
    }

    get pageListOffset(): string {
        return this._pageListOffset + &apos;px&apos;;
    }
		
	private goForward(clickedMenuItem: MenuItemModel): void {
        this._menuItemStack.push(clickedMenuItem);
        this._pageListOffset -= this._menuWidth;
    }

    private goBack(): void {
        this._pageListOffset += this._menuWidth;

    const timeout = this._animationDuration + 10; // Allow some leeway for animation to complete
        setTimeout(() =&gt; this._menuItemStack.pop(), timeout);
    }
}
</code></pre>
<p>In order to get a smooth scroll between the pages within the menu, each page is held in one big div whose width is adjusted to accommodate all the pages side-by-side and then the div&apos;s <em>left</em> property is adjusted to set the container&apos;s offset.</p>
<p><em>menu-container.component.html</em></p>
<pre><code class="language-html">&lt;div class=&quot;menu-container&quot;&gt;
    &lt;div class=&quot;pages-list&quot;
         [style.width]=&quot;pageListWidth&quot;
         [style.left]=&quot;pageListOffset&quot;&gt;
        &lt;div class=&quot;page&quot; *ngFor=&quot;let menuItem of menuItems&quot;&gt;
            &lt;app-menu-page [menuItem]=&quot;menuItem&quot;
                           (menuMoreClicked)=&quot;goForward($event)&quot;
                           (menuBackClicked)=&quot;goBack()&quot;&gt;&lt;/app-menu-page&gt;
        &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;
</code></pre>
<p><img src="https://adenearnshaw.com/content/images/2018/09/ng_animation_navigate_menu.gif" alt="Navigating the menu" loading="lazy"></p>
<p>Full sample code: <a href="https://github.com/adenearnshaw/ng-animated-menu">GitHub</a></p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>Full sample code: <a href="https://github.com/adenearnshaw/ng-animated-menu">GitHub</a></p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Building a TimePipe in Angular]]></title><description><![CDATA[Angular's DatePipe does a great job of formatting Date strings or objects into specified formats, however, if you want to pass in a time string like "09:00" you're out of luck. Here's a Pipe which extends the standard DatePipe in order to provide that functionality.]]></description><link>https://adenearnshaw.com/angular-timepipe/</link><guid isPermaLink="false">5f175d8aadd0ae0db6dcd4e3</guid><category><![CDATA[Angular]]></category><category><![CDATA[Web]]></category><dc:creator><![CDATA[Aden Earnshaw]]></dc:creator><pubDate>Wed, 25 Jul 2018 19:50:00 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1533749047139-189de3cf06d3?ixlib=rb-0.3.5&amp;q=80&amp;fm=jpg&amp;crop=entropy&amp;cs=tinysrgb&amp;w=1080&amp;fit=max&amp;ixid=eyJhcHBfaWQiOjExNzczfQ&amp;s=87fc17230df396d97f9d72e5a5ee389d" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="https://images.unsplash.com/photo-1533749047139-189de3cf06d3?ixlib=rb-0.3.5&amp;q=80&amp;fm=jpg&amp;crop=entropy&amp;cs=tinysrgb&amp;w=1080&amp;fit=max&amp;ixid=eyJhcHBfaWQiOjExNzczfQ&amp;s=87fc17230df396d97f9d72e5a5ee389d" alt="Building a TimePipe in Angular"><p>Angular&apos;s DatePipe does a great job of formatting Date strings or objects into specified formats, however, if you want to pass in a time string like &quot;09:00&quot; you&apos;re out of luck.</p>
<p>The easiest way to over come this is to extend the DatePipe with some additional logic which can handle time strings and feed these into the base method. This allows you to use the standard formatting notation of Angular without having to do much.</p>
<p>Here is the code:</p>
<pre><code class="language-typescript">import { Pipe, PipeTransform } from &apos;@angular/core&apos;;
import { DatePipe } from &apos;@angular/common&apos;;

@Pipe({
    name: &apos;time&apos;
})
export class TimePipe extends DatePipe implements PipeTransform {
    public transform(value: any, format: string): string {
        const dateTime: Date = new Date(value);

        let dateTimeString: string;
        if (this.isValidDate(dateTime)) {
            dateTimeString = dateTime.toString();
        } else {
            dateTimeString = `1970-01-01 ${value}`;
        }

        dateTimeString = dateTimeString.replace(/-/g, &apos;/&apos;);

        if (!this.isValidDate(new Date(dateTimeString))) {
            return value;
        }

        const formattedTime: string = super.transform(dateTimeString, format);

        return formattedTime;
    }

    private isValidDate(d: any): boolean {
        return d instanceof Date &amp;amp;&amp;amp; !isNaN(d.getTime());
    }
}
</code></pre>
<p>Here you can see that we override the <strong>transform()</strong> method and in it, immediately try and parse the inputted value. We then check if this is a valid Date, if it is not, then we assume that a time string has been passed in and concatenate this with a date value. Once we have a valid date, then we use the DatePipe&apos;s transform method and allow Angular to do the rest.</p>
<p>You can find the file &amp; some tests here: <a href="https://github.com/adenearnshaw/ng-timepipe">github.com/adenearnshaw/ng-timepipe</a></p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Power up your Terminal]]></title><description><![CDATA[Get all the goodness of PoshGit from within your Terminal along with a few other helpful features]]></description><link>https://adenearnshaw.com/power-up-your-terminal/</link><guid isPermaLink="false">5f175d8aadd0ae0db6dcd4e2</guid><category><![CDATA[MacOS]]></category><dc:creator><![CDATA[Aden Earnshaw]]></dc:creator><pubDate>Sun, 10 Jun 2018 06:04:00 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p>Having recently migrated from a PC to a Mac, I&apos;ve been missing some home comforts from Powershell. One of my favourite things was <a href="https://github.com/dahlbyk/posh-git">PostGit</a>, which provides in-line Git information relating to your current folder.</p>
<p>Since moving to Terminal on the Mac, I found my productivity had dropped significantly as little issues got in my way.</p>
<p>Here are a few code snippets I&apos;ve found which help improve Terminal&apos;s usability.</p>
<h2 id="setautocompletetobecaseinsensitive">Set Auto-complete to be case insensitive</h2>
<pre><code class="language-shell">echo &quot;set completion-ignore-case On&quot; &amp;gt;&amp;gt; ~/.inputrc
</code></pre>
<p>By default, tab completion is case-sensitive, so this snippet adds a property to the .inputrc file (and creates the file too) to ignore case. To revert. just modify the file in your <a href="https://code.visualstudio.com/">favourite code editor</a> and remove the line.</p>
<h2 id="installhomebrew">Install <a href="https://brew.sh/">Homebrew</a></h2>
<p>Akin to Chocolatey in Windows, Homebrew is a command-line utility that allows you to install additional tools and packages from a remote repository.</p>
<p>To install, paste the following code into terminal and hit enter:</p>
<pre><code>/usr/bin/ruby -e &quot;$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)&quot;
</code></pre>
<h2 id="installgitcompletion">Install <a href="https://github.com/bobthecow/git-flow-completion/wiki/Install-Bash-git-completion">git-completion</a></h2>
<p>As the heading suggests, this package provides auto-completion for Git commands, and just makes writing commands that bit quicker</p>
<p><a href="https://github.com/bobthecow/git-flow-completion/wiki/Install-Bash-git-completion">https://github.com/bobthecow/git-flow-completion/wiki/Install-Bash-git-completion</a></p>
<h2 id="installposhgitbash">Install <a href="https://github.com/lyze/posh-git-sh">posh-git-bash</a></h2>
<p>Posh-Git for bash is core to my Terminal experience. I&apos;m not a massive fan of UI based clients such as <a href="https://www.sourcetreeapp.com/">SourceTree</a> or <a href="https://www.gitkraken.com/">GitKraken</a>.</p>
<p>What this provides is a colour-coded in-line summary of the git status of the current directory, including which branch is checked out and whether you&apos;re up-to-date with your remote.</p>
<p>Follow the <a href="https://github.com/lyze/posh-git-sh">readme</a> and install</p>
<hr>
<p>Once you&apos;ve installed these things, your <strong>.bash_profile</strong> &amp; <strong>.bashrc</strong> files should look similar to the samples below. You may not be able to be able to see the files in Finder, so use the <code>code</code> command in Terminal to open them in VS Code, or turn on <strong>ShowAllFiles</strong> and double-click them once they appear in finder (See below on how to launch VS Code and show hidden files).</p>
<h4 id="bash_profile">.bash_profile</h4>
<p>Your <strong>.bash_profile</strong> file should include sections for <strong>bash completion</strong> and referencing the <strong>.bashrc</strong>:</p>
<pre><code>if [ -f $(brew --prefix)/etc/bash_completion ]; then
  . $(brew --prefix)/etc/bash_completion
fi

source ~/.bashrc  
</code></pre>
<h4 id="bashrc">.bashrc</h4>
<p>Your <strong>.bashrc</strong> file should include these lines:</p>
<pre><code>source ~/git-prompt.sh

PROMPT_COMMAND=&apos;__posh_git_ps1 &quot;\u@\h:\w &quot; &quot;\\\$ &quot;;&apos;$PROMPT_COMMAND
</code></pre>
<hr>
<h2 id="turnoncodecommandtolaunchvscode">Turn on &apos;code&apos; command to launch VS Code</h2>
<p>In VS Code hit: <strong>CMD</strong> + <strong>SHFT</strong> + <strong>P</strong> then type the following (auto-complete should help):</p>
<pre><code>Shell Command: Install &apos;code&apos; command in PATH
</code></pre>
<p>Once enabled, you can open a file by typing:</p>
<pre><code class="language-shell">code ~/.bashrc
</code></pre>
<p>or if you want to open the folder at your current location you can use:</p>
<pre><code class="language-shell">code .
</code></pre>
<hr>
<h2 id="showhiddenfiles">Show hidden files</h2>
<p>Something that&apos;s related more to Finder than Terminal, but is a bit obscure to find is how to show hidden files.</p>
<p>This can be toggled on or off in the finder using <strong>Shift+Cmd+.</strong></p>
<p>Or for something a bit more permanent here&apos;s the command to turn them on:</p>
<pre><code class="language-shell">defaults write com.apple.finder AppleShowAllFiles YES
</code></pre>
<hr>
<h2 id="maketabcyclethroughoptions">Make &apos;tab&apos; cycle through options</h2>
<p>When pressing tab, the default behaviour is to auto-complete if the terminal can only find one option that matches the current input, or display all options if more than one match is found. However, in Powershell, you can cycle through the various options until you find the one you want. To achieve this in Terminal open your ~/.bashrc file in <strong>VS Code</strong> and enter the following:</p>
<pre><code class="language-shell">bind &apos;&quot;\t&quot;:menu-complete&apos;
</code></pre>
<p>Hit save and reload your terminal. You should now be able to cycle through items using tab.</p>
<hr>
<h3 id="update25072018">Update (25/07/2018)</h3>
<p>After seeing this post, an old colleague of mine pointed me in the direction of iTerm2 and Oh-My-Zsh, and after using it for a while I must admit that I&apos;m a convert.</p>
<p>Using <a href="https://gist.github.com/kevin-smets/8568070">this gist</a> I was able to setup the terminal and VSCode &amp; have been using the combo ever since.</p>
<p>Many thanks to <a href="https://twitter.com/atkinchris">@AtkinChris</a> for pointing me in the right direction</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Welcome to my new blog]]></title><description><![CDATA[Life's getting on a bit, so I thought I'd better fire up the ol' blog again.]]></description><link>https://adenearnshaw.com/welcome-to-my-new-blog/</link><guid isPermaLink="false">5f175d8aadd0ae0db6dcd4e1</guid><category><![CDATA[General]]></category><dc:creator><![CDATA[Aden Earnshaw]]></dc:creator><pubDate>Tue, 08 May 2018 06:53:00 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p>So many moons ago, I set up a little old Wordpress site which lived at saintchubs.com. Although my intentions were good, the number of items I posted were few and far between.</p>
<p>As with most blogs, the majority of the posts were more for my benefit than others, with little snippets and links to other peoples blogs. Writing these were useful to help the knowledge sink in, but in most cases I never referred back to them, and never saw many people directed to them from Google.</p>
<p>For a while I didn&apos;t like writing too many articles, as Imposter Syndrome gripped me, thinking that anything I wrote would be second hand news, and not worth a reader&apos;s time. Now, I&apos;m a little older, a little wiser and have a bit more experience under my belt, so I&apos;ve decided to start again. I&apos;ve got myself a new twitter/github/linkedin handle and a new domain and it&apos;s time to write some original content.</p>
<p>I&apos;m going to set myself a target of writing two or three articles a month. This doesn&apos;t sound like much, but baring in mind my previous cadence averaged about 1.5 per year, this should be plenty for now.</p>
<p>Thanks very much for visiting my new site, and I hope that it helps you.</p>
<p>Aden</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Using a custom font in Xamarin Forms Entry Placeholder]]></title><description><![CDATA[By default, Xamarin Forms will assign an Entry's placeholder the same font as its text, however you may need to override it. Using custom renderers, we can override this to give you the desired effect.]]></description><link>https://adenearnshaw.com/xamarin-forms-custom-placeholder-font/</link><guid isPermaLink="false">5f175d8aadd0ae0db6dcd4e0</guid><category><![CDATA[Xamarin]]></category><category><![CDATA[Xamarin Forms]]></category><category><![CDATA[iOS]]></category><category><![CDATA[Android]]></category><dc:creator><![CDATA[Aden Earnshaw]]></dc:creator><pubDate>Mon, 26 Mar 2018 21:15:00 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p>After stumbling upon <a href="https://blog.verslu.is/xamarin/xamarin-forms-xamarin/custom-fonts-with-xamarin-forms-revisited/">this</a> article the other day, which revisits the topic of custom fonts, it reminded me of an issue I encountered a while ago; giving your Entry a different font for both the placeholder and the text.</p>
<p>By default, Xamarin Forms will assign an Entry&apos;s placeholder the same font as its text, using custom renderers, we can override this to add the desired functionality.</p>
<h3 id="addingcustomfontstoyourlibrary">Adding custom fonts to your library</h3>
<p>In order to use custom fonts within your Xamarin apps you first need to register them. Follow <strong>Gerald Versluis&apos; <a href="https://blog.verslu.is/xamarin/xamarin-forms-xamarin/custom-fonts-with-xamarin-forms-revisited/">blog post</a></strong> on how to import and register your custom font files on each platform.</p>
<h3 id="addextendedcontroltosharedlibrary">Add extended control to Shared library</h3>
<p>First, create a custom control in your shared code which extends from <strong>Entry</strong> and add an additional BindableProperty to store your placeholder font.</p>
<pre><code class="language-csharp">public class CustomPlaceholderEntry : Entry
{
    public static readonly BindableProperty PlaceholderFontFamilyProperty
            = BindableProperty.Create(nameof(PlaceholderFontFamily), 
                                      typeof(string), 
                                      typeof(CustomPlaceholderEntry), 
                                      default(string));

    public string PlaceholderFontFamily
    {
        get { return (string)GetValue(PlaceholderFontFamilyProperty); }
        set { SetValue(PlaceholderFontFamilyProperty, value); }
    }
}
</code></pre>
<p>You can extend this further if you want to include properties such as the placeholder&apos;s colour and size.</p>
<h3 id="ios">iOS</h3>
<ol>
<li>Create a custom renderer which inherits from <strong>EntryRenderer</strong>.</li>
<li>Add the following code to load your font into a new variable and assign it to an <strong>NSAttributedString</strong> which can be passed to the native control:</li>
</ol>
<pre><code class="language-csharp">private void UpdatePlaceholderFont()
{
    ...
		var descriptor = new UIFontDescriptor().CreateWithFamily(CustomElement.PlaceholderFontFamily);
    var placeholderFont = UIFont.FromDescriptor(descriptor, (float)CustomElement.FontSize);
    ...
    Control.AttributedPlaceholder = new NSAttributedString(CustomElement.Placeholder, placeholderFont);
}
</code></pre>
<ol start="3">
<li>Call <strong>UpdatePlaceholderFont()</strong> from the <strong>OnElementChanged</strong> &amp; <strong>OnElementPropertyChanged</strong></li>
<li>Register your custom renderer and providing you&apos;ve registered your fonts correctly and declared them in the <strong>Info.plist</strong>, you should be able to see a custom font set for the placeholder of your entry.</li>
</ol>
<h3 id="android">Android</h3>
<p>Implementing a custom placeholder font on Android is a little more complex than iOS, but still achievable. As with iOS, the native Android control also exposes a property that allows for a custom placeholder. in this case, it&apos;s <strong>Control.HintFormatted</strong>.</p>
<p>The <strong>Control.HintFormatted</strong> property can be assigned a <strong>TypefaceSpan</strong>, however, out of the box, this doesn&apos;t expose all the functionality we need. Therefore, first we have to create our own <strong>CustomTypefaceSpan</strong> which will allow us to set some additional properties.</p>
<pre><code class="language-csharp">public class CustomTypefaceSpan : TypefaceSpan
{
    private readonly Typeface _customTypeface;

    public CustomTypefaceSpan(Typeface type) : base(&quot;&quot;)
    {
        _customTypeface = type;
    }

    public CustomTypefaceSpan(string family, Typeface type) : base(family)
    {
       customTypeface = type;
    }

    public override void UpdateDrawState(TextPaint ds)
    {
        ApplyCustomTypeFace(ds, _customTypeface);
    }

    public override void UpdateMeasureState(TextPaint paint)
    {
        ApplyCustomTypeFace(paint, _customTypeface);
    }

    private static void ApplyCustomTypeFace(Paint paint, Typeface tf)
    {
        paint.SetTypeface(tf);
    }
}
</code></pre>
<p>Now we have our <strong>CustomTypefaceSpan</strong> we can create a new custom renderer.</p>
<ol>
<li>As with iOS, create a new custom renderer which extends from <strong>EntryRenderer</strong>.</li>
<li>Create an <strong>UpdatePlaceholderFont</strong> method as outlined below:</li>
</ol>
<pre><code class="language-csharp">private void UpdatePlaceholderFont()
{
    ...

    var placeholderFontSize = (int)CustomElement.FontSize;
    var placeholderSpan = new SpannableString(CustomElement.Placeholder);
						
    // Set Fontsize
    placeholderSpan.SetSpan(new AbsoluteSizeSpan(placeholderFontSize, true), 0, placeholderSpan.Length(), SpanTypes.InclusiveExclusive); 

    var typeFace = FindFont(CustomElement.PlaceholderFontFamily);
    var typeFaceSpan = new CustomTypefaceSpan(typeFace);
		
    //Set Fontface
    placeholderSpan.SetSpan(typeFaceSpan, 0, placeholderSpan.Length(), SpanTypes.InclusiveExclusive); 

    Control.HintFormatted = placeholderSpan;
}
</code></pre>
<ol start="3">
<li>Call <strong>UpdatePlaceholderFont()</strong> from the <strong>OnElementChanged</strong> &amp; <strong>OnElementPropertyChanged</strong></li>
</ol>
<p>There we have it, a very brief guide on how to change your Entry&apos;s placeholder font. If the code here is too sparse, you can find a full working demo on my GitHub (apologies in advance for the use of Comic Sans &#x1F605;).</p>
<p>Full demo source: <a href="https://github.com/adenearnshaw/XamCustomPlaceholderFont">github.com/adenearnshaw/XamCustomPlaceholderFont</a></p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Using a Grid ItemsPanel with a DataTemplateSelector]]></title><description><![CDATA[Trying to assign items in a list to columns and rows within an ItemsControl with a Grid can throw up some issues. Here we look into a couple of ways of solving the problems, including how to deal with setting an items position when a DataTemplateSelector is required.]]></description><link>https://adenearnshaw.com/using-a-grid-itemspanel-with-a-datatemplateselector/</link><guid isPermaLink="false">5f175d8aadd0ae0db6dcd4df</guid><category><![CDATA[Windows]]></category><category><![CDATA[UWP]]></category><dc:creator><![CDATA[Aden Earnshaw]]></dc:creator><pubDate>Mon, 07 Sep 2015 20:05:00 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p>The other week, I was working on an app with a requirement to show a collection of items in a grid formation spanning the entire view. First we looked at the feasibility of using an out of the box solution such as GridView, but this wasn&#x2019;t flexible enough for our requirements. I decided that a good approach would be to use an ItemsControl with a Grid used as the ItemsPanelTemplate.</p>
<p>In theory, this approach worked great, as the data we received came in the form of a multidimensional array, therefore we could directly map each item&apos;s column and row. As with all great plans, there was a floor, the Gird.Row/Column attached properties on the item&#x2019;s DataTemplate, didn&#x2019;t seem to work. After some quick investigation using XamlSpy I could see that each item&#x2019;s DataTemplate was being encapsulated in a ContentPresenter, preventing Grid.Row/Column from applying to the ItemPanel.</p>
<p>After a quick Google, I came across this <a href="http://garfoot.com/blog/2013/09/using-grids-with-itemscontrol-in-xaml/">post by Rob Garfoot</a>, who had a solution. It was exactly what I was after, so I implemented the custom <strong><a href="https://github.com/adenearnshaw/GridItemsPanelWithDataTemplate/blob/master/GridItemsPanelWithDataTemplate/GridItemsPanelWithDataTemplate.Shared/Controls/GridAwareItemsControl.cs">GridAwareItemsControl</a></strong> and added the attached properties and I was good to go.</p>
<p>As with all projects, a requirement was added afterwards to use a DataTemplateSelector to choose different templates, not anticipating any issues, I created a custom Selector and dropped it in my code. I was wrong, the view appeared completely wrong and was a mess. After another quick inspection in XamlSpy I found that now there was a second ContentPresenter being added to each Item. After a couple of hours of trying to refactor the GridAwareItemsControl provided by Rob, I stumbled across the solution.</p>
<p>The Grid&#x2019;s attached properties are accessible from the DataTemplateSelector. Therefore, you can set the Row/Column properties from here by passing in the container object and casting it to a FrameworkElement.</p>
<pre><code class="language-csharp">protected override DataTemplate SelectTemplateCore(object item, DependencyObject container)
{
    ...

    Grid.SetColumn(uiElement, listItem.GridColumn);
    Grid.SetRow(uiElement, listItem.GridRow);
    Grid.SetColumnSpan(uiElement, listItem.GridColumnSpan);
    Grid.SetRowSpan(uiElement, listItem.GridRowSpan);

    ...

    return base.SelectTemplateCore(item, container);
}
</code></pre>
<p>If you want to see it in action, you can grab a demo <a href="https://github.com/adenearnshaw/GridItemsPanelWithDataTemplate">here</a>.</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Replicating TargetNullValue in Windows8]]></title><description><![CDATA[There are times in this world when using binding statements, that you want to specify a default value for a property if the result provided is null.]]></description><link>https://adenearnshaw.com/replicating-targetnullvalue-in-windows8/</link><guid isPermaLink="false">5f175d8aadd0ae0db6dcd4de</guid><category><![CDATA[Windows]]></category><category><![CDATA[UWP]]></category><dc:creator><![CDATA[Aden Earnshaw]]></dc:creator><pubDate>Sat, 28 Jul 2012 16:39:00 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p>There are times in this world when using binding statements, that you want to specify a default value for a property if the result provided is null. In a post found <a href="http://jesseliberty.com/2011/12/29/binding-formatting/">here</a> by Jesse Liberty, he details how developers can utilize the TargetNullValue option within the xaml binding statement to provide this option.</p>
<p>Recently I&apos;ve been porting my SaintsFC WP7 app over to Windows 8 metro app &amp; I&apos;ve found that this option is no longer available. It&apos;s been confirmed that this will likely not be in the RTM version of Windows 8 either so here&apos;s a workaround using a converter as a substitute. It&apos;s a little more convoluted than a simple property within the binding but it will also be able to provide you with a more extensive feature set as a result.</p>
<p>So for wp7 my binding statement may have looked something like this:</p>
<pre><code class="language-xml">&lt;TextBlock Text={Binding Path=&apos;Salutation&apos;, TargetNullValue=&apos;Hello Sir&apos;} /&gt;
</code></pre>
<p>However for Windows 8 it looks a little something like this:</p>
<pre><code class="language-xml">&lt;TextBlock Text={Binding Path=&apos;Salutation&apos;, Converter={StaticResource TargetNullValueConverter}, ConverterParameter=&apos;DefaultSalutation1&apos;} /&gt;
</code></pre>
<p>Not quite at neat as the SL/WP7 implementation, but it does have a few benefits:</p>
<ul>
<li>You can change the parameter to provide a different results</li>
<li>You can perform more complex actions.</li>
</ul>
<h4 id="howtoimplement">How to implement:</h4>
<ol>
<li>Create a blank application, and add a folder called <strong>Converters</strong></li>
<li>In Converters folder, create a new Class called <strong>TargetNullValueConverter.cs</strong></li>
<li>Then make the class public and implement the <strong>IValueConverter</strong> interface.</li>
<li>From here we&apos;ll add the logic which will provide the basis of the TargetNullValue replacement. In the <strong>Convert()</strong> method enter the following code:</li>
</ol>
<pre><code class="language-csharp">if (value != null) 
    return value; 
else 
{
    string returnValue = String.Empty; 
    switch ((string)parameter) 
    { 
        case &quot;SelectedImage&quot;: 
            returnValue = &quot;/Assets/SplashScreen.png&quot;; 
            break; 
        default: 
            returnValue =&quot;/Assets/SplashScreen.png&quot;; 
            break; 
    } 
    return returnValue;
} 
</code></pre>
<p>Firstly the code checks to see if theres a value, if there is, then theres no heavy lifting involved and the converter can just return the original value. However, if the value is null the bulk of the logic kicks in. I find that adding a Switch statement is the easiest way of handling the return value as it means you can write the converter just once and for every circumstance where you need a different value to be returned, you just write a new case.</p>
<h4 id="demo">Demo</h4>
<p>To demonstrate this method I&apos;ll talk through a quick demo. First, add a ImageItem class and implement <em>INotifyPropertyChanged</em> then add a property of type <em>ImageSource</em> named <em>SelectedImage</em>.</p>
<p>Next we&apos;ll go to the MainPage.xaml and create our interface. Add the following declaration:</p>
<pre><code class="language-xml">xmlns:converters=&quot;using:TargetNullConverter.Converters&quot;
</code></pre>
<p>Set the data context to the ImageItem that you created a minute ago</p>
<pre><code class="language-xml">&lt;Page.DataContext&gt;
    &lt;local:ImageItem /&gt;
&lt;/Page.DataContext&gt;
</code></pre>
<p>Then add the converter to the Page Resources</p>
<pre><code class="language-xml">&lt;Page.Resources&gt;
    &lt;converters:TargetNullValueConverter x:Key=&quot;TargetNullValueConverter&quot;/&gt;
&lt;/Page.Resources&gt;
</code></pre>
<p>Add the following markup to the main grid:</p>
<pre><code class="language-xml">&lt;Grid.RowDefinitions&gt; 
    &lt;RowDefinition Height=&quot;Auto&quot; /&gt; 
    &lt;RowDefinition Height=&quot;*&quot; /&gt;
&lt;/Grid.RowDefinitions&gt;
&lt;StackPanel Orientation=&quot;Horizontal&quot; 
                 HorizontalAlignment=&quot;Left&quot; 
                 VerticalAlignment=&quot;Top&quot; 
                 Margin=&quot;40,40,0,0&quot; &gt;
    &lt;Button Content=&quot;Customize Picture&quot; 
            Click=&quot;GetPicture&quot; /&gt;
    &lt;Button Content=&quot;Reset resource to null&quot; 
            Click=&quot;ResetPicture&quot; /&gt;
&lt;/StackPanel&gt; 

&lt;Image Grid.Row=&quot;1&quot; 
       HorizontalAlignment=&quot;Stretch&quot; 
       Height=&quot;550&quot; 
       Stretch=&quot;Uniform&quot; 
       Source=&quot;{Binding SelectedImage, Converter={StaticResource TargetNullValueConverter}, ConverterParameter=SelectedImage}&quot; /&gt;
</code></pre>
<p>That&#x2019;s the Markup done, now go to the code behind.<br>
In the constructor, cast the DataContext to a static instance of the ImageItem object</p>
<pre><code class="language-csharp">imageItem = this.DataContext as ImageItem;
</code></pre>
<p>Then create an asynchronous method called which utilises the FileOpenPicker class to get an image and save it to an object with a property of ImageSource then hook up GetPicture() to call it.</p>
<pre><code class="language-csharp">FileOpenPicker openPicker = new FileOpenPicker(); 
openPicker.ViewMode = PickerViewMode.Thumbnail; 
openPicker.SuggestedStartLocation = PickerLocationId.PicturesLibrary; 
openPicker.FileTypeFilter.Add(&quot;.jpg&quot;); 
openPicker.FileTypeFilter.Add(&quot;.jpeg&quot;);
openPicker.FileTypeFilter.Add(&quot;.png&quot;); 
StorageFile file = await openPicker.PickSingleFileAsync(); 

if (file != null) 
{ 
    var stream = await file.OpenAsync(FileAccessMode.Read); 
    BitmapImage img = new BitmapImage(); 
    img.SetSource(stream); 
    imageItem.SelectedImage = img; 
}
</code></pre>
<p>For ResetPicture() just set the object&apos;s <strong>SelectedImage</strong> property to null</p>
<pre><code class="language-csharp">imageItem.SelectedImage = null;
</code></pre>
<p>And that&apos;s it, all that&apos;s left is to build &amp; run the code and you&apos;ll be able to see this in action.</p>
<!--kg-card-end: markdown-->]]></content:encoded></item></channel></rss>