<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://sirjohnk.com/feed.xml" rel="self" type="application/atom+xml" /><link href="https://sirjohnk.com/" rel="alternate" type="text/html" /><updated>2026-02-22T00:07:33+01:00</updated><id>https://sirjohnk.com/feed.xml</id><title type="html">SirJohnK’s Blog</title><subtitle>The blog of Johan Svensson, aka SirJohnK, mostly about software development in C# with focus on cross platform development with .NET MAUI.</subtitle><author><name>Johan Svensson</name></author><entry><title type="html">MAUI Lib - ZebraScannerSDK.Maui!</title><link href="https://sirjohnk.com/coding/MAUI-Lib-2/" rel="alternate" type="text/html" title="MAUI Lib - ZebraScannerSDK.Maui!" /><published>2026-02-17T00:00:00+01:00</published><updated>2026-02-17T00:00:00+01:00</updated><id>https://sirjohnk.com/coding/MAUI-Lib-2</id><content type="html" xml:base="https://sirjohnk.com/coding/MAUI-Lib-2/"><![CDATA[<p><strong>Using Zebra Scanners with non Zebra devices on Android or iOS?</strong></p>

<p><em>Then maybe this enhanced .NET MAUI version of the Zebra Scanner SDK for Xamarin/MAUI is for you!</em></p>

<h2 id="background">Background</h2>
<p>A couple of years ago, when upgrading a <a href="https://dotnet.microsoft.com/en-us/apps/xamarin">Xamarin</a> application to <a href="https://dotnet.microsoft.com/en-us/apps/maui">.NET MAUI</a>, the Zebra <a href="https://www.zebra.com/us/en/support-downloads/software/scanner-software/xamarin-wrapper-for-scanner-sdk-for-android-and-ios.html">Scanner Xamarin Wrapper (Android and iOS)</a> was not yet migrated to <a href="https://dotnet.microsoft.com/en-us/apps/maui">.NET MAUI</a>, so this library was created. Zebra have since then released the <a href="https://www.zebra.com/us/en/support-downloads/software/scanner-software/net-maui-wrapper.html">.NET MAUI Wrapper for Scanner SDK (iOS and Android)</a> package. That package is not distributed as a common NuGet package and is not updated in the same pace as the native Android/iOS libraries, therefore this library is still maintained as a convenient complement.</p>

<h2 id="library">Library</h2>
<p>The library is available both as a <a href="https://www.nuget.org/packages/ZebraScannerSDK.Maui">NuGet package</a> and a <a href="https://github.com/SirJohnK/ZebraScannerSDK.Maui">MIT licensed repository at GitHub</a>.</p>

<table>
  <thead>
    <tr>
      <th>Name</th>
      <th style="text-align: center">Nuget</th>
      <th style="text-align: center">GitHub</th>
      <th style="text-align: center">Support</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>ZebraScannerSDK.Maui</td>
      <td style="text-align: center"><a href="https://www.nuget.org/packages/ZebraScannerSDK.Maui/"><img src="https://img.shields.io/nuget/v/ZebraScannerSDK.Maui" alt="NuGet" /></a></td>
      <td style="text-align: center"><a href="https://github.com/SirJohnK/ZebraScannerSDK.Maui"><img src="https://img.shields.io/github/v/release/sirjohnk/ZebraScannerSDK.Maui" alt="GitHub Release Date" /></a></td>
      <td style="text-align: center"><a href="https://www.buymeacoffee.com/sirjohnk" target="_blank"><img src="https://www.buymeacoffee.com/assets/img/custom_images/orange_img.png" alt="Buy Me A Coffee" align="right" style="height: 37px !important;width: 170px !important;" /></a></td>
    </tr>
  </tbody>
</table>

<h2 id="whats-included">What’s included?</h2>
<p>Compared to the original solution we have some enhanced and added features:</p>
<ul>
  <li>One easy to use NuGet package.</li>
  <li>Easy setup with service collection extension.</li>
  <li>
    <p>New <code class="language-plaintext highlighter-rouge">IScannerSDK</code> interface registered for constructor injection with DI.</p>
  </li>
  <li>New sample app.</li>
</ul>

<h2 id="setup">Setup</h2>
<p>Use the <code class="language-plaintext highlighter-rouge">AddZebraScannerSDK</code> service collection extension method for library configuration.</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">var</span> <span class="n">builder</span> <span class="p">=</span> <span class="n">MauiApp</span><span class="p">.</span><span class="nf">CreateBuilder</span><span class="p">();</span>
<span class="n">builder</span>
    <span class="p">.</span><span class="n">UseMauiApp</span><span class="p">&lt;</span><span class="n">App</span><span class="p">&gt;()</span>
    <span class="p">.</span><span class="nf">ConfigureFonts</span><span class="p">(</span><span class="n">fonts</span> <span class="p">=&gt;</span>
    <span class="p">{</span>
        <span class="n">fonts</span><span class="p">.</span><span class="nf">AddFont</span><span class="p">(</span><span class="s">"OpenSans-Regular.ttf"</span><span class="p">,</span> <span class="s">"OpenSansRegular"</span><span class="p">);</span>
        <span class="n">fonts</span><span class="p">.</span><span class="nf">AddFont</span><span class="p">(</span><span class="s">"OpenSans-Semibold.ttf"</span><span class="p">,</span> <span class="s">"OpenSansSemibold"</span><span class="p">);</span>
    <span class="p">})</span>

    <span class="c1">//Add Services</span>
    <span class="n">builder</span><span class="p">.</span><span class="n">Services</span><span class="p">.</span><span class="nf">AddZebraScannerSDK</span><span class="p">();</span>
</code></pre></div></div>
<p>For further documentation, see the <a href="#official-zebra-resources">Official Zebra Resources</a> or the <a href="#sample">Sample application</a>.</p>

<h2 id="sample">Sample</h2>
<p>Look at the <a href="https://github.com/SirJohnK/ZebraScannerSDK.Maui/tree/main/ZebraScannerSDK.Maui.Sample">Sample project</a> for a example of how to use this library in an .NET MAUI application.</p>

<p><a href="https://github.com/SirJohnK/ZebraScannerSDK.Maui/tree/main/ZebraScannerSDK.Maui.Sample"><img src="/assets/images/MainView.png" alt="Main View" /></a>
<a href="https://github.com/SirJohnK/ZebraScannerSDK.Maui/tree/main/ZebraScannerSDK.Maui.Sample"><img src="/assets/images/PairingView.png" alt="Pairing View" /></a></p>

<h2 id="official-zebra-resources">Official Zebra Resources</h2>
<ul>
  <li><a href="https://www.zebra.com/us/en/support-downloads/software/scanner-software/net-maui-wrapper.html">.NET MAUI Wrapper for Scanner SDK (iOS and Android)</a></li>
  <li><a href="https://www.zebra.com/us/en/support-downloads/software/scanner-software/scanner-sdk-for-android.html">Scanner SDK for Android</a></li>
  <li><a href="https://www.zebra.com/us/en/support-downloads/software/scanner-software/scanner-sdk-for-iOS.html">Scanner SDK for iOS</a></li>
  <li><a href="https://www.zebra.com/us/en/support-downloads/software/scanner-software/xamarin-wrapper-for-scanner-sdk-for-android-and-ios.html">Scanner Xamarin Wrapper (Android and iOS)</a> (Deprecated and no longer maintained)</li>
</ul>]]></content><author><name>Johan Svensson</name></author><category term="Coding" /><category term=".NET" /><category term="MAUI" /><category term="Zebra Scanner SDK" /><category term="Bluetooth" /><summary type="html"><![CDATA[Using Zebra Scanners with non Zebra devices on Android or iOS? Then maybe this enhanced .NET MAUI version of the Zebra Scanner SDK for Xamarin/MAUI is for you! Background A couple of years ago, when upgrading a Xamarin application to .NET MAUI, the Zebra Scanner Xamarin Wrapper (Android and iOS) was not yet migrated to .NET MAUI, so this library was created. Zebra have since then released the .NET MAUI Wrapper for Scanner SDK (iOS and Android) package. That package is not distributed as a common NuGet package and is not updated in the same pace as the native Android/iOS libraries, therefore this library is still maintained as a convenient complement. Library The library is available both as a NuGet package and a MIT licensed repository at GitHub. Name Nuget GitHub Support ZebraScannerSDK.Maui What’s included? Compared to the original solution we have some enhanced and added features: One easy to use NuGet package. Easy setup with service collection extension. New IScannerSDK interface registered for constructor injection with DI. New sample app. Setup Use the AddZebraScannerSDK service collection extension method for library configuration. var builder = MauiApp.CreateBuilder(); builder .UseMauiApp&lt;App&gt;() .ConfigureFonts(fonts =&gt; { fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular"); fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold"); }) //Add Services builder.Services.AddZebraScannerSDK(); For further documentation, see the Official Zebra Resources or the Sample application. Sample Look at the Sample project for a example of how to use this library in an .NET MAUI application. Official Zebra Resources .NET MAUI Wrapper for Scanner SDK (iOS and Android) Scanner SDK for Android Scanner SDK for iOS Scanner Xamarin Wrapper (Android and iOS) (Deprecated and no longer maintained)]]></summary></entry><entry><title type="html">MAUI Snack - Get ANY Resource Dictionary Value in Code Behind!</title><link href="https://sirjohnk.com/coding/MAUI-Snack-2/" rel="alternate" type="text/html" title="MAUI Snack - Get ANY Resource Dictionary Value in Code Behind!" /><published>2023-01-27T00:00:00+01:00</published><updated>2023-01-27T00:00:00+01:00</updated><id>https://sirjohnk.com/coding/MAUI-Snack-2</id><content type="html" xml:base="https://sirjohnk.com/coding/MAUI-Snack-2/"><![CDATA[<p><a href="https://learn.microsoft.com/en-us/dotnet/maui/fundamentals/resource-dictionaries">Resource Dictionaries</a> enables us to create reusable resources in our XAML files or in code behind! To resolve and access <code class="language-plaintext highlighter-rouge">Resource Dictionary Resources</code> in code behind, we can access it, in some cases, by using the Resource <code class="language-plaintext highlighter-rouge">Key</code> index name in the <code class="language-plaintext highlighter-rouge">Resource Dictionary</code>:</p>
<div class="language-c# highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">var</span> <span class="n">cornerRadius</span> <span class="p">=</span> <span class="n">Application</span><span class="p">.</span><span class="n">Current</span><span class="p">?.</span><span class="n">Resources</span><span class="p">[</span><span class="s">"DefaultCornerRadius"</span><span class="p">]</span> <span class="k">as</span> <span class="n">CornerRadius</span><span class="p">;</span>
</code></pre></div></div>
<p>…or with <code class="language-plaintext highlighter-rouge">TryGetValue</code>…</p>
<div class="language-c# highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">if</span> <span class="p">(</span><span class="n">Application</span><span class="p">.</span><span class="n">Current</span><span class="p">?.</span><span class="n">Resources</span><span class="p">.</span><span class="nf">TryGetValue</span><span class="p">(</span><span class="s">"DefaultCornerRadius"</span><span class="p">,</span> <span class="k">out</span> <span class="kt">var</span> <span class="n">resource</span><span class="p">)</span> <span class="p">??</span> <span class="k">false</span><span class="p">)</span>
<span class="p">{</span>
  <span class="kt">var</span> <span class="n">cornerRadius</span> <span class="p">=</span> <span class="n">resource</span> <span class="k">as</span> <span class="n">CornerRadius</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>
<p><strong>BUT</strong> when we need to access a <code class="language-plaintext highlighter-rouge">Resource</code> that is defined with <code class="language-plaintext highlighter-rouge">OnPlatform</code>, <code class="language-plaintext highlighter-rouge">OnIdiom</code> and/or references a <code class="language-plaintext highlighter-rouge">DynamicResource</code> in a <code class="language-plaintext highlighter-rouge">Merged Dictionary</code>, it gets trickier! Especially if this is nested in multiple layers!</p>

<p><em>Let’s look at an extreme example!</em></p>

<p>First we have the main <code class="language-plaintext highlighter-rouge">Application Resource Dictionary</code> with the <code class="language-plaintext highlighter-rouge">DefaultCornerRadius</code>resource. Based <code class="language-plaintext highlighter-rouge">OnPlatform</code> the value references a specific <code class="language-plaintext highlighter-rouge">DynamicResource</code>.</p>
<div class="language-c# highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">&lt;</span><span class="n">Application</span><span class="p">.</span><span class="n">Resources</span><span class="p">&gt;</span>
    <span class="p">&lt;</span><span class="n">ResourceDictionary</span><span class="p">&gt;</span>
        <span class="p">&lt;</span><span class="n">OnPlatform</span> <span class="n">x</span><span class="p">:</span><span class="n">Key</span><span class="p">=</span><span class="s">"DefaultCornerRadius"</span> <span class="n">x</span><span class="p">:</span><span class="n">TypeArguments</span><span class="p">=</span><span class="s">"CornerRadius"</span><span class="p">&gt;</span>
            <span class="p">&lt;</span><span class="n">On</span> <span class="n">Platform</span><span class="p">=</span><span class="s">"Android"</span> <span class="n">Value</span><span class="p">=</span><span class="s">"{DynamicResource SmallCornerRadius}"</span><span class="p">/&gt;</span>
            <span class="p">&lt;</span><span class="n">On</span> <span class="n">Platform</span><span class="p">=</span><span class="s">"iOS"</span>  <span class="n">Value</span><span class="p">=</span><span class="s">"{DynamicResource MediumCornerRadius}/&gt;
</span>        <span class="p">&lt;/</span><span class="n">OnPlatform</span><span class="p">&gt;</span>
    <span class="p">&lt;/</span><span class="n">ResourceDictionary</span><span class="p">&gt;</span>
<span class="p">&lt;/</span><span class="n">Application</span><span class="p">.</span><span class="n">Resources</span><span class="p">&gt;</span>
</code></pre></div></div>
<p>At runtime, the <code class="language-plaintext highlighter-rouge">DefaultStyle</code> Resource Dictionary is added, based on screen resolution, as a <code class="language-plaintext highlighter-rouge">Merged Dictionary</code> with the values for <code class="language-plaintext highlighter-rouge">CornerRadius</code>.</p>
<div class="language-c# highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">Resources</span><span class="p">.</span><span class="n">MergedDictionaries</span><span class="p">.</span><span class="nf">Add</span><span class="p">(</span><span class="k">new</span> <span class="nf">DefaultStyle</span><span class="p">());</span>
</code></pre></div></div>
<p>In <code class="language-plaintext highlighter-rouge">DefaultStyle</code> dictionary, both <code class="language-plaintext highlighter-rouge">SmallCornerRadius</code> and <code class="language-plaintext highlighter-rouge">MediumCornerRadius</code> is defined based on Idiom!</p>
<div class="language-c# highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">&lt;</span><span class="n">ResourceDictionary</span>
    <span class="n">x</span><span class="p">:</span><span class="n">Class</span><span class="p">=</span><span class="s">"RetailOperationApp.Resources.Styles.DefaultStyle"</span>
    <span class="n">xmlns</span><span class="p">=</span><span class="s">"http://schemas.microsoft.com/dotnet/2021/maui"</span>
    <span class="n">xmlns</span><span class="p">:</span><span class="n">x</span><span class="p">=</span><span class="s">"http://schemas.microsoft.com/winfx/2009/xaml"</span><span class="p">&gt;</span>

    <span class="p">&lt;</span><span class="n">OnIdiom</span>
        <span class="n">x</span><span class="p">:</span><span class="n">Key</span><span class="p">=</span><span class="s">"SmallCornerRadius"</span>
        <span class="n">x</span><span class="p">:</span><span class="n">TypeArguments</span><span class="p">=</span><span class="s">"CornerRadius"</span>
        <span class="n">Default</span><span class="p">=</span><span class="s">"10"</span>
        <span class="n">Desktop</span><span class="p">=</span><span class="s">"11"</span>
        <span class="n">Phone</span><span class="p">=</span><span class="s">"12"</span>
        <span class="n">TV</span><span class="p">=</span><span class="s">"13"</span>
        <span class="n">Tablet</span><span class="p">=</span><span class="s">"14"</span>
        <span class="n">Watch</span><span class="p">=</span><span class="s">"15"</span> <span class="p">/&gt;</span>

    <span class="p">&lt;</span><span class="n">OnIdiom</span>
        <span class="n">x</span><span class="p">:</span><span class="n">Key</span><span class="p">=</span><span class="s">"MediumCornerRadius"</span>
        <span class="n">x</span><span class="p">:</span><span class="n">TypeArguments</span><span class="p">=</span><span class="s">"CornerRadius"</span>
        <span class="n">Default</span><span class="p">=</span><span class="s">"20"</span>
        <span class="n">Desktop</span><span class="p">=</span><span class="s">"21"</span>
        <span class="n">Phone</span><span class="p">=</span><span class="s">"22"</span>
        <span class="n">TV</span><span class="p">=</span><span class="s">"23"</span>
        <span class="n">Tablet</span><span class="p">=</span><span class="s">"24"</span>
        <span class="n">Watch</span><span class="p">=</span><span class="s">"25"</span> <span class="p">/&gt;</span>
        
<span class="p">&lt;/</span><span class="n">ResourceDictionary</span><span class="p">&gt;</span>
</code></pre></div></div>
<p>In this case and as far as I know, to resolve the correct CornerRadius for <code class="language-plaintext highlighter-rouge">DefaultCornerRadius</code> requires first resolving the correct <code class="language-plaintext highlighter-rouge">OnPlatform</code>, then finding the <code class="language-plaintext highlighter-rouge">DynamicResource</code> and finally resolve the correct <code class="language-plaintext highlighter-rouge">OnIdom</code>…which makes it tricky to have a easy way of resolving ANY resource!</p>

<p><strong>BUT</strong>, what if we could resolve ANY resource like this:</p>
<div class="language-c# highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">var</span> <span class="n">cornerRadius</span> <span class="p">=</span> <span class="n">ResourcesUtility</span><span class="p">.</span><span class="n">FindResource</span><span class="p">&lt;</span><span class="n">CornerRadius</span><span class="p">&gt;(</span><span class="s">"DefaultCornerRadius"</span><span class="p">);</span>
</code></pre></div></div>
<p>…or…</p>
<div class="language-c# highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">var</span> <span class="n">cornerRadius</span> <span class="p">=</span> <span class="n">Application</span><span class="p">.</span><span class="n">Current</span><span class="p">?.</span><span class="n">Resources</span><span class="p">.</span><span class="n">FindResource</span><span class="p">&lt;</span><span class="n">CornerRadius</span><span class="p">&gt;(</span><span class="s">"DefaultCornerRadius"</span><span class="p">);</span>
</code></pre></div></div>
<p>To solve this, I have made the following static class that enables just that!</p>
<div class="language-c# highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">static</span> <span class="k">class</span> <span class="nc">ResourcesUtility</span>
<span class="p">{</span>
    <span class="k">private</span> <span class="k">static</span> <span class="n">T</span><span class="p">?</span> <span class="n">GetResource</span><span class="p">&lt;</span><span class="n">T</span><span class="p">&gt;(</span><span class="n">ResourceDictionary</span> <span class="n">resources</span><span class="p">,</span> <span class="kt">object</span><span class="p">?</span> <span class="n">resource</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="c1">//Check resource type</span>
        <span class="k">switch</span> <span class="p">(</span><span class="n">resource</span><span class="p">)</span>
        <span class="p">{</span>
            <span class="k">case</span> <span class="n">OnPlatform</span><span class="p">&lt;</span><span class="n">T</span><span class="p">&gt;</span> <span class="k">value</span><span class="p">:</span>
                <span class="c1">//Get return type platform specific resource</span>
                <span class="k">return</span> <span class="n">GetResource</span><span class="p">&lt;</span><span class="n">T</span><span class="p">&gt;(</span><span class="n">resources</span><span class="p">,</span> <span class="k">value</span><span class="p">.</span><span class="n">Platforms</span><span class="p">?.</span><span class="nf">FirstOrDefault</span><span class="p">(</span><span class="n">p</span> <span class="p">=&gt;</span> <span class="n">p</span><span class="p">.</span><span class="n">Platform</span><span class="p">.</span><span class="nf">Contains</span><span class="p">(</span><span class="s">$"</span><span class="p">{</span><span class="n">DeviceInfo</span><span class="p">.</span><span class="n">Platform</span><span class="p">}</span><span class="s">"</span><span class="p">))?.</span><span class="n">Value</span><span class="p">);</span>

            <span class="k">case</span> <span class="n">OnIdiomExtension</span> <span class="k">value</span><span class="p">:</span>
                <span class="p">{</span>
                    <span class="c1">//Get idiom specific resource</span>
                    <span class="kt">var</span> <span class="n">idiomValue</span> <span class="p">=</span> <span class="k">value</span><span class="p">.</span><span class="n">Default</span><span class="p">;</span>
                    <span class="k">if</span> <span class="p">(</span><span class="n">DeviceInfo</span><span class="p">.</span><span class="n">Idiom</span> <span class="p">==</span> <span class="n">DeviceIdiom</span><span class="p">.</span><span class="n">Desktop</span><span class="p">)</span> <span class="n">idiomValue</span> <span class="p">=</span> <span class="k">value</span><span class="p">.</span><span class="n">Desktop</span><span class="p">;</span>
                    <span class="k">if</span> <span class="p">(</span><span class="n">DeviceInfo</span><span class="p">.</span><span class="n">Idiom</span> <span class="p">==</span> <span class="n">DeviceIdiom</span><span class="p">.</span><span class="n">Phone</span><span class="p">)</span> <span class="n">idiomValue</span> <span class="p">=</span> <span class="k">value</span><span class="p">.</span><span class="n">Phone</span><span class="p">;</span>
                    <span class="k">if</span> <span class="p">(</span><span class="n">DeviceInfo</span><span class="p">.</span><span class="n">Idiom</span> <span class="p">==</span> <span class="n">DeviceIdiom</span><span class="p">.</span><span class="n">Tablet</span><span class="p">)</span> <span class="n">idiomValue</span> <span class="p">=</span> <span class="k">value</span><span class="p">.</span><span class="n">Tablet</span><span class="p">;</span>
                    <span class="k">if</span> <span class="p">(</span><span class="n">DeviceInfo</span><span class="p">.</span><span class="n">Idiom</span> <span class="p">==</span> <span class="n">DeviceIdiom</span><span class="p">.</span><span class="n">TV</span><span class="p">)</span> <span class="n">idiomValue</span> <span class="p">=</span> <span class="k">value</span><span class="p">.</span><span class="n">TV</span><span class="p">;</span>
                    <span class="k">if</span> <span class="p">(</span><span class="n">DeviceInfo</span><span class="p">.</span><span class="n">Idiom</span> <span class="p">==</span> <span class="n">DeviceIdiom</span><span class="p">.</span><span class="n">Watch</span><span class="p">)</span> <span class="n">idiomValue</span> <span class="p">=</span> <span class="k">value</span><span class="p">.</span><span class="n">Watch</span><span class="p">;</span>
                    <span class="k">return</span> <span class="n">GetResource</span><span class="p">&lt;</span><span class="n">T</span><span class="p">&gt;(</span><span class="n">resources</span><span class="p">,</span> <span class="n">idiomValue</span><span class="p">);</span>
                <span class="p">}</span>

            <span class="k">case</span> <span class="n">OnIdiom</span><span class="p">&lt;</span><span class="n">T</span><span class="p">&gt;</span> <span class="k">value</span><span class="p">:</span>
                <span class="p">{</span>
                    <span class="c1">//Get return type idiom specific resource</span>
                    <span class="kt">var</span> <span class="n">idiomValue</span> <span class="p">=</span> <span class="k">value</span><span class="p">.</span><span class="n">Default</span><span class="p">;</span>
                    <span class="k">if</span> <span class="p">(</span><span class="n">DeviceInfo</span><span class="p">.</span><span class="n">Idiom</span> <span class="p">==</span> <span class="n">DeviceIdiom</span><span class="p">.</span><span class="n">Desktop</span><span class="p">)</span> <span class="n">idiomValue</span> <span class="p">=</span> <span class="k">value</span><span class="p">.</span><span class="n">Desktop</span><span class="p">;</span>
                    <span class="k">if</span> <span class="p">(</span><span class="n">DeviceInfo</span><span class="p">.</span><span class="n">Idiom</span> <span class="p">==</span> <span class="n">DeviceIdiom</span><span class="p">.</span><span class="n">Phone</span><span class="p">)</span> <span class="n">idiomValue</span> <span class="p">=</span> <span class="k">value</span><span class="p">.</span><span class="n">Phone</span><span class="p">;</span>
                    <span class="k">if</span> <span class="p">(</span><span class="n">DeviceInfo</span><span class="p">.</span><span class="n">Idiom</span> <span class="p">==</span> <span class="n">DeviceIdiom</span><span class="p">.</span><span class="n">Tablet</span><span class="p">)</span> <span class="n">idiomValue</span> <span class="p">=</span> <span class="k">value</span><span class="p">.</span><span class="n">Tablet</span><span class="p">;</span>
                    <span class="k">if</span> <span class="p">(</span><span class="n">DeviceInfo</span><span class="p">.</span><span class="n">Idiom</span> <span class="p">==</span> <span class="n">DeviceIdiom</span><span class="p">.</span><span class="n">TV</span><span class="p">)</span> <span class="n">idiomValue</span> <span class="p">=</span> <span class="k">value</span><span class="p">.</span><span class="n">TV</span><span class="p">;</span>
                    <span class="k">if</span> <span class="p">(</span><span class="n">DeviceInfo</span><span class="p">.</span><span class="n">Idiom</span> <span class="p">==</span> <span class="n">DeviceIdiom</span><span class="p">.</span><span class="n">Watch</span><span class="p">)</span> <span class="n">idiomValue</span> <span class="p">=</span> <span class="k">value</span><span class="p">.</span><span class="n">Watch</span><span class="p">;</span>
                    <span class="k">return</span> <span class="n">idiomValue</span><span class="p">;</span>
                <span class="p">}</span>

            <span class="k">case</span> <span class="n">DynamicResource</span> <span class="k">value</span><span class="p">:</span>
                <span class="c1">//Get dynamic resource</span>
                <span class="k">return</span> <span class="n">resources</span><span class="p">.</span><span class="n">FindResource</span><span class="p">&lt;</span><span class="n">T</span><span class="p">&gt;(</span><span class="k">value</span><span class="p">.</span><span class="n">Key</span><span class="p">);</span>

            <span class="k">case</span> <span class="kt">string</span> <span class="k">value</span><span class="p">:</span>
                <span class="p">{</span>
                    <span class="c1">//Attempt to cast to resource type or return default</span>
                    <span class="k">try</span>
                    <span class="p">{</span>
                        <span class="kt">var</span> <span class="n">converter</span> <span class="p">=</span> <span class="n">TypeDescriptor</span><span class="p">.</span><span class="nf">GetConverter</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">T</span><span class="p">));</span>
                        <span class="k">if</span> <span class="p">(</span><span class="n">converter</span><span class="p">?.</span><span class="nf">CanConvertFrom</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="kt">string</span><span class="p">))</span> <span class="p">??</span> <span class="k">false</span><span class="p">)</span>
                        <span class="p">{</span>
                            <span class="c1">// Cast ConvertFromString(string text) : object to (T)</span>
                            <span class="k">return</span> <span class="p">(</span><span class="n">T</span><span class="p">?)</span><span class="n">converter</span><span class="p">.</span><span class="nf">ConvertFromString</span><span class="p">(</span><span class="k">value</span><span class="p">);</span>
                        <span class="p">}</span>
                        <span class="k">return</span> <span class="k">default</span><span class="p">;</span>
                    <span class="p">}</span>
                    <span class="k">catch</span>
                    <span class="p">{</span>
                        <span class="k">return</span> <span class="k">default</span><span class="p">;</span>
                    <span class="p">}</span>
                <span class="p">}</span>

            <span class="k">case</span> <span class="n">T</span> <span class="k">value</span><span class="p">:</span>
                <span class="c1">//Return found resource value</span>
                <span class="k">return</span> <span class="k">value</span><span class="p">;</span>

            <span class="k">default</span><span class="p">:</span>
                <span class="c1">//Return default resource value</span>
                <span class="k">return</span> <span class="k">default</span><span class="p">;</span>
        <span class="p">}</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">static</span> <span class="n">T</span><span class="p">?</span> <span class="n">FindResource</span><span class="p">&lt;</span><span class="n">T</span><span class="p">&gt;(</span><span class="k">this</span> <span class="n">ResourceDictionary</span> <span class="n">resources</span><span class="p">,</span> <span class="kt">string</span> <span class="n">resourceKey</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="c1">//Verify parameter</span>
        <span class="k">if</span> <span class="p">(</span><span class="kt">string</span><span class="p">.</span><span class="nf">IsNullOrWhiteSpace</span><span class="p">(</span><span class="n">resourceKey</span><span class="p">))</span>
            <span class="k">return</span> <span class="k">default</span><span class="p">;</span>

        <span class="c1">//Attempt to find resource</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">resources</span><span class="p">.</span><span class="nf">TryGetValue</span><span class="p">(</span><span class="n">resourceKey</span><span class="p">,</span> <span class="k">out</span> <span class="kt">var</span> <span class="n">resource</span><span class="p">))</span>
            <span class="c1">//Get resource</span>
            <span class="k">return</span> <span class="n">GetResource</span><span class="p">&lt;</span><span class="n">T</span><span class="p">&gt;(</span><span class="n">resources</span><span class="p">,</span> <span class="n">resource</span><span class="p">);</span>
        <span class="k">else</span>
            <span class="c1">//If nothing found, return default</span>
            <span class="k">return</span> <span class="k">default</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">static</span> <span class="n">T</span><span class="p">?</span> <span class="n">FindResource</span><span class="p">&lt;</span><span class="n">T</span><span class="p">&gt;(</span><span class="kt">string</span> <span class="n">resourceKey</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="c1">//Verify Current Application</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">Application</span><span class="p">.</span><span class="n">Current</span> <span class="k">is</span> <span class="n">not</span> <span class="k">null</span><span class="p">)</span>
            <span class="c1">//Attempt to find resource</span>
            <span class="k">return</span> <span class="n">Application</span><span class="p">.</span><span class="n">Current</span><span class="p">.</span><span class="n">Resources</span><span class="p">.</span><span class="n">FindResource</span><span class="p">&lt;</span><span class="n">T</span><span class="p">&gt;(</span><span class="n">resourceKey</span><span class="p">);</span>
        <span class="k">else</span>
            <span class="c1">//If nothing found, return default</span>
            <span class="k">return</span> <span class="k">default</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p>So with this we have a easy way to <em>“Get ANY Resource Dictionary Value in Code Behind”</em>. Enjoy!</p>]]></content><author><name>Johan Svensson</name></author><category term="Coding" /><category term=".NET" /><category term="MAUI" /><category term="Resource Dictionary" /><summary type="html"><![CDATA[Resource Dictionaries enables us to create reusable resources in our XAML files or in code behind! To resolve and access Resource Dictionary Resources in code behind, we can access it, in some cases, by using the Resource Key index name in the Resource Dictionary: var cornerRadius = Application.Current?.Resources["DefaultCornerRadius"] as CornerRadius; …or with TryGetValue… if (Application.Current?.Resources.TryGetValue("DefaultCornerRadius", out var resource) ?? false) { var cornerRadius = resource as CornerRadius; } BUT when we need to access a Resource that is defined with OnPlatform, OnIdiom and/or references a DynamicResource in a Merged Dictionary, it gets trickier! Especially if this is nested in multiple layers!]]></summary></entry><entry><title type="html">MAUI Lib - LocalizationResourceManager for MAUI!</title><link href="https://sirjohnk.com/coding/MAUI-Lib-1/" rel="alternate" type="text/html" title="MAUI Lib - LocalizationResourceManager for MAUI!" /><published>2022-12-27T00:00:00+01:00</published><updated>2022-12-27T00:00:00+01:00</updated><id>https://sirjohnk.com/coding/MAUI-Lib-1</id><content type="html" xml:base="https://sirjohnk.com/coding/MAUI-Lib-1/"><![CDATA[<p>I have been a fan of the Localization helpers and extensions in the <a href="https://github.com/xamarin/XamarinCommunityToolkit">Xamarin Community Toolkit</a> and have been using this in my Xamarin projects. Since moving to <a href="https://github.com/dotnet/maui">.NET MAUI</a>, I hoped for this to be part of the <a href="https://github.com/CommunityToolkit/Maui">MAUI Community Toolkit</a>. For good reasons the team has decided not to include this in MCT and a <a href="https://github.com/CommunityToolkit/dotnet/issues/312">proposal</a> is issued in the <a href="https://github.com/CommunityToolkit/dotnet">.NET Community Toolkit</a>. But the XCT solution have dependencies to the Xamarin <code class="language-plaintext highlighter-rouge">IMarkupExtension</code> interface and the XCT <code class="language-plaintext highlighter-rouge">WeakEventManager</code> helper class, which makes it tricky to port to a non MAUI library. So until we have a official solution, or anyway is added to MCT, I decided to create a .NET MAUI library for this called <em>LocalizationResourceManager.Maui</em>!</p>

<p>Big shoutout to the original authors, <a href="https://github.com/Char0394">Charlin Agramonte</a>, <a href="https://github.com/brminnick">Brandon Minnick</a>, <a href="https://github.com/maxkoshevoi">Maksym Koshovyi</a> and the entire <a href="https://github.com/xamarin/XamarinCommunityToolkit/graphs/contributors">Xamarin Community Toolkit Team</a>!</p>

<h2 id="library">Library</h2>
<p>The library is available both as a <a href="https://www.nuget.org/packages/LocalizationResourceManager.Maui/">NuGet package</a> and a <a href="https://github.com/SirJohnK/LocalizationResourceManager.Maui">MIT licensed repository at GitHub</a>.</p>

<table>
  <thead>
    <tr>
      <th>Name</th>
      <th style="text-align: center">Nuget</th>
      <th style="text-align: center">GitHub</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>LocalizationResourceManager.Maui</td>
      <td style="text-align: center"><a href="https://www.nuget.org/packages/LocalizationResourceManager.Maui/"><img src="https://buildstats.info/nuget/LocalizationResourceManager.Maui?includePreReleases=true" alt="NuGet" /></a></td>
      <td style="text-align: center"><a href="https://github.com/SirJohnK/LocalizationResourceManager.Maui"><img src="https://img.shields.io/github/v/release/sirjohnk/LocalizationResourceManager.Maui" alt="GitHub Release Date" /></a></td>
    </tr>
  </tbody>
</table>

<p>Compared to the original solution we have some enhanced and added features:</p>
<ul>
  <li>Easy setup with builder pattern extension</li>
  <li>Supports multiple Resource managers</li>
  <li>Supports file based Resource managers</li>
  <li>Supports storing and restoring of the latest set culture</li>
  <li>New <code class="language-plaintext highlighter-rouge">ILocalizationResourceManager</code> interface registered for constructor injection with DI</li>
  <li>Stores current Default / System culture</li>
  <li>Supports Resource names with dots.</li>
  <li>Option to set a placeholder text to be displayed if text is not found.</li>
  <li><code class="language-plaintext highlighter-rouge">TranslateBindingExtension</code> for custom binding with format and plural support in XAML by <a href="https://github.com/stephenquan">Stephen Quan</a>.</li>
  <li>Uses the <a href="https://learn.microsoft.com/en-us/dotnet/api/microsoft.maui.weakeventmanager">WeakEventManager</a> (.NET MAUI)</li>
</ul>

<p>For localized texts used in XAML and/or code behind, we still have:</p>
<ul>
  <li><code class="language-plaintext highlighter-rouge">TranslateExtension</code> (XAML Markup Extension)</li>
  <li><code class="language-plaintext highlighter-rouge">LocalizedString</code> (Track Culture Change in code behind)</li>
</ul>

<h2 id="preparations">Preparations</h2>
<p>To use this library, there are some preperations you need to do in your .NET MAUI project/application:</p>
<ul>
  <li>Set the <code class="language-plaintext highlighter-rouge">Assembly neutral language</code> to your default language.<br />
(In project properties screen or directly in the project file!)<br /></li>
</ul>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">&lt;</span><span class="n">NeutralLanguage</span><span class="p">&gt;</span><span class="n">en</span><span class="p">&lt;/</span><span class="n">NeutralLanguage</span><span class="p">&gt;</span>
</code></pre></div></div>

<ul>
  <li>Create/Add a <code class="language-plaintext highlighter-rouge">Resources File</code> (resx) with the Resources Files Template for your default language. e.g. <strong>AppResources.resx</strong></li>
  <li>Create/Add a <code class="language-plaintext highlighter-rouge">Resources File</code> (resx) for each additional language you want to support. e.g. <strong>AppResources-fr.rex</strong> for French<br />(Use same name as default file and add language code. <a href="https://msdn.microsoft.com/en-us/goglobal/bb964664.aspx">List of all Language codes</a>)</li>
</ul>

<h2 id="easy-setup">Easy setup</h2>
<p>As many .NET MAUI libraries, I use the builder pattern for easy configuration. To setup the library, you use the <code class="language-plaintext highlighter-rouge">UseLocalizationResourceManager</code> extension method with the <code class="language-plaintext highlighter-rouge">ILocalizationSettings</code> settings methods for custom configuration.</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">var</span> <span class="n">builder</span> <span class="p">=</span> <span class="n">MauiApp</span><span class="p">.</span><span class="nf">CreateBuilder</span><span class="p">();</span>
<span class="n">builder</span>
    <span class="p">.</span><span class="n">UseMauiApp</span><span class="p">&lt;</span><span class="n">App</span><span class="p">&gt;()</span>
    <span class="p">.</span><span class="nf">ConfigureFonts</span><span class="p">(</span><span class="n">fonts</span> <span class="p">=&gt;</span>
    <span class="p">{</span>
        <span class="n">fonts</span><span class="p">.</span><span class="nf">AddFont</span><span class="p">(</span><span class="s">"OpenSans-Regular.ttf"</span><span class="p">,</span> <span class="s">"OpenSansRegular"</span><span class="p">);</span>
        <span class="n">fonts</span><span class="p">.</span><span class="nf">AddFont</span><span class="p">(</span><span class="s">"OpenSans-Semibold.ttf"</span><span class="p">,</span> <span class="s">"OpenSansSemibold"</span><span class="p">);</span>
    <span class="p">})</span>
    <span class="p">.</span><span class="nf">UseLocalizationResourceManager</span><span class="p">(</span><span class="n">settings</span> <span class="p">=&gt;</span>
    <span class="p">{</span>
        <span class="n">settings</span><span class="p">.</span><span class="nf">AddResource</span><span class="p">(</span><span class="n">AppResources</span><span class="p">.</span><span class="n">ResourceManager</span><span class="p">);</span>
        <span class="n">settings</span><span class="p">.</span><span class="nf">RestoreLatestCulture</span><span class="p">(</span><span class="k">true</span><span class="p">);</span>
    <span class="p">});</span>
</code></pre></div></div>
<p>Settings contains 6 methods for configuration:</p>
<ul>
  <li>AddResource</li>
  <li>AddFileResource</li>
  <li>InitialCulture</li>
  <li>RestoreLatestCulture</li>
  <li>SupportNameWithDots</li>
  <li>SuppressTextNotFoundException</li>
</ul>

<h3 id="addresource">AddResource</h3>
<p>Used to add one or more Resource Managers. e.g. AppResources.ResourceManager, SpecialResources.ResourceManager etc.</p>

<p><strong>Note</strong>: All resource libraries will be searched in the order they were added, until resource is found!</p>
<h3 id="addfileresource">AddFileResource</h3>
<p>Use to add file based Resource Managers. Enables the option to Create/Read/Write at runtime with <a href="https://learn.microsoft.com/en-us/dotnet/api/system.resources.resourcewriter">ResourceWriter</a> and <a href="https://learn.microsoft.com/en-us/dotnet/api/system.resources.resourcereader">ResourceReader</a>.</p>
<h3 id="initialculture">InitialCulture</h3>
<p>Set the initial/startup culture used for application. e.g. new CultureInfo(“fr”)</p>

<p><strong>Default</strong>: Current System Culture</p>
<h3 id="restorelatestculture">RestoreLatestCulture</h3>
<p>Flag indicating if latest set culture should be restored on application startup.</p>

<p><strong>Default</strong>: false<br />
<strong>Note</strong>: This setting, if set to true, will override the InitalCulture setting!</p>

<h3 id="supportnamewithdots">SupportNameWithDots</h3>
<p>Activate support for Resource <code class="language-plaintext highlighter-rouge">Names</code> with Dots when used with TranslateExtension. e.g. Text=”{localization:Translate Hello.World}”<br />
Dots in names will be temporarily replaced by the substitution text to correctly be handled in the extension binding.</p>

<p>Option to set custom dot substitution. Default: “_”</p>

<h3 id="suppresstextnotfoundexception">SuppressTextNotFoundException</h3>
<p>Ability to Suppress/Deactivate throwing the text not found exception with the option to set a placeholder text to be displayed if text is not found.</p>
<ul>
  <li><strong>UsePlaceholder</strong> flag to indicating if a placeholder text should be displayed if text is not found. (Optional, Default: false, <code class="language-plaintext highlighter-rouge">string.Empy</code> will be returned)</li>
  <li><strong>Placeholder</strong> text to be displayed if text is not found, when UsePlaceHolder is activated. (Optional, Default: Resource name)</li>
</ul>

<p>(“{0}” in the placeholder text, will be replaced with the resource name.)</p>

<h2 id="use-in-xaml">Use in XAML</h2>
<p>When used for localized texts in XAML pages, use the <code class="language-plaintext highlighter-rouge">TranslateExtension</code>:</p>
<ul>
  <li>Add namespace reference to library.</li>
  <li>Use Translate extension with name of resource.</li>
</ul>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">&lt;</span><span class="n">ContentPage</span>
    <span class="n">x</span><span class="p">:</span><span class="n">Class</span><span class="p">=</span><span class="s">"LocalizationResourceManager.Maui.Sample.MainPage"</span>
    <span class="n">xmlns</span><span class="p">=</span><span class="s">"http://schemas.microsoft.com/dotnet/2021/maui"</span>
    <span class="n">xmlns</span><span class="p">:</span><span class="n">x</span><span class="p">=</span><span class="s">"http://schemas.microsoft.com/winfx/2009/xaml"</span>
    <span class="n">xmlns</span><span class="p">:</span><span class="n">localization</span><span class="p">=</span><span class="s">"clr-namespace:LocalizationResourceManager.Maui;assembly=LocalizationResourceManager.Maui"</span><span class="p">&gt;</span>
</code></pre></div></div>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">&lt;</span><span class="n">Label</span>
    <span class="n">FontSize</span><span class="p">=</span><span class="s">"18"</span>
    <span class="n">HorizontalOptions</span><span class="p">=</span><span class="s">"Center"</span>
    <span class="n">SemanticProperties</span><span class="p">.</span><span class="n">Description</span><span class="p">=</span><span class="s">"{localization:Translate WelcomeToMAUI}"</span>
    <span class="n">SemanticProperties</span><span class="p">.</span><span class="n">HeadingLevel</span><span class="p">=</span><span class="s">"Level2"</span>
    <span class="n">Text</span><span class="p">=</span><span class="s">"{localization:Translate WelcomeToMAUI}"</span> <span class="p">/&gt;</span>
</code></pre></div></div>
<h2 id="custom-binding-in-xaml">Custom binding in XAML</h2>
<p>Use the <code class="language-plaintext highlighter-rouge">TranslateBindingExtension</code> for custom binding with format and plural support.</p>

<p><strong><em>Plural support in XAML</em></strong></p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">&lt;</span><span class="n">Button</span>
    <span class="n">x</span><span class="p">:</span><span class="n">Name</span><span class="p">=</span><span class="s">"CounterBtn"</span>
    <span class="n">Clicked</span><span class="p">=</span><span class="s">"OnCounterClicked"</span>
    <span class="n">HorizontalOptions</span><span class="p">=</span><span class="s">"Center"</span>
    <span class="n">SemanticProperties</span><span class="p">.</span><span class="n">Hint</span><span class="p">=</span><span class="s">"{localization:Translate CounterBtnHint}"</span>
    <span class="n">Text</span><span class="p">=</span><span class="s">"{localization:TranslateBinding Count, TranslateFormat=ClickedManyTimes, TranslateOne=ClickedOneTime, TranslateZero=ClickMe}"</span> <span class="p">/&gt;</span>
</code></pre></div></div>

<p>The way it works is:</p>

<p><code class="language-plaintext highlighter-rouge">TranslateFormat</code> : (optional) similar to StringFormat, but the format comes from a string resource, e.g. “Clicked {0} times”<br />
<code class="language-plaintext highlighter-rouge">TranslateOne</code> : (optional) similar to StringFormat, but used for when the binding value is one (1), e.g. “Clicked {0} time”<br />
<code class="language-plaintext highlighter-rouge">TranslateZero</code> : (optional) similar to StringFormat, but used for when the binding value is zero (0), e.g. “Click Me”</p>

<p><strong><em>Date/Time in XAML</em></strong></p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="n">DateTime</span> <span class="n">CurrentDateTime</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span> <span class="p">=</span> <span class="n">DateTime</span><span class="p">.</span><span class="n">Now</span><span class="p">;</span>
</code></pre></div></div>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">&lt;!--</span> <span class="n">DateIs</span> <span class="kt">string</span> <span class="n">resource</span><span class="p">:</span> <span class="s">"Date is: {0}"</span> <span class="p">--&gt;</span>
<span class="p">&lt;</span><span class="n">Label</span> <span class="n">Text</span><span class="p">=</span><span class="s">"{localization:TranslateBinding CurrentDateTime, TranslateFormat=DateIs}/"</span><span class="p">/&gt;</span>

<span class="p">&lt;!</span> <span class="p">--</span> <span class="n">TimeIs</span> <span class="kt">string</span> <span class="n">resource</span><span class="p">:</span> <span class="s">"Time is: {0:HH}:{0:mm}:{0:ss}"</span> <span class="p">--&gt;</span>
<span class="p">&lt;</span><span class="n">Label</span> <span class="n">Text</span><span class="p">=</span><span class="s">"{localization:TranslateBinding CurrentDateTime, TranslateFormat=TimeIs}/"</span> <span class="p">/&gt;</span>
</code></pre></div></div>

<p><strong><em>Currency in XAML</em></strong></p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="kt">decimal</span> <span class="n">Price</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span> <span class="p">=</span> <span class="m">123.45</span><span class="p">;</span>
</code></pre></div></div>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">&lt;!--</span> <span class="n">TotalPrice</span> <span class="kt">string</span> <span class="n">resource</span><span class="p">:</span> <span class="s">"Total Price is: {0:C}"</span> <span class="p">--&gt;</span>
<span class="p">&lt;</span><span class="n">Label</span> <span class="n">Text</span><span class="p">=</span><span class="s">"{localization:TranslateBinding Price, TranslateFormat=TotalPrice}"</span> <span class="p">/&gt;</span>
</code></pre></div></div>

<p><strong><em>Translate collections in XAML</em></strong></p>

<p><code class="language-plaintext highlighter-rouge">TranslateValue</code> : (optional) Apply localization changes to a view model, e.g.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="n">IList</span><span class="p">&lt;</span><span class="kt">string</span><span class="p">&gt;</span> <span class="n">Fruits</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span> <span class="p">=</span> <span class="k">new</span> <span class="n">List</span><span class="p">&lt;</span><span class="kt">string</span><span class="p">&gt;</span> <span class="p">{</span> <span class="s">"LBL_APPLES"</span><span class="p">,</span> <span class="s">"LBL_ORANGES"</span> <span class="p">};</span>
</code></pre></div></div>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">&lt;</span><span class="n">CollectionView</span> <span class="n">ItemsSource</span><span class="p">=</span><span class="s">"{Binding Fruits}"</span><span class="p">&gt;</span>
    <span class="p">&lt;</span><span class="n">CollectionView</span><span class="p">.</span><span class="n">ItemTemplate</span><span class="p">&gt;</span>
        <span class="p">&lt;</span><span class="n">DataTemplate</span><span class="p">&gt;</span>
            <span class="p">&lt;</span><span class="n">Label</span> <span class="n">Text</span><span class="p">=</span><span class="s">"{localization:TranslateBinding . , TranslateValue=True}"</span><span class="p">/&gt;</span>
        <span class="p">&lt;</span><span class="n">DataTemplate</span><span class="p">&gt;</span>
    <span class="p">&lt;/</span><span class="n">CollectionView</span><span class="p">.</span><span class="n">ItemTemplate</span><span class="p">&gt;</span>
<span class="p">&lt;/</span><span class="n">CollectionView</span><span class="p">&gt;</span>
</code></pre></div></div>

<p><strong><em>Translate true/false states in XAML</em></strong></p>

<p><code class="language-plaintext highlighter-rouge">TranslateTrue</code> : (optional) string resource used for when the binding value is true, e.g. “Yes”, “On”, “Activated”<br />
<code class="language-plaintext highlighter-rouge">TranslateFalse</code> : (optional) string resource used for when the binding value is false, e.g. “No”, “Off”, “Deactivated”</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="kt">bool</span> <span class="n">OrderSent</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span> <span class="p">=</span> <span class="k">false</span><span class="p">;</span>
</code></pre></div></div>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">&lt;!--</span> <span class="n">Yes</span><span class="p">/</span><span class="n">No</span> <span class="kt">string</span> <span class="n">resources</span><span class="p">:</span> <span class="s">"Yes"</span> <span class="p">/</span> <span class="s">"No"</span> <span class="p">--&gt;</span>
<span class="p">&lt;</span><span class="n">Label</span> <span class="n">Text</span><span class="p">=</span><span class="s">"{localization:TranslateBinding OrderSent, TranslateTrue=Yes, TranslateFalse=No}"</span> <span class="p">/&gt;</span>
</code></pre></div></div>

<h2 id="use-in-code">Use in Code</h2>
<p>When used to handle localized texts in code behind or ViewModel, use the <code class="language-plaintext highlighter-rouge">LocalizedString</code> class:</p>
<ul>
  <li>Add LocalizedString to code behind or ViewModel to track culture changes</li>
  <li>If needed, make binding to LocalizedString in XAML</li>
</ul>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="n">LocalizedString</span> <span class="n">HelloWorld</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="p">}</span> <span class="p">=</span> <span class="k">new</span><span class="p">(()</span> <span class="p">=&gt;</span> <span class="s">$"</span><span class="p">{</span><span class="n">AppResources</span><span class="p">.</span><span class="n">Hello</span><span class="p">}</span><span class="s">, </span><span class="p">{</span><span class="n">AppResources</span><span class="p">.</span><span class="n">World</span><span class="p">}</span><span class="s">!"</span><span class="p">);</span>
</code></pre></div></div>
<p>…or to support multiple Resource managers…</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="n">LocalizedString</span> <span class="n">HelloWorld</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="p">}</span>

<span class="k">public</span> <span class="nf">MainPage</span><span class="p">(</span><span class="n">ILocalizationResourceManager</span> <span class="n">resourceManager</span><span class="p">)</span>
<span class="p">{</span>
    <span class="n">HelloWorld</span> <span class="p">=</span> <span class="k">new</span><span class="p">(()</span> <span class="p">=&gt;</span> <span class="s">$"</span><span class="p">{</span><span class="n">resourceManager</span><span class="p">[</span><span class="s">"Hello"</span><span class="p">]}</span><span class="s">, </span><span class="p">{</span><span class="n">resourceManager</span><span class="p">[</span><span class="s">"World"</span><span class="p">]}</span><span class="s">!"</span><span class="p">);</span>
</code></pre></div></div>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">&lt;</span><span class="n">Label</span>
    <span class="n">FontSize</span><span class="p">=</span><span class="s">"32"</span>
    <span class="n">HorizontalOptions</span><span class="p">=</span><span class="s">"Center"</span>
    <span class="n">SemanticProperties</span><span class="p">.</span><span class="n">HeadingLevel</span><span class="p">=</span><span class="s">"Level1"</span>
    <span class="n">Text</span><span class="p">=</span><span class="s">"{Binding HelloWorld.Localized}"</span> <span class="p">/&gt;</span>
</code></pre></div></div>

<h2 id="set-and-get-culture">Set and Get Culture</h2>
<p>To handle and access the Current or Default Culture, we inject the <code class="language-plaintext highlighter-rouge">ILocalizationResourceManager</code> interface into our code behind or ViewModel to access the LocalizationResourceManager instance:</p>
<ul>
  <li>Add the <code class="language-plaintext highlighter-rouge">ILocalizationResourceManager</code> interface to your constructor and store locally for later access.</li>
  <li>Use <strong>CurrentCulture</strong> property to Get or Set CurrentCulture. (All text accessed by <code class="language-plaintext highlighter-rouge">TranslateExtension</code> or <code class="language-plaintext highlighter-rouge">LocalizedString</code> will be updated immediately!)</li>
  <li>Use <strong>DefaultCulture</strong> property to Get Default/System culture.</li>
  <li>Use <strong>GetValue</strong> method or Indexer operator <strong>[]</strong> to manually retrieve localized text based on Current culture.</li>
  <li>Use <strong>ReleaseAllResources</strong> method to Release/Close all resources for all registered resources. (Use before manually accessing registered file based resources!)</li>
</ul>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">partial</span> <span class="k">class</span> <span class="nc">MainPage</span> <span class="p">:</span> <span class="n">ContentPage</span>
<span class="p">{</span>
    <span class="k">private</span> <span class="k">readonly</span> <span class="n">ILocalizationResourceManager</span> <span class="n">resourceManager</span><span class="p">;</span>

    <span class="k">public</span> <span class="nf">MainPage</span><span class="p">(</span><span class="n">ILocalizationResourceManager</span> <span class="n">resourceManager</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="nf">InitializeComponent</span><span class="p">();</span>
        <span class="k">this</span><span class="p">.</span><span class="n">resourceManager</span> <span class="p">=</span> <span class="n">resourceManager</span><span class="p">;</span>
</code></pre></div></div>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="kt">string</span><span class="p">?</span> <span class="n">CurrentCulture</span> <span class="p">=&gt;</span> <span class="n">resourceManager</span><span class="p">?.</span><span class="n">CurrentCulture</span><span class="p">.</span><span class="n">NativeName</span><span class="p">;</span>
</code></pre></div></div>
<p>…or…</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="n">LocalizedString</span> <span class="n">CurrentCulture</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="p">}</span>

<span class="k">public</span> <span class="nf">MainPage</span><span class="p">(</span><span class="n">ILocalizationResourceManager</span> <span class="n">resourceManager</span><span class="p">)</span>
<span class="p">{</span>
    <span class="n">CurrentCulture</span> <span class="p">=</span> <span class="k">new</span><span class="p">(()</span> <span class="p">=&gt;</span> <span class="n">resourceManager</span><span class="p">.</span><span class="n">CurrentCulture</span><span class="p">.</span><span class="n">NativeName</span><span class="p">);</span>
</code></pre></div></div>
<p>One line to change Current Culture and Refresh ALL localized texts!</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">resourceManager</span><span class="p">.</span><span class="n">CurrentCulture</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">CultureInfo</span><span class="p">(</span><span class="s">"en"</span><span class="p">);</span>
</code></pre></div></div>

<h2 id="sample">Sample</h2>
<p>Look at the <a href="https://github.com/SirJohnK/LocalizationResourceManager.Maui/tree/main/LocalizationResourceManager.Maui.Sample">Sample project</a> for a example of how to use this library in an .NET MAUI application.</p>

<p><a href="https://github.com/SirJohnK/LocalizationResourceManager.Maui/tree/main/LocalizationResourceManager.Maui.Sample"><img src="/assets/images/LocalizationResourceManager.gif" alt="Sample Application" /></a></p>]]></content><author><name>Johan Svensson</name></author><category term="Coding" /><category term=".NET" /><category term="MAUI" /><category term="Localization" /><category term="Community Toolkit" /><summary type="html"><![CDATA[I have been a fan of the Localization helpers and extensions in the Xamarin Community Toolkit and have been using this in my Xamarin projects. Since moving to .NET MAUI, I hoped for this to be part of the MAUI Community Toolkit. For good reasons the team has decided not to include this in MCT and a proposal is issued in the .NET Community Toolkit. But the XCT solution have dependencies to the Xamarin IMarkupExtension interface and the XCT WeakEventManager helper class, which makes it tricky to port to a non MAUI library. So until we have a official solution, or anyway is added to MCT, I decided to create a .NET MAUI library for this called LocalizationResourceManager.Maui!]]></summary></entry><entry><title type="html">MAUI Snack - Add WeakEventManager to MVVM Toolkit!</title><link href="https://sirjohnk.com/coding/MAUI-Snack-1/" rel="alternate" type="text/html" title="MAUI Snack - Add WeakEventManager to MVVM Toolkit!" /><published>2022-12-06T00:00:00+01:00</published><updated>2022-12-06T00:00:00+01:00</updated><id>https://sirjohnk.com/coding/MAUI-Snack-1</id><content type="html" xml:base="https://sirjohnk.com/coding/MAUI-Snack-1/"><![CDATA[<p><a href="https://learn.microsoft.com/en-us/dotnet/communitytoolkit/mvvm/">MVVM Toolkit</a> is an amazing library when building .NET MAUI Apps with MVVM! Especially the MVVM source generators, that generates all that boiler plate code for <code class="language-plaintext highlighter-rouge">INotifyPropertyChanged</code>, <code class="language-plaintext highlighter-rouge">Properties</code>, <code class="language-plaintext highlighter-rouge">Commands</code> etc. With a couple of nifty <code class="language-plaintext highlighter-rouge">Attributes</code>and <code class="language-plaintext highlighter-rouge">Classes</code> you can easily add this to your code!</p>

<p>Like in this example for a base view model class:</p>
<div class="language-c# highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">/// &lt;summary&gt;</span>
<span class="c1">/// Base ViewModel.</span>
<span class="c1">/// &lt;/summary&gt;</span>
<span class="k">public</span> <span class="k">partial</span> <span class="k">class</span> <span class="nc">BaseViewModel</span> <span class="p">:</span> <span class="n">ObservableObject</span>
<span class="p">{</span>
    <span class="p">[</span><span class="n">ObservableProperty</span><span class="p">]</span>
    <span class="k">private</span> <span class="kt">string</span> <span class="n">title</span><span class="p">;</span>
    
    <span class="p">[</span><span class="n">ObservableProperty</span><span class="p">]</span>
    <span class="p">[</span><span class="nf">NotifyPropertyChangedFor</span><span class="p">(</span><span class="k">nameof</span><span class="p">(</span><span class="n">CanExecute</span><span class="p">))]</span>
    <span class="k">private</span> <span class="kt">bool</span> <span class="n">isBusy</span><span class="p">;</span>

    <span class="k">public</span> <span class="kt">bool</span> <span class="n">CanExecute</span> <span class="p">=&gt;</span> <span class="p">!</span><span class="n">IsBusy</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p class="notice"><strong>No WeakEventManager!</strong> The one thing that I miss from the Xamarin Community Toolkit is the <a href="https://learn.microsoft.com/en-us/xamarin/community-toolkit/helpers/weakeventmanagert">WeakEventManager</a> for safe handling of events! In <a href="https://learn.microsoft.com/en-us/dotnet/maui/what-is-maui">.NET MAUI</a> we have that <a href="https://learn.microsoft.com/en-us/dotnet/api/microsoft.maui.weakeventmanager">WeakEventManager</a> built in!</p>

<p>So I decided to extend the <code class="language-plaintext highlighter-rouge">ObservableObject</code> class in the <a href="https://learn.microsoft.com/en-us/dotnet/communitytoolkit/mvvm/">MVVM Toolkit</a> to add this! By inherting this class into a class called <code class="language-plaintext highlighter-rouge">BaseObservableObject</code> and implementing <code class="language-plaintext highlighter-rouge">INotifyPropertyChanged</code> and <code class="language-plaintext highlighter-rouge">INotifyPropertyChanging</code> events, I could override the <code class="language-plaintext highlighter-rouge">EventHandler</code> and intercept the events to use the <a href="https://learn.microsoft.com/en-us/dotnet/api/microsoft.maui.weakeventmanager">WeakEventManager</a>.</p>

<div class="language-c# highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">/// &lt;summary&gt;</span>
<span class="c1">/// Extended ObservableObject that uses WeakEventManager to avoid memory leaks!</span>
<span class="c1">/// &lt;/summary&gt;</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">BaseObservableObject</span> <span class="p">:</span> <span class="n">ObservableObject</span><span class="p">,</span> <span class="n">INotifyPropertyChanged</span><span class="p">,</span> <span class="n">INotifyPropertyChanging</span>
<span class="p">{</span>
    <span class="k">private</span> <span class="k">readonly</span> <span class="n">WeakEventManager</span> <span class="n">weakEventManager</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">WeakEventManager</span><span class="p">();</span>

    <span class="k">event</span> <span class="n">PropertyChangedEventHandler</span><span class="p">?</span> <span class="n">INotifyPropertyChanged</span><span class="p">.</span><span class="n">PropertyChanged</span>
    <span class="p">{</span>
        <span class="k">add</span> <span class="p">=&gt;</span> <span class="n">weakEventManager</span><span class="p">.</span><span class="nf">AddEventHandler</span><span class="p">(</span><span class="k">value</span><span class="p">);</span>
        <span class="k">remove</span> <span class="p">=&gt;</span> <span class="n">weakEventManager</span><span class="p">.</span><span class="nf">RemoveEventHandler</span><span class="p">(</span><span class="k">value</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="k">event</span> <span class="n">System</span><span class="p">.</span><span class="n">ComponentModel</span><span class="p">.</span><span class="n">PropertyChangingEventHandler</span><span class="p">?</span> <span class="n">INotifyPropertyChanging</span><span class="p">.</span><span class="n">PropertyChanging</span>
    <span class="p">{</span>
        <span class="k">add</span> <span class="p">=&gt;</span> <span class="n">weakEventManager</span><span class="p">.</span><span class="nf">AddEventHandler</span><span class="p">(</span><span class="k">value</span><span class="p">);</span>
        <span class="k">remove</span> <span class="p">=&gt;</span> <span class="n">weakEventManager</span><span class="p">.</span><span class="nf">RemoveEventHandler</span><span class="p">(</span><span class="k">value</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">new</span> <span class="k">event</span> <span class="n">PropertyChangedEventHandler</span><span class="p">?</span> <span class="n">PropertyChanged</span>
    <span class="p">{</span>
        <span class="k">add</span> <span class="p">=&gt;</span> <span class="n">weakEventManager</span><span class="p">.</span><span class="nf">AddEventHandler</span><span class="p">(</span><span class="k">value</span><span class="p">);</span>
        <span class="k">remove</span> <span class="p">=&gt;</span> <span class="n">weakEventManager</span><span class="p">.</span><span class="nf">RemoveEventHandler</span><span class="p">(</span><span class="k">value</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">new</span> <span class="k">event</span> <span class="n">System</span><span class="p">.</span><span class="n">ComponentModel</span><span class="p">.</span><span class="n">PropertyChangingEventHandler</span><span class="p">?</span> <span class="n">PropertyChanging</span>
    <span class="p">{</span>
        <span class="k">add</span> <span class="p">=&gt;</span> <span class="n">weakEventManager</span><span class="p">.</span><span class="nf">AddEventHandler</span><span class="p">(</span><span class="k">value</span><span class="p">);</span>
        <span class="k">remove</span> <span class="p">=&gt;</span> <span class="n">weakEventManager</span><span class="p">.</span><span class="nf">RemoveEventHandler</span><span class="p">(</span><span class="k">value</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="k">protected</span> <span class="k">override</span> <span class="k">void</span> <span class="nf">OnPropertyChanged</span><span class="p">(</span><span class="n">PropertyChangedEventArgs</span> <span class="n">e</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">weakEventManager</span><span class="p">.</span><span class="nf">HandleEvent</span><span class="p">(</span><span class="k">this</span><span class="p">,</span> <span class="n">e</span><span class="p">,</span> <span class="k">nameof</span><span class="p">(</span><span class="n">INotifyPropertyChanged</span><span class="p">.</span><span class="n">PropertyChanged</span><span class="p">));</span>
    <span class="p">}</span>

    <span class="k">protected</span> <span class="k">override</span> <span class="k">void</span> <span class="nf">OnPropertyChanging</span><span class="p">(</span><span class="n">System</span><span class="p">.</span><span class="n">ComponentModel</span><span class="p">.</span><span class="n">PropertyChangingEventArgs</span> <span class="n">e</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">weakEventManager</span><span class="p">.</span><span class="nf">HandleEvent</span><span class="p">(</span><span class="k">this</span><span class="p">,</span> <span class="n">e</span><span class="p">,</span> <span class="k">nameof</span><span class="p">(</span><span class="n">INotifyPropertyChanging</span><span class="p">.</span><span class="n">PropertyChanging</span><span class="p">));</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>So now by inherting the <code class="language-plaintext highlighter-rouge">BaseObservableObject</code> in our classes, we now have event handling with <a href="https://learn.microsoft.com/en-us/xamarin/community-toolkit/helpers/weakeventmanagert">WeakEventManager</a> in our code using the <a href="https://learn.microsoft.com/en-us/dotnet/communitytoolkit/mvvm/">MVVM Toolkit</a>!</p>

<div class="language-c# highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">partial</span> <span class="k">class</span> <span class="nc">BaseViewModel</span> <span class="p">:</span> <span class="n">BaseObservableObject</span>
</code></pre></div></div>]]></content><author><name>Johan Svensson</name></author><category term="Coding" /><category term=".NET" /><category term="MAUI" /><category term="MVVM Toolkit" /><category term="Community Toolkit" /><summary type="html"><![CDATA[MVVM Toolkit is an amazing library when building .NET MAUI Apps with MVVM! Especially the MVVM source generators, that generates all that boiler plate code for INotifyPropertyChanged, Properties, Commands etc. With a couple of nifty Attributesand Classes you can easily add this to your code!]]></summary></entry></feed>