<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Victor Hugo Garcia</title>
    <description>The latest articles on DEV Community by Victor Hugo Garcia (@vhugogarcia).</description>
    <link>https://dev.to/vhugogarcia</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F637736%2Fd4182a50-a75a-43fb-a043-f5cc17f26148.png</url>
      <title>DEV Community: Victor Hugo Garcia</title>
      <link>https://dev.to/vhugogarcia</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/vhugogarcia"/>
    <language>en</language>
    <item>
      <title>Xperience Community: Content Repositories</title>
      <dc:creator>Victor Hugo Garcia</dc:creator>
      <pubDate>Thu, 26 Mar 2026 13:47:51 +0000</pubDate>
      <link>https://dev.to/vhugogarcia/xperience-community-content-repositories-1gaf</link>
      <guid>https://dev.to/vhugogarcia/xperience-community-content-repositories-1gaf</guid>
      <description>&lt;p&gt;If you have been building with &lt;strong&gt;Xperience by Kentico&lt;/strong&gt;, you are probably familiar with the repetitive ceremony around fetching web page content: URL resolution, language detection, caching, null guards. It is the kind of code you write once per project and then paste — slightly modified — into the next one.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;Xperience Community: Content Repository&lt;/strong&gt; package was built to centralize exactly that kind of logic. And with version &lt;strong&gt;1.0.2&lt;/strong&gt;, it gets a meaningful new addition: the &lt;code&gt;WebPageRepository&lt;/code&gt;.&lt;/p&gt;




&lt;h3&gt;
  
  
  What's New in v1.0.2
&lt;/h3&gt;

&lt;p&gt;This release ships two things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;IWebPageRepository&lt;/code&gt; and &lt;code&gt;WebPageRepository&lt;/code&gt;&lt;/strong&gt; — a new repository for resolving web page URLs by GUID, with built-in language awareness and caching.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Kentico package upgrades&lt;/strong&gt; — all Kentico dependencies bumped to &lt;strong&gt;31.2.0&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The web page repository is small in surface area but fills a real gap. It gives you a single, safe place to resolve a &lt;code&gt;WebPageUrl&lt;/code&gt; from a GUID, handles language fallbacks automatically, and caches results intelligently so you're not hitting the database on every request.&lt;/p&gt;




&lt;h3&gt;
  
  
  Installation
&lt;/h3&gt;

&lt;p&gt;Add the package via the .NET CLI:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dotnet add package XperienceCommunity.ContentRepository
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then register all repositories in your &lt;code&gt;Program.cs&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddXperienceContentRepositories&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it. &lt;code&gt;IWebPageRepository&lt;/code&gt; is now registered in DI and ready to use.&lt;/p&gt;




&lt;h3&gt;
  
  
  The WebPageRepository
&lt;/h3&gt;

&lt;p&gt;The new repository exposes a single, focused method:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;IWebPageRepository&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;WebPageUrl&lt;/span&gt;&lt;span class="p"&gt;?&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;GetUrlByGuid&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Guid&lt;/span&gt; &lt;span class="n"&gt;webPageGuid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="n"&gt;languageName&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Under the hood, &lt;code&gt;WebPageRepository&lt;/code&gt; wires together three Kentico services — &lt;code&gt;IWebPageUrlRetriever&lt;/code&gt;, &lt;code&gt;IPreferredLanguageRetriever&lt;/code&gt;, and &lt;code&gt;IProgressiveCache&lt;/code&gt; — so you do not have to.&lt;/p&gt;

&lt;p&gt;Here is what the implementation does for you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;GUID guard&lt;/strong&gt; — returns &lt;code&gt;null&lt;/code&gt; immediately if the GUID is empty, avoiding pointless lookups.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Language resolution&lt;/strong&gt; — if no language is passed, it falls back to the current preferred language via &lt;code&gt;IPreferredLanguageRetriever&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Progressive caching&lt;/strong&gt; — caches the resolved URL for 60 minutes, scoped to the GUID and language. Cache is invalidated via the &lt;code&gt;webpageitem|byguid|{guid}&lt;/code&gt; dependency, so stale URLs are never served after a content update.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Graceful error handling&lt;/strong&gt; — if URL retrieval fails for any reason (page doesn't exist, routing misconfiguration), it returns &lt;code&gt;null&lt;/code&gt; and skips caching the failed result.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For the full implementation, check the &lt;a href="https://github.com/vhugogarcia/xperience-community-content-repository" rel="noopener noreferrer"&gt;repository on GitHub&lt;/a&gt;.&lt;/p&gt;




&lt;h3&gt;
  
  
  Usage
&lt;/h3&gt;

&lt;p&gt;You can access it directly through DI or via the centralized &lt;code&gt;ContentRepositories&lt;/code&gt; accessor:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Via direct injection&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IWebPageRepository&lt;/span&gt; &lt;span class="n"&gt;webPageRepository&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;?&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;GetPageUrl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Guid&lt;/span&gt; &lt;span class="n"&gt;pageGuid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;webPageRepository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetUrlByGuid&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pageGuid&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="n"&gt;RelativePath&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Via ContentRepositories accessor&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyOtherService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ContentRepositories&lt;/span&gt; &lt;span class="n"&gt;repos&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;?&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;GetPageUrl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Guid&lt;/span&gt; &lt;span class="n"&gt;pageGuid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;repo&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;repos&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetWebPageRepository&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;repo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetUrlByGuid&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pageGuid&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="n"&gt;RelativePath&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can also pass a language explicitly when you need to resolve a URL for a specific locale rather than the current preferred language:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;webPageRepository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetUrlByGuid&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pageGuid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;languageName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"es"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Why This Matters
&lt;/h3&gt;

&lt;p&gt;URL resolution from a GUID might sound trivial, but it is a frequent request in real Xperience projects — especially when building navigation menus, breadcrumbs, related content links, or any component that stores references to other pages by GUID rather than by full path.&lt;/p&gt;

&lt;p&gt;Without something like this, you typically end up either writing the caching boilerplate yourself for each use case, or skipping caching altogether and accepting the performance cost. The &lt;code&gt;WebPageRepository&lt;/code&gt; solves that cleanly in one place.&lt;/p&gt;




&lt;h3&gt;
  
  
  What's Already in the Package
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;WebPageRepository&lt;/code&gt; joins an already capable set of repositories. A quick summary of what the package covers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;IPageTypeRepository&amp;lt;T&amp;gt;&lt;/code&gt;&lt;/strong&gt; — query web page content types by ID, GUID, path, taxonomy tag, or custom where conditions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;IContentTypeRepository&amp;lt;T&amp;gt;&lt;/code&gt;&lt;/strong&gt; — retrieve reusable content items with pagination, smart folder support, and multi-type queries.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;IMediaFileRepository&lt;/code&gt;&lt;/strong&gt; — fetch media files by GUID or from asset related items, with caching included.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;ICacheDependencyBuilder&lt;/code&gt;&lt;/strong&gt; — a utility for assembling cache dependencies consistently across your project.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;ContentRepositories&lt;/code&gt;&lt;/strong&gt; — a centralized accessor that provides all repositories through a single injected service.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;Version 1.0.2 of &lt;strong&gt;Xperience Community: Content Repository&lt;/strong&gt; is a focused update — a new repository that handles one common task well, paired with a dependency upgrade to Kentico 31.2.0. If you are already using the package, updating is straightforward. If you have not tried it yet, this is a good moment to add it to your toolbox.&lt;/p&gt;

&lt;p&gt;The NuGet package is available at &lt;a href="https://www.nuget.org/packages/XperienceCommunity.ContentRepository" rel="noopener noreferrer"&gt;nuget.org/packages/XperienceCommunity.ContentRepository&lt;/a&gt;, and the full source is on &lt;a href="https://github.com/vhugogarcia/xperience-community-content-repository" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Follow me on social:&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;LinkedIn: *&lt;/em&gt;&lt;a href="https://www.linkedin.com/in/victorhugogarcia/" rel="noopener noreferrer"&gt;victorhugogarcia&lt;/a&gt;***&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;GitHub: *&lt;/em&gt;&lt;a href="https://github.com/vhugogarcia" rel="noopener noreferrer"&gt;@vhugogarcia&lt;/a&gt;***&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;X: *&lt;/em&gt;&lt;a href="https://twitter.com/ivictorhugo" rel="noopener noreferrer"&gt;@ivictorhugo&lt;/a&gt;***&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>dotnet</category>
      <category>kentico</category>
      <category>xperience</category>
    </item>
    <item>
      <title>Xperience Community: Essentials</title>
      <dc:creator>Victor Hugo Garcia</dc:creator>
      <pubDate>Wed, 08 Oct 2025 18:07:51 +0000</pubDate>
      <link>https://dev.to/vhugogarcia/xperience-community-essentials-2e9p</link>
      <guid>https://dev.to/vhugogarcia/xperience-community-essentials-2e9p</guid>
      <description>&lt;p&gt;If you work with &lt;strong&gt;Xperience by Kentico&lt;/strong&gt;, you know how much repetitive code can pile up across projects. From text manipulation and encryption to URL handling and localization, the small things add up fast. That’s why the &lt;strong&gt;Xperience Community: Essentials&lt;/strong&gt; package was created — a lightweight, yet powerful collection of helpers, utilities, and extensions designed to make your life easier and your codebase cleaner.&lt;/p&gt;

&lt;p&gt;With this &lt;a href="https://www.nuget.org/packages/XperienceCommunity.Essentials" rel="noopener noreferrer"&gt;NuGet&lt;/a&gt; package, you can spend less time rewriting boilerplate and more time focusing on the actual business logic of your application.&lt;/p&gt;




&lt;h3&gt;
  
  
  Implementation
&lt;/h3&gt;

&lt;p&gt;Getting started is incredibly easy. You can add the package directly to your Xperience project via the .NET CLI:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dotnet add package XperienceCommunity.Essentials
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once installed, initialize the configuration helper in your &lt;code&gt;Program.cs&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;ConfigurationHelper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Initialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Configuration&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This step activates configuration-dependent features such as AES encryption and other utilities that rely on your app's configuration settings.&lt;/p&gt;

&lt;p&gt;If you plan to use encryption helpers, you’ll also need to define a section in your &lt;code&gt;appsettings.json&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"XperienceCommunityEssentials"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"AesSecureKey"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"your-base64-key"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That’s it! You’re now ready to start using the wide range of extensions the package provides.&lt;/p&gt;




&lt;h3&gt;
  
  
  Key Features
&lt;/h3&gt;

&lt;h4&gt;
  
  
  AES Encryption Helper
&lt;/h4&gt;

&lt;p&gt;Protect sensitive information with simple encryption and decryption methods. Just configure your AES key once, and you can easily encrypt or decrypt strings throughout your project.&lt;/p&gt;

&lt;h4&gt;
  
  
  Text Helper Extensions
&lt;/h4&gt;

&lt;p&gt;Tackle common text operations effortlessly. From truncating and Base64 encoding to cleaning HTML and generating random IDs, these helpers eliminate repetitive code and make string handling a breeze.&lt;/p&gt;

&lt;h4&gt;
  
  
  Collection Extensions
&lt;/h4&gt;

&lt;p&gt;One of the most powerful parts of this library is the &lt;strong&gt;Collection Extensions&lt;/strong&gt;, especially when working with Xperience asset collections, related items, or structured content.&lt;/p&gt;

&lt;p&gt;When you’re dealing with lists of assets, pages, or objects, you often need to check if data exists, access nested properties safely, or retrieve default values — all without endless null-checks or verbose LINQ.&lt;/p&gt;

&lt;p&gt;These extensions make your code much cleaner and more expressive. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Safely get the first matching asset name&lt;/span&gt;
&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;assetCollection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetFirstOrEmpty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AssetFile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Metadata&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Get the first asset URL or an empty string if not available&lt;/span&gt;
&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;assetCollection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetFirstOrEmpty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AssetFile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Url&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Retrieve a default value safely from complex collections&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;assetCollection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetFirstOrDefault&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SomeIntProperty&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Check if two collections have any matching elements&lt;/span&gt;
&lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;hasMatch&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sourceList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ContainsAny&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;targetList&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These helpers are especially handy for handling &lt;strong&gt;content hub assets&lt;/strong&gt;, and &lt;strong&gt;custom structured data&lt;/strong&gt;. Instead of defensive coding everywhere, you can write elegant one-liners that are both safe and maintainable.&lt;/p&gt;

&lt;h4&gt;
  
  
  Localization Extensions
&lt;/h4&gt;

&lt;p&gt;Improve your localization workflow with built-in fallbacks. Never worry about missing translations again — just define a default value that will be displayed when a key isn’t found.&lt;/p&gt;

&lt;h4&gt;
  
  
  URL Helpers
&lt;/h4&gt;

&lt;p&gt;Easily manipulate URLs within Xperience. Convert relative URLs to absolute ones, trim paths, or safely handle URL conversions in your page components.&lt;/p&gt;

&lt;h4&gt;
  
  
  Enum Dropdown Provider
&lt;/h4&gt;

&lt;p&gt;Populate dropdowns dynamically using enums — perfect for admin UI components and form fields. With a few lines of code, your enums become user-friendly selection options.&lt;/p&gt;




&lt;h3&gt;
  
  
  Example Usage
&lt;/h3&gt;

&lt;p&gt;Here are a few quick examples that show how convenient these helpers can be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Encrypt and decrypt text&lt;/span&gt;
&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;encrypted&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;EncryptionHelper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;EncryptAes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"sensitive info"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;decrypted&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;EncryptionHelper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;DecryptAes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;encrypted&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Clean HTML&lt;/span&gt;
&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;clean&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;htmlContent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CleanHtml&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// Generate random ID&lt;/span&gt;
&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;TextHelper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GenerateId&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;12&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Safe property access&lt;/span&gt;
&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;assetCollection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetFirstOrEmpty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AssetFile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Metadata&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Localized text with fallback&lt;/span&gt;
&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;localizer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetStringOrDefault&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Welcome"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Welcome to our site!"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These examples show how &lt;strong&gt;XperienceCommunity.Essentials&lt;/strong&gt; simplifies daily development and improves code consistency across your projects.&lt;/p&gt;




&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;The &lt;strong&gt;Xperience Community: Essentials&lt;/strong&gt; package was built to save developers time and help maintain cleaner, more maintainable codebases. It consolidates common functionality that nearly every Xperience project needs into a single, well-documented library.&lt;/p&gt;




&lt;p&gt;Follow me on Social:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;LinkedIn &lt;strong&gt;&lt;a href="https://www.linkedin.com/in/victorhugogarcia/" rel="noopener noreferrer"&gt;victorhugogarcia&lt;/a&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;GitHub &lt;strong&gt;&lt;a href="https://github.com/vhugogarcia" rel="noopener noreferrer"&gt;@vhugogarcia&lt;/a&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;X &lt;strong&gt;&lt;a href="https://twitter.com/ivictorhugo" rel="noopener noreferrer"&gt;@ivictorhugo&lt;/a&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>dotnet</category>
      <category>kentico</category>
      <category>webdev</category>
      <category>csharp</category>
    </item>
    <item>
      <title>Deprecation of ListView in .NET MAUI</title>
      <dc:creator>Victor Hugo Garcia</dc:creator>
      <pubDate>Sat, 29 Mar 2025 19:20:52 +0000</pubDate>
      <link>https://dev.to/vhugogarcia/deprecation-of-listview-in-net-maui-cga</link>
      <guid>https://dev.to/vhugogarcia/deprecation-of-listview-in-net-maui-cga</guid>
      <description>&lt;p&gt;Just a few hours ago, the .NET MAUI team &lt;a href="https://github.com/dotnet/maui/issues/28699" rel="noopener noreferrer"&gt;announced&lt;/a&gt; a significant change coming in .NET 10: the &lt;code&gt;ListView&lt;/code&gt; control and all its related cell types (&lt;code&gt;TextCell&lt;/code&gt;, &lt;code&gt;ImageCell&lt;/code&gt;, &lt;code&gt;ViewCell&lt;/code&gt;, etc.) will be marked as obsolete. This decision is part of Microsoft's strategy to streamline the developer experience by focusing on a single, optimized control for displaying collections of data. Which I'm personally happy with, the less duplicated controls to maintain the better.&lt;/p&gt;

&lt;p&gt;If you've been using MAUI (or Xamarin.Forms before it), you're likely familiar with &lt;code&gt;ListView&lt;/code&gt; - it's been a staple for displaying lists of data since the early days. However, &lt;code&gt;CollectionView&lt;/code&gt; in the past had several performance and rendering issues, but these days thanks to Microsoft and the community, the Collection View offers numerous advantages, including better performance, more flexible layouts, and improved customization options. With .NET 10 on the horizon, now is the perfect time to migrate your existing &lt;code&gt;ListView&lt;/code&gt; implementations to &lt;code&gt;CollectionView&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In this article, I'll walk you through a straightforward migration process, highlighting the key differences between these controls and providing practical examples to ensure a smooth transition for your MAUI applications.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding the Key Differences
&lt;/h2&gt;

&lt;p&gt;Before diving into the migration process, it's helpful to understand some fundamental differences between &lt;code&gt;ListView&lt;/code&gt; and &lt;code&gt;CollectionView&lt;/code&gt;:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;ListView&lt;/th&gt;
&lt;th&gt;CollectionView&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Cell Types&lt;/td&gt;
&lt;td&gt;Uses predefined cells (&lt;code&gt;TextCell&lt;/code&gt;, &lt;code&gt;ImageCell&lt;/code&gt;, etc.)&lt;/td&gt;
&lt;td&gt;Uses DataTemplates directly&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Selection&lt;/td&gt;
&lt;td&gt;Single or multiple selection with built-in visual feedback&lt;/td&gt;
&lt;td&gt;Single or multiple but even more flexible selection with customizable visual feedback&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Item Appearance&lt;/td&gt;
&lt;td&gt;Uses &lt;code&gt;Cell&lt;/code&gt; hierarchy&lt;/td&gt;
&lt;td&gt;Uses direct &lt;code&gt;DataTemplate&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Layouts&lt;/td&gt;
&lt;td&gt;Vertical list only&lt;/td&gt;
&lt;td&gt;Vertical, horizontal, and grid layouts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Performance&lt;/td&gt;
&lt;td&gt;Less optimized&lt;/td&gt;
&lt;td&gt;Better virtualization and performance&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Grouping&lt;/td&gt;
&lt;td&gt;Through &lt;code&gt;GroupDisplayBinding&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;More flexible grouping options&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Headers/Footers&lt;/td&gt;
&lt;td&gt;Basic header/footer templates&lt;/td&gt;
&lt;td&gt;Enhanced header/footer templates&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Step 1: Replace the Control Declaration
&lt;/h2&gt;

&lt;p&gt;The first step is to replace the &lt;code&gt;ListView&lt;/code&gt; declaration with &lt;code&gt;CollectionView&lt;/code&gt; in your XAML:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Before (ListView):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;ListView&lt;/span&gt; &lt;span class="na"&gt;x:Name=&lt;/span&gt;&lt;span class="s"&gt;"MyListView"&lt;/span&gt; 
          &lt;span class="na"&gt;ItemsSource=&lt;/span&gt;&lt;span class="s"&gt;"{Binding Items}"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="c"&gt;&amp;lt;!-- Cell templates here --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/ListView&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;After (CollectionView):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;CollectionView&lt;/span&gt; &lt;span class="na"&gt;x:Name=&lt;/span&gt;&lt;span class="s"&gt;"MyCollectionView"&lt;/span&gt;
                &lt;span class="na"&gt;ItemsSource=&lt;/span&gt;&lt;span class="s"&gt;"{Binding Items}"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="c"&gt;&amp;lt;!-- Item templates here --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/CollectionView&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 2: Convert Cell Templates to DataTemplates
&lt;/h2&gt;

&lt;p&gt;One of the biggest differences is how items are templated. &lt;code&gt;ListView&lt;/code&gt; uses various cell types, while &lt;code&gt;CollectionView&lt;/code&gt; uses &lt;code&gt;DataTemplate&lt;/code&gt; directly.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example: Converting TextCell
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Before (ListView with TextCell):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;ListView&lt;/span&gt; &lt;span class="na"&gt;ItemsSource=&lt;/span&gt;&lt;span class="s"&gt;"{Binding Items}"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;ListView.ItemTemplate&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;DataTemplate&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;TextCell&lt;/span&gt; &lt;span class="na"&gt;Text=&lt;/span&gt;&lt;span class="s"&gt;"{Binding Title}"&lt;/span&gt; 
                      &lt;span class="na"&gt;Detail=&lt;/span&gt;&lt;span class="s"&gt;"{Binding Description}"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/DataTemplate&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/ListView.ItemTemplate&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/ListView&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;After (CollectionView):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;CollectionView&lt;/span&gt; &lt;span class="na"&gt;ItemsSource=&lt;/span&gt;&lt;span class="s"&gt;"{Binding Items}"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;CollectionView.ItemTemplate&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;DataTemplate&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;Grid&lt;/span&gt; &lt;span class="na"&gt;Padding=&lt;/span&gt;&lt;span class="s"&gt;"10"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;Grid.RowDefinitions&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;RowDefinition&lt;/span&gt; &lt;span class="na"&gt;Height=&lt;/span&gt;&lt;span class="s"&gt;"Auto"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;RowDefinition&lt;/span&gt; &lt;span class="na"&gt;Height=&lt;/span&gt;&lt;span class="s"&gt;"Auto"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;/Grid.RowDefinitions&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;Label&lt;/span&gt; &lt;span class="na"&gt;Grid.Row=&lt;/span&gt;&lt;span class="s"&gt;"0"&lt;/span&gt; &lt;span class="na"&gt;Text=&lt;/span&gt;&lt;span class="s"&gt;"{Binding Title}"&lt;/span&gt; &lt;span class="na"&gt;FontAttributes=&lt;/span&gt;&lt;span class="s"&gt;"Bold"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;Label&lt;/span&gt; &lt;span class="na"&gt;Grid.Row=&lt;/span&gt;&lt;span class="s"&gt;"1"&lt;/span&gt; &lt;span class="na"&gt;Text=&lt;/span&gt;&lt;span class="s"&gt;"{Binding Description}"&lt;/span&gt; &lt;span class="na"&gt;FontSize=&lt;/span&gt;&lt;span class="s"&gt;"Small"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/Grid&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/DataTemplate&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/CollectionView.ItemTemplate&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/CollectionView&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Example: Converting ImageCell
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Before (ListView with ImageCell):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;ListView&lt;/span&gt; &lt;span class="na"&gt;ItemsSource=&lt;/span&gt;&lt;span class="s"&gt;"{Binding Items}"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;ListView.ItemTemplate&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;DataTemplate&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;ImageCell&lt;/span&gt; &lt;span class="na"&gt;Text=&lt;/span&gt;&lt;span class="s"&gt;"{Binding Title}"&lt;/span&gt; 
                       &lt;span class="na"&gt;Detail=&lt;/span&gt;&lt;span class="s"&gt;"{Binding Description}"&lt;/span&gt;
                       &lt;span class="na"&gt;ImageSource=&lt;/span&gt;&lt;span class="s"&gt;"{Binding ImageUrl}"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/DataTemplate&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/ListView.ItemTemplate&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/ListView&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;After (CollectionView):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;CollectionView&lt;/span&gt; &lt;span class="na"&gt;ItemsSource=&lt;/span&gt;&lt;span class="s"&gt;"{Binding Items}"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;CollectionView.ItemTemplate&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;DataTemplate&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;Grid&lt;/span&gt; &lt;span class="na"&gt;Padding=&lt;/span&gt;&lt;span class="s"&gt;"10"&lt;/span&gt; &lt;span class="na"&gt;ColumnSpacing=&lt;/span&gt;&lt;span class="s"&gt;"10"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;Grid.ColumnDefinitions&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;ColumnDefinition&lt;/span&gt; &lt;span class="na"&gt;Width=&lt;/span&gt;&lt;span class="s"&gt;"50"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;ColumnDefinition&lt;/span&gt; &lt;span class="na"&gt;Width=&lt;/span&gt;&lt;span class="s"&gt;"*"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;/Grid.ColumnDefinitions&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;Grid.RowDefinitions&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;RowDefinition&lt;/span&gt; &lt;span class="na"&gt;Height=&lt;/span&gt;&lt;span class="s"&gt;"Auto"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;RowDefinition&lt;/span&gt; &lt;span class="na"&gt;Height=&lt;/span&gt;&lt;span class="s"&gt;"Auto"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;/Grid.RowDefinitions&amp;gt;&lt;/span&gt;

                &lt;span class="nt"&gt;&amp;lt;Image&lt;/span&gt; &lt;span class="na"&gt;Grid.Row=&lt;/span&gt;&lt;span class="s"&gt;"0"&lt;/span&gt; &lt;span class="na"&gt;Grid.RowSpan=&lt;/span&gt;&lt;span class="s"&gt;"2"&lt;/span&gt; &lt;span class="na"&gt;Grid.Column=&lt;/span&gt;&lt;span class="s"&gt;"0"&lt;/span&gt;
                       &lt;span class="na"&gt;Source=&lt;/span&gt;&lt;span class="s"&gt;"{Binding ImageUrl}"&lt;/span&gt;
                       &lt;span class="na"&gt;Aspect=&lt;/span&gt;&lt;span class="s"&gt;"AspectFill"&lt;/span&gt;
                       &lt;span class="na"&gt;HeightRequest=&lt;/span&gt;&lt;span class="s"&gt;"50"&lt;/span&gt; &lt;span class="na"&gt;WidthRequest=&lt;/span&gt;&lt;span class="s"&gt;"50"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;

                &lt;span class="nt"&gt;&amp;lt;Label&lt;/span&gt; &lt;span class="na"&gt;Grid.Row=&lt;/span&gt;&lt;span class="s"&gt;"0"&lt;/span&gt; &lt;span class="na"&gt;Grid.Column=&lt;/span&gt;&lt;span class="s"&gt;"1"&lt;/span&gt; 
                       &lt;span class="na"&gt;Text=&lt;/span&gt;&lt;span class="s"&gt;"{Binding Title}"&lt;/span&gt; 
                       &lt;span class="na"&gt;FontAttributes=&lt;/span&gt;&lt;span class="s"&gt;"Bold"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;

                &lt;span class="nt"&gt;&amp;lt;Label&lt;/span&gt; &lt;span class="na"&gt;Grid.Row=&lt;/span&gt;&lt;span class="s"&gt;"1"&lt;/span&gt; &lt;span class="na"&gt;Grid.Column=&lt;/span&gt;&lt;span class="s"&gt;"1"&lt;/span&gt; 
                       &lt;span class="na"&gt;Text=&lt;/span&gt;&lt;span class="s"&gt;"{Binding Description}"&lt;/span&gt; 
                       &lt;span class="na"&gt;FontSize=&lt;/span&gt;&lt;span class="s"&gt;"Small"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/Grid&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/DataTemplate&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/CollectionView.ItemTemplate&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/CollectionView&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 3: Update Selection Handling
&lt;/h2&gt;

&lt;p&gt;The selection mechanism differs between the two controls:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Before (ListView):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;OnItemSelected&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;object&lt;/span&gt; &lt;span class="n"&gt;sender&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;SelectedItemChangedEventArgs&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SelectedItem&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// Handle the selected item&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;selectedItem&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SelectedItem&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;MyItemType&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// Important: Deselect the item&lt;/span&gt;
    &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;ListView&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;sender&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;SelectedItem&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;After (CollectionView):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;CollectionView&lt;/span&gt;
      &lt;span class="na"&gt;x:Name=&lt;/span&gt;&lt;span class="s"&gt;"collectionView"&lt;/span&gt;
      &lt;span class="na"&gt;SelectionMode=&lt;/span&gt;&lt;span class="s"&gt;"Single"&lt;/span&gt;
      &lt;span class="na"&gt;SelectionChanged=&lt;/span&gt;&lt;span class="s"&gt;"OnSelectionChanged"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/CollectionView&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;OnSelectionChanged&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;object&lt;/span&gt; &lt;span class="n"&gt;sender&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;SelectionChangedEventArgs&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;previous&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PreviousSelection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FirstOrDefault&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;current&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CurrentSelection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FirstOrDefault&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 4: Convert Grouping
&lt;/h2&gt;

&lt;p&gt;If you're using grouping in your &lt;code&gt;ListView&lt;/code&gt;, you'll need to adapt it for &lt;code&gt;CollectionView&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Before (ListView with grouping):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;ListView&lt;/span&gt; &lt;span class="na"&gt;ItemsSource=&lt;/span&gt;&lt;span class="s"&gt;"{Binding GroupedItems}"&lt;/span&gt; 
          &lt;span class="na"&gt;IsGroupingEnabled=&lt;/span&gt;&lt;span class="s"&gt;"True"&lt;/span&gt;
          &lt;span class="na"&gt;GroupDisplayBinding=&lt;/span&gt;&lt;span class="s"&gt;"{Binding Key}"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;ListView.ItemTemplate&amp;gt;&lt;/span&gt;
        &lt;span class="c"&gt;&amp;lt;!-- Item template --&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/ListView.ItemTemplate&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/ListView&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;After (CollectionView with grouping):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;CollectionView&lt;/span&gt; &lt;span class="na"&gt;ItemsSource=&lt;/span&gt;&lt;span class="s"&gt;"{Binding GroupedItems}"&lt;/span&gt; 
                &lt;span class="na"&gt;IsGrouped=&lt;/span&gt;&lt;span class="s"&gt;"True"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;CollectionView.GroupHeaderTemplate&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;DataTemplate&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;Label&lt;/span&gt; &lt;span class="na"&gt;Text=&lt;/span&gt;&lt;span class="s"&gt;"{Binding Key}"&lt;/span&gt; 
                   &lt;span class="na"&gt;FontAttributes=&lt;/span&gt;&lt;span class="s"&gt;"Bold"&lt;/span&gt;
                   &lt;span class="na"&gt;BackgroundColor=&lt;/span&gt;&lt;span class="s"&gt;"LightGray"&lt;/span&gt;
                   &lt;span class="na"&gt;Padding=&lt;/span&gt;&lt;span class="s"&gt;"10"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/DataTemplate&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/CollectionView.GroupHeaderTemplate&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;CollectionView.ItemTemplate&amp;gt;&lt;/span&gt;
        &lt;span class="c"&gt;&amp;lt;!-- Item template --&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/CollectionView.ItemTemplate&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/CollectionView&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 5: Headers and Footers
&lt;/h2&gt;

&lt;p&gt;Converting headers and footers is straightforward:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Before (ListView):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;ListView&lt;/span&gt; &lt;span class="na"&gt;ItemsSource=&lt;/span&gt;&lt;span class="s"&gt;"{Binding Items}"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;ListView.Header&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;Label&lt;/span&gt; &lt;span class="na"&gt;Text=&lt;/span&gt;&lt;span class="s"&gt;"Items List"&lt;/span&gt; &lt;span class="na"&gt;FontSize=&lt;/span&gt;&lt;span class="s"&gt;"Large"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/ListView.Header&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;ListView.Footer&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;Label&lt;/span&gt; &lt;span class="na"&gt;Text=&lt;/span&gt;&lt;span class="s"&gt;"End of list"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/ListView.Footer&amp;gt;&lt;/span&gt;
    &lt;span class="c"&gt;&amp;lt;!-- Item template --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/ListView&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;After (CollectionView):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;CollectionView&lt;/span&gt; &lt;span class="na"&gt;ItemsSource=&lt;/span&gt;&lt;span class="s"&gt;"{Binding Items}"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;CollectionView.Header&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;Label&lt;/span&gt; &lt;span class="na"&gt;Text=&lt;/span&gt;&lt;span class="s"&gt;"Items List"&lt;/span&gt; &lt;span class="na"&gt;FontSize=&lt;/span&gt;&lt;span class="s"&gt;"Large"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/CollectionView.Header&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;CollectionView.Footer&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;Label&lt;/span&gt; &lt;span class="na"&gt;Text=&lt;/span&gt;&lt;span class="s"&gt;"End of list"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/CollectionView.Footer&amp;gt;&lt;/span&gt;
    &lt;span class="c"&gt;&amp;lt;!-- Item template --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/CollectionView&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 6: Take Advantage of New Layout Options
&lt;/h2&gt;

&lt;p&gt;One significant advantage of &lt;code&gt;CollectionView&lt;/code&gt; is its flexible layout options:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Vertical List (default):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;CollectionView&lt;/span&gt; &lt;span class="na"&gt;ItemsSource=&lt;/span&gt;&lt;span class="s"&gt;"{Binding Items}"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;CollectionView.ItemsLayout&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;LinearItemsLayout&lt;/span&gt; &lt;span class="na"&gt;Orientation=&lt;/span&gt;&lt;span class="s"&gt;"Vertical"&lt;/span&gt; &lt;span class="na"&gt;ItemSpacing=&lt;/span&gt;&lt;span class="s"&gt;"5"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/CollectionView.ItemsLayout&amp;gt;&lt;/span&gt;
    &lt;span class="c"&gt;&amp;lt;!-- Item template --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/CollectionView&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Horizontal List:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;CollectionView&lt;/span&gt; &lt;span class="na"&gt;ItemsSource=&lt;/span&gt;&lt;span class="s"&gt;"{Binding Items}"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;CollectionView.ItemsLayout&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;LinearItemsLayout&lt;/span&gt; &lt;span class="na"&gt;Orientation=&lt;/span&gt;&lt;span class="s"&gt;"Horizontal"&lt;/span&gt; &lt;span class="na"&gt;ItemSpacing=&lt;/span&gt;&lt;span class="s"&gt;"5"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/CollectionView.ItemsLayout&amp;gt;&lt;/span&gt;
    &lt;span class="c"&gt;&amp;lt;!-- Item template --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/CollectionView&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Grid Layout:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;CollectionView&lt;/span&gt; &lt;span class="na"&gt;ItemsSource=&lt;/span&gt;&lt;span class="s"&gt;"{Binding Items}"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;CollectionView.ItemsLayout&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;GridItemsLayout&lt;/span&gt; &lt;span class="na"&gt;Orientation=&lt;/span&gt;&lt;span class="s"&gt;"Vertical"&lt;/span&gt; 
                         &lt;span class="na"&gt;Span=&lt;/span&gt;&lt;span class="s"&gt;"2"&lt;/span&gt;
                         &lt;span class="na"&gt;HorizontalItemSpacing=&lt;/span&gt;&lt;span class="s"&gt;"5"&lt;/span&gt;
                         &lt;span class="na"&gt;VerticalItemSpacing=&lt;/span&gt;&lt;span class="s"&gt;"5"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/CollectionView.ItemsLayout&amp;gt;&lt;/span&gt;
    &lt;span class="c"&gt;&amp;lt;!-- Item template --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/CollectionView&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 7: Handle Empty State
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;CollectionView&lt;/code&gt; has better support for empty state handling:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;CollectionView&lt;/span&gt; &lt;span class="na"&gt;ItemsSource=&lt;/span&gt;&lt;span class="s"&gt;"{Binding Items}"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;CollectionView.EmptyView&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;StackLayout&lt;/span&gt; &lt;span class="na"&gt;Padding=&lt;/span&gt;&lt;span class="s"&gt;"20"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;Label&lt;/span&gt; &lt;span class="na"&gt;Text=&lt;/span&gt;&lt;span class="s"&gt;"No items available"&lt;/span&gt; 
                   &lt;span class="na"&gt;HorizontalOptions=&lt;/span&gt;&lt;span class="s"&gt;"Center"&lt;/span&gt;
                   &lt;span class="na"&gt;VerticalOptions=&lt;/span&gt;&lt;span class="s"&gt;"Center"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;Button&lt;/span&gt; &lt;span class="na"&gt;Text=&lt;/span&gt;&lt;span class="s"&gt;"Refresh"&lt;/span&gt; &lt;span class="na"&gt;Command=&lt;/span&gt;&lt;span class="s"&gt;"{Binding RefreshCommand}"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/StackLayout&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/CollectionView.EmptyView&amp;gt;&lt;/span&gt;
    &lt;span class="c"&gt;&amp;lt;!-- Item template --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/CollectionView&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Common Challenges and Solutions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Challenge 1: Context Actions
&lt;/h3&gt;

&lt;p&gt;ListView's &lt;code&gt;ContextActions&lt;/code&gt; don't have a direct equivalent in &lt;code&gt;CollectionView&lt;/code&gt;. Instead, you can use &lt;code&gt;SwipeView&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Before (ListView with ContextActions):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;ListView&lt;/span&gt; &lt;span class="na"&gt;ItemsSource=&lt;/span&gt;&lt;span class="s"&gt;"{Binding Items}"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;ListView.ItemTemplate&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;DataTemplate&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;ViewCell&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;ViewCell.ContextActions&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;MenuItem&lt;/span&gt; &lt;span class="na"&gt;Text=&lt;/span&gt;&lt;span class="s"&gt;"Edit"&lt;/span&gt; &lt;span class="na"&gt;Command=&lt;/span&gt;&lt;span class="s"&gt;"{Binding Source={RelativeSource AncestorType={x:Type vm:MyViewModel}}, Path=EditCommand}"&lt;/span&gt; &lt;span class="na"&gt;CommandParameter=&lt;/span&gt;&lt;span class="s"&gt;"{Binding .}"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;MenuItem&lt;/span&gt; &lt;span class="na"&gt;Text=&lt;/span&gt;&lt;span class="s"&gt;"Delete"&lt;/span&gt; &lt;span class="na"&gt;Command=&lt;/span&gt;&lt;span class="s"&gt;"{Binding Source={RelativeSource AncestorType={x:Type vm:MyViewModel}}, Path=DeleteCommand}"&lt;/span&gt; &lt;span class="na"&gt;CommandParameter=&lt;/span&gt;&lt;span class="s"&gt;"{Binding .}"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;/ViewCell.ContextActions&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;Label&lt;/span&gt; &lt;span class="na"&gt;Text=&lt;/span&gt;&lt;span class="s"&gt;"{Binding Title}"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/ViewCell&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/DataTemplate&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/ListView.ItemTemplate&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/ListView&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;After (CollectionView with SwipeView):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;CollectionView&lt;/span&gt; &lt;span class="na"&gt;ItemsSource=&lt;/span&gt;&lt;span class="s"&gt;"{Binding Items}"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;CollectionView.ItemTemplate&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;DataTemplate&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;SwipeView&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;SwipeView.RightItems&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;SwipeItems&amp;gt;&lt;/span&gt;
                        &lt;span class="nt"&gt;&amp;lt;SwipeItem&lt;/span&gt; &lt;span class="na"&gt;Text=&lt;/span&gt;&lt;span class="s"&gt;"Edit"&lt;/span&gt; 
                                   &lt;span class="na"&gt;Command=&lt;/span&gt;&lt;span class="s"&gt;"{Binding Source={RelativeSource AncestorType={x:Type vm:MyViewModel}}, Path=EditCommand}"&lt;/span&gt; 
                                   &lt;span class="na"&gt;CommandParameter=&lt;/span&gt;&lt;span class="s"&gt;"{Binding .}"&lt;/span&gt;
                                   &lt;span class="na"&gt;BackgroundColor=&lt;/span&gt;&lt;span class="s"&gt;"Blue"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
                        &lt;span class="nt"&gt;&amp;lt;SwipeItem&lt;/span&gt; &lt;span class="na"&gt;Text=&lt;/span&gt;&lt;span class="s"&gt;"Delete"&lt;/span&gt; 
                                   &lt;span class="na"&gt;Command=&lt;/span&gt;&lt;span class="s"&gt;"{Binding Source={RelativeSource AncestorType={x:Type vm:MyViewModel}}, Path=DeleteCommand}"&lt;/span&gt; 
                                   &lt;span class="na"&gt;CommandParameter=&lt;/span&gt;&lt;span class="s"&gt;"{Binding .}"&lt;/span&gt;
                                   &lt;span class="na"&gt;BackgroundColor=&lt;/span&gt;&lt;span class="s"&gt;"Red"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;/SwipeItems&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;/SwipeView.RightItems&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;Grid&lt;/span&gt; &lt;span class="na"&gt;Padding=&lt;/span&gt;&lt;span class="s"&gt;"10"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;Label&lt;/span&gt; &lt;span class="na"&gt;Text=&lt;/span&gt;&lt;span class="s"&gt;"{Binding Title}"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;/Grid&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/SwipeView&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/DataTemplate&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/CollectionView.ItemTemplate&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/CollectionView&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Challenge 2: HasUnevenRows
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;ListView&lt;/code&gt; had &lt;code&gt;HasUnevenRows&lt;/code&gt; for variable height rows. With &lt;code&gt;CollectionView&lt;/code&gt;, rows are automatically sized based on content:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Before (ListView):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;ListView&lt;/span&gt; &lt;span class="na"&gt;ItemsSource=&lt;/span&gt;&lt;span class="s"&gt;"{Binding Items}"&lt;/span&gt; &lt;span class="na"&gt;HasUnevenRows=&lt;/span&gt;&lt;span class="s"&gt;"True"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="c"&gt;&amp;lt;!-- Item template --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/ListView&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;After (CollectionView):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;CollectionView&lt;/span&gt; &lt;span class="na"&gt;ItemsSource=&lt;/span&gt;&lt;span class="s"&gt;"{Binding Items}"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="c"&gt;&amp;lt;!-- No equivalent property needed - it's the default behavior --&amp;gt;&lt;/span&gt;
    &lt;span class="c"&gt;&amp;lt;!-- Item template --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/CollectionView&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;With .NET 10 marking &lt;code&gt;ListView&lt;/code&gt; as obsolete, now is the ideal time to migrate your MAUI applications to use &lt;code&gt;CollectionView&lt;/code&gt;. The transition may require some initial effort, especially if you have complex templates or custom behaviors, but the benefits are substantial. &lt;code&gt;CollectionView&lt;/code&gt; offers better performance, more flexible layouts, and an overall improved developer experience.&lt;/p&gt;

&lt;p&gt;The migration process outlined in this article provides a straightforward path to update your applications, covering the most common scenarios you'll encounter. By embracing &lt;code&gt;CollectionView&lt;/code&gt; now, you'll future-proof your applications and take advantage of the enhancements that Microsoft continues to make to this control.&lt;/p&gt;

&lt;p&gt;Remember that while the obsolescence marking begins with .NET 10 Preview 3, &lt;code&gt;ListView&lt;/code&gt; will continue to function in .NET 10, giving you some time to complete your migration. However, bug fixes for &lt;code&gt;ListView&lt;/code&gt; will generally not be prioritized, so it's best to start the transition sooner rather than later.&lt;/p&gt;

&lt;p&gt;Have you encountered any specific challenges in migrating from &lt;code&gt;ListView&lt;/code&gt; to &lt;code&gt;CollectionView&lt;/code&gt;? Let me know in the comments below, and let's work through them together!&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>dotnetmaui</category>
    </item>
    <item>
      <title>Delete bin and obj Folders in .NET MAUI</title>
      <dc:creator>Victor Hugo Garcia</dc:creator>
      <pubDate>Mon, 27 Jan 2025 03:53:10 +0000</pubDate>
      <link>https://dev.to/vhugogarcia/delete-bin-and-obj-folders-in-net-maui-3j1e</link>
      <guid>https://dev.to/vhugogarcia/delete-bin-and-obj-folders-in-net-maui-3j1e</guid>
      <description>&lt;p&gt;Every .NET and .NET MAUI developer has encountered that moment when mysterious build issues appear, and the age-old advice rings true: "Have you tried deleting your bin and obj folders?" These folders, while essential for storing compiled builds and cache files, can sometimes cause headaches during development.&lt;/p&gt;

&lt;p&gt;Today, I'm excited to introduce a simple yet powerful &lt;a href="https://marketplace.visualstudio.com/items?itemName=vhugogarcia.delete-bin-obj" rel="noopener noreferrer"&gt;Visual Studio Code extension&lt;/a&gt; that streamlines this common cleanup task for .NET developers.&lt;/p&gt;




&lt;h3&gt;
  
  
  Real-life Scenarios
&lt;/h3&gt;

&lt;p&gt;When starting a new project in .NET MAUI, setting up the app icon or splash screen is an important step. This often involves ensuring the design meets the right specifications, such as proper padding, sizing, and background color. If you find that changes aren’t reflecting as expected after deleting the app from the emulator or device, it’s a good idea to clear the associated folders as well. This ensures the updates are applied correctly and avoids potential design inconsistencies.&lt;/p&gt;

&lt;h3&gt;
  
  
  How to Use the "Delete Bin and Obj Folders" Extension
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;1. Install the extension&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Open the Extensions panel in Visual Studio Code.&lt;/li&gt;
&lt;li&gt;Search for Delete Bin.&lt;/li&gt;
&lt;li&gt;Find "Delete Bin and Obj Folders" by vhugogarcia and click Install.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fakx7ubg44cle9hx3dhpe.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fakx7ubg44cle9hx3dhpe.png" alt="Extensions Panel" width="594" height="308"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. On the Explorer window&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Right-click the folder where you would like to delete the /bin and /obj folders&lt;/li&gt;
&lt;li&gt;Click the option: "Delete /bin and /obj Folders"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnfb4ra76mkzjetijtkzo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnfb4ra76mkzjetijtkzo.png" alt="Context Menu Option" width="800" height="72"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3.Rebuild and Keep Coding&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Rebuild your project to generate fresh build files
You’ll be starting from a clean slate, ready to tackle the next coding challenge.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;The Delete Bin and Obj Folders extension is all about keeping things simple and saving you time. It’s a small but powerful extension that helps .NET developers like you and me to run our .NET app with a fresh build and generated cache files. While it may seem like a small change, saving a couple of clicks and the time spent searching for those folders can add up. Over time, this extension will save you precious seconds and minutes, making your workflow smoother and more efficient.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://marketplace.visualstudio.com/items?itemName=vhugogarcia.delete-bin-obj" rel="noopener noreferrer"&gt;Download the extension&lt;/a&gt; now and see how much easier it makes your day-to-day development. And if you enjoy using it, don’t forget to leave a review, contribute, share your feedback—it means the world and helps me create even better tools for our community!&lt;/p&gt;

&lt;p&gt;Follow me on Social:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;LinkedIn &lt;strong&gt;&lt;a href="https://www.linkedin.com/in/victorhugogarcia/" rel="noopener noreferrer"&gt;victorhugogarcia&lt;/a&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Bluesky &lt;strong&gt;&lt;a href="https://bsky.app/profile/vhugogarcia.bsky.social" rel="noopener noreferrer"&gt;vhugogarcia.bsky.social&lt;/a&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;GitHub &lt;strong&gt;&lt;a href="https://github.com/vhugogarcia" rel="noopener noreferrer"&gt;@vhugogarcia&lt;/a&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;X &lt;strong&gt;&lt;a href="https://twitter.com/ivictorhugo" rel="noopener noreferrer"&gt;@ivictorhugo&lt;/a&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>dotnet</category>
      <category>vscode</category>
      <category>dotnetmaui</category>
    </item>
    <item>
      <title>Align the Button Text in .NET MAUI</title>
      <dc:creator>Victor Hugo Garcia</dc:creator>
      <pubDate>Thu, 09 Jan 2025 19:22:13 +0000</pubDate>
      <link>https://dev.to/vhugogarcia/align-the-button-text-in-net-maui-1900</link>
      <guid>https://dev.to/vhugogarcia/align-the-button-text-in-net-maui-1900</guid>
      <description>&lt;p&gt;Mobile app developers often encounter seemingly simple UI challenges that require platform-specific solutions. One such challenge is the proper alignment of button text across iOS and Android platforms in .NET MAUI applications. In this article, we'll explore how to achieve precise control over button text alignment in .NET MAUI by leveraging custom handlers.&lt;/p&gt;




&lt;h3&gt;
  
  
  Create a static class FormHandler
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.Maui&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Drawing&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="cp"&gt;#if IOS
&lt;/span&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;UIKit&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Foundation&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="cp"&gt;#endif
&lt;/span&gt;
&lt;span class="cp"&gt;#if ANDROID
&lt;/span&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.Maui.Controls.Compatibility.Platform.Android&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="cp"&gt;#endif
&lt;/span&gt;
&lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;DemoApp.Handlers&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;FormHandler&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;AlignButtonTextToLeftBottom&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Microsoft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Maui&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Handlers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ButtonHandler&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Mapper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AppendToMapping&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ButtonTextAlignmentToLeftBottom"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;view&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
       &lt;span class="p"&gt;{&lt;/span&gt;
         &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;view&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="n"&gt;Button&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ClassId&lt;/span&gt;&lt;span class="p"&gt;==&lt;/span&gt;&lt;span class="s"&gt;"ButtonTextAlignmentToLeftBottom"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
         &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="cp"&gt;#if IOS
&lt;/span&gt;        &lt;span class="n"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PlatformView&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;VerticalAlignment&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;UIControlContentVerticalAlignment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Bottom&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PlatformView&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HorizontalAlignment&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;UIControlContentHorizontalAlignment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Left&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="cp"&gt;#elif ANDROID
&lt;/span&gt;        &lt;span class="n"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PlatformView&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Gravity&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Android&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Views&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GravityFlags&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Left&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="n"&gt;Android&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Views&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GravityFlags&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Bottom&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="cp"&gt;#endif
&lt;/span&gt;        &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;In certain scenarios you may need to apply the alignment only to a single button on your UI, if that is the case you can use the ClassId property. This way the style will be applied for only those elements with the defined ClassId, otherwise, just remove the conditional from the code above. Thanks to our friend &lt;a href="https://github.com/MarcAlx" rel="noopener noreferrer"&gt;MarcAlx&lt;/a&gt; for sharing this idea.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;Button&lt;/span&gt; &lt;span class="na"&gt;ClassId=&lt;/span&gt;&lt;span class="s"&gt;"ButtonTextAlignmentToLeftBottom"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Register the handler
&lt;/h4&gt;

&lt;p&gt;On the MauiProgram.cs file register the handler&lt;br&gt;
&lt;code&gt;FormHandler.AlignButtonTextToLeftBottom();&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;Custom handlers in .NET MAUI provide the flexibility needed to fine-tune platform-specific behaviors while maintaining a clean, cross-platform codebase. By implementing these solutions for button text alignment, we've not only solved an immediate visual challenge but also demonstrated the power and versatility of MAUI's handler architecture. Whether you're aiming for center-aligned text, left-justified content, or any specific style, I hope this guide will help you implement it seamlessly.&lt;/p&gt;

&lt;p&gt;Follow me on Social:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;LinkedIn &lt;strong&gt;&lt;a href="https://www.linkedin.com/in/victorhugogarcia/" rel="noopener noreferrer"&gt;victorhugogarcia&lt;/a&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Bluesky &lt;strong&gt;&lt;a href="https://bsky.app/profile/vhugogarcia.bsky.social" rel="noopener noreferrer"&gt;vhugogarcia.bsky.social&lt;/a&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;GitHub &lt;strong&gt;&lt;a href="https://github.com/vhugogarcia" rel="noopener noreferrer"&gt;@vhugogarcia&lt;/a&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Threads  &lt;strong&gt;&lt;a href="https://www.threads.net/@ihugo" rel="noopener noreferrer"&gt;@ihugo&lt;/a&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;X &lt;strong&gt;&lt;a href="https://twitter.com/ivictorhugo" rel="noopener noreferrer"&gt;@ivictorhugo&lt;/a&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>dotnet</category>
      <category>dotnetmaui</category>
      <category>ios</category>
      <category>android</category>
    </item>
    <item>
      <title>Stay Ahead of the Curve: Embrace .NET MAUI for .NET 9</title>
      <dc:creator>Victor Hugo Garcia</dc:creator>
      <pubDate>Tue, 12 Nov 2024 14:51:33 +0000</pubDate>
      <link>https://dev.to/vhugogarcia/stay-ahead-of-the-curve-embrace-net-maui-for-net-9-5ad5</link>
      <guid>https://dev.to/vhugogarcia/stay-ahead-of-the-curve-embrace-net-maui-for-net-9-5ad5</guid>
      <description>&lt;p&gt;As the landscape of mobile app development continues to evolve, staying up-to-date with the latest tools and frameworks is crucial for maintaining a competitive edge. One of the latest advancements in this realm is .NET MAUI for .NET 9, a significant upgrade that offers a plethora of new features and improvements. This blog post will delve into why upgrading to .NET MAUI for .NET 9 is a smart move for your development team and explain why the transition to .NET 9, even if it’s a &lt;a href="https://dotnet.microsoft.com/en-us/platform/support/policy/dotnet-core" rel="noopener noreferrer"&gt;Standard Term Support (STS)&lt;/a&gt; release, aligns well with the fast-paced nature of mobile app updates.&lt;/p&gt;

&lt;h2&gt;
  
  
  Benefits
&lt;/h2&gt;

&lt;h4&gt;
  
  
  Enhanced Performance and Stability
&lt;/h4&gt;

&lt;p&gt;One of the most compelling reasons to upgrade to .NET MAUI for .NET 9 is the enhanced performance and stability it offers. The new version includes optimizations that make your applications run smoother and faster. This can lead to a better user experience, which is essential for retaining and engaging users.&lt;/p&gt;

&lt;h4&gt;
  
  
  Improved Developer Experience
&lt;/h4&gt;

&lt;p&gt;Introduces several new controls and features that streamline the development process. This includes a &lt;a href="https://learn.microsoft.com/en-us/dotnet/maui/whats-new/dotnet-9?view=net-maui-8.0#new-controls" rel="noopener noreferrer"&gt;Hybrid WebView&lt;/a&gt;, &lt;a href="https://dev.toTitlebar%20for%20Windows"&gt;Title Bar for Windows&lt;/a&gt;, etc.&lt;/p&gt;

&lt;h4&gt;
  
  
  Control Enhancements
&lt;/h4&gt;

&lt;p&gt;The latest release includes a variety of new control enhancements such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;BackButtonBehavior OneWay binding mode&lt;/li&gt;
&lt;li&gt;On iOS and Mac Catalyst 18, .NET MAUI for .NET 9 changes the default behavior for hosting content in a BlazorWebView to localhost.&lt;/li&gt;
&lt;li&gt;Button controls on iOS now respect spacing, padding, border width, and margins more accurately than in previous releases&lt;/li&gt;
&lt;li&gt;Performance and stability improvements to CollectionView and CarouselView&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Please refer to the &lt;a href="https://learn.microsoft.com/en-us/dotnet/maui/whats-new/dotnet-9?view=net-maui-8.0#control-enhancements" rel="noopener noreferrer"&gt;official documentation&lt;/a&gt; to find out the full list of control enhancements.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Standard Term Support (STS) .NET 9 is Suitable for Mobile Development
&lt;/h2&gt;

&lt;p&gt;In the world of mobile app development, updates and new features are rolled out frequently to keep up with user expectations and market trends. Because of this, upgrading to a Standard Term Support (STS) release like .NET 9 is less of a burden than it might be in other types of software development. Mobile apps are typically updated often, which means that staying on top of the latest tools and frameworks is already a part of the development cycle. Adopting .NET 9 ensures you have access to the latest improvements and security updates, which can be critical for maintaining the quality and security of your applications.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Packages Compatibility&lt;/strong&gt;&lt;br&gt;
When it comes to package compatibility, you'll be glad to know that packages supporting .NET 6 are generally compatible with .NET 9, unless there are specific dependencies that might hinder this compatibility. In such cases, it’s worth checking if you can upgrade the package to the latest version that supports .NET 8. You might also consider reaching out to the package developer for an update or, even better, contributing to the package yourself if it’s open-source, to ensure .NET compatibility.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Upgrading to .NET MAUI for .NET 9 offers numerous benefits, from enhanced performance and developer experience to advanced UI components and better cross-platform capabilities. In the rapidly evolving field of mobile development, taking advantage of the latest tools and frameworks is essential for staying competitive. Given the frequent updates in the mobile app world, transitioning to an Standard Term Support (STS) release like .NET 9 aligns perfectly with the fast-paced development cycle, ensuring your applications remain cutting-edge and secure.&lt;/p&gt;

&lt;p&gt;Embrace the future of mobile app development with .NET MAUI for .NET 9 and keep your applications at the forefront of technology.&lt;/p&gt;

&lt;p&gt;Happy upgrade and may your apps load faster!&lt;/p&gt;

&lt;p&gt;Follow me on Social:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;LinkedIn &lt;strong&gt;&lt;a href="https://www.linkedin.com/in/victorhugogarcia/" rel="noopener noreferrer"&gt;victorhugogarcia&lt;/a&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Bluesky &lt;strong&gt;&lt;a href="https://bsky.app/profile/vhugogarcia.bsky.social" rel="noopener noreferrer"&gt;vhugogarcia.bsky.social&lt;/a&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;GitHub &lt;strong&gt;&lt;a href="https://github.com/vhugogarcia" rel="noopener noreferrer"&gt;@vhugogarcia&lt;/a&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Threads  &lt;strong&gt;&lt;a href="https://www.threads.net/@ihugo" rel="noopener noreferrer"&gt;@ihugo&lt;/a&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;X &lt;strong&gt;&lt;a href="https://twitter.com/ivictorhugo" rel="noopener noreferrer"&gt;@ivictorhugo&lt;/a&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>dotnet</category>
      <category>dotnetmaui</category>
      <category>mobile</category>
    </item>
    <item>
      <title>Loading State for Images in .NET MAUI</title>
      <dc:creator>Victor Hugo Garcia</dc:creator>
      <pubDate>Thu, 31 Oct 2024 17:41:09 +0000</pubDate>
      <link>https://dev.to/vhugogarcia/loading-state-for-images-in-net-maui-28ng</link>
      <guid>https://dev.to/vhugogarcia/loading-state-for-images-in-net-maui-28ng</guid>
      <description>&lt;p&gt;Handling the loading state for images can significantly enhance the user experience in any application. In this post, we will explore how to implement a loading indicator when images are being fetched and displayed in .NET MAUI for iOS, Windows, macOS and Android platforms. Leveraging Control Reference Bindings, we'll ensure that your app feels smooth and responsive even when dealing with heavy image loading tasks.&lt;/p&gt;

&lt;h2&gt;
  
  
  Special Thanks
&lt;/h2&gt;

&lt;p&gt;A huge shoutout to my friend Gerald Versluis for his insightful video on using &lt;a href="https://www.youtube.com/watch?v=PH9_bPu-ImQ" rel="noopener noreferrer"&gt;Control Reference Bindings&lt;/a&gt;. His guidance has been invaluable in making this implementation a reality.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementation
&lt;/h2&gt;

&lt;p&gt;You can implement the loading state either on a Single Image, CarouselView, or CollectionView. In the example below, we are going to use a CarouselView:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;CarouselView&lt;/span&gt;
    &lt;span class="na"&gt;VerticalOptions=&lt;/span&gt;&lt;span class="s"&gt;"Start"&lt;/span&gt;
    &lt;span class="na"&gt;Loop=&lt;/span&gt;&lt;span class="s"&gt;"False"&lt;/span&gt;
    &lt;span class="na"&gt;HeightRequest=&lt;/span&gt;&lt;span class="s"&gt;"256"&lt;/span&gt;
    &lt;span class="na"&gt;IsBounceEnabled=&lt;/span&gt;&lt;span class="s"&gt;"True"&lt;/span&gt;
    &lt;span class="na"&gt;PeekAreaInsets=&lt;/span&gt;&lt;span class="s"&gt;"30"&lt;/span&gt;
    &lt;span class="na"&gt;BackgroundColor=&lt;/span&gt;&lt;span class="s"&gt;"Transparent"&lt;/span&gt;
    &lt;span class="na"&gt;ItemsSource=&lt;/span&gt;&lt;span class="s"&gt;"{Binding Images}"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;CarouselView.ItemsLayout&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;LinearItemsLayout&lt;/span&gt;
            &lt;span class="na"&gt;Orientation=&lt;/span&gt;&lt;span class="s"&gt;"Horizontal"&lt;/span&gt;
            &lt;span class="na"&gt;ItemSpacing=&lt;/span&gt;&lt;span class="s"&gt;"10"&lt;/span&gt;
            &lt;span class="na"&gt;SnapPointsType=&lt;/span&gt;&lt;span class="s"&gt;"Mandatory"&lt;/span&gt;
            &lt;span class="na"&gt;SnapPointsAlignment=&lt;/span&gt;&lt;span class="s"&gt;"Start"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/CarouselView.ItemsLayout&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;CarouselView.ItemTemplate&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;DataTemplate&lt;/span&gt; &lt;span class="na"&gt;x:DataType=&lt;/span&gt;&lt;span class="s"&gt;"models:Demo"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;Grid&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;Image&lt;/span&gt;
                    &lt;span class="na"&gt;x:Name=&lt;/span&gt;&lt;span class="s"&gt;"MainImage"&lt;/span&gt;
                    &lt;span class="na"&gt;Aspect=&lt;/span&gt;&lt;span class="s"&gt;"AspectFill"&lt;/span&gt;
                    &lt;span class="na"&gt;Source=&lt;/span&gt;&lt;span class="s"&gt;"{Binding ImageUrl}"&lt;/span&gt;
                    &lt;span class="na"&gt;HeightRequest=&lt;/span&gt;&lt;span class="s"&gt;"180"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;ActivityIndicator&lt;/span&gt;
                    &lt;span class="na"&gt;HeightRequest=&lt;/span&gt;&lt;span class="s"&gt;"32"&lt;/span&gt;
                    &lt;span class="na"&gt;WidthRequest=&lt;/span&gt;&lt;span class="s"&gt;"32"&lt;/span&gt;
                    &lt;span class="na"&gt;VerticalOptions=&lt;/span&gt;&lt;span class="s"&gt;"Center"&lt;/span&gt;
                    &lt;span class="na"&gt;Margin=&lt;/span&gt;&lt;span class="s"&gt;"0,0,0,0"&lt;/span&gt;
                    &lt;span class="na"&gt;HorizontalOptions=&lt;/span&gt;&lt;span class="s"&gt;"Center"&lt;/span&gt;
                    &lt;span class="na"&gt;IsRunning=&lt;/span&gt;&lt;span class="s"&gt;"{Binding IsLoading, Source={x:Reference MainImage}}"&lt;/span&gt;
                    &lt;span class="na"&gt;IsVisible=&lt;/span&gt;&lt;span class="s"&gt;"{Binding IsLoading, Source={x:Reference MainImage}}"&lt;/span&gt;
                    &lt;span class="na"&gt;Color=&lt;/span&gt;&lt;span class="s"&gt;"#000000"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/Grid&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/DataTemplate&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/CarouselView.ItemTemplate&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/CarouselView&amp;gt;&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Implementing a loading indicator for images in your .NET MAUI application can greatly enhance the user experience by providing visual feedback during image loading. This tutorial demonstrated how to achieve this using Control Reference Bindings for both all supported platforms. By leveraging the IsLoading property of the Image control, you can ensure that your app remains responsive and user-friendly.&lt;/p&gt;

&lt;p&gt;For more detailed information on the IsLoading property, please refer to the &lt;a href="https://learn.microsoft.com/en-us/dotnet/api/microsoft.maui.controls.image.isloading?view=net-maui-8.0" rel="noopener noreferrer"&gt;official Microsoft documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Happy coding and may your apps load smoothly!&lt;/p&gt;

&lt;p&gt;Follow me on Social:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;LinkedIn &lt;strong&gt;&lt;a href="https://www.linkedin.com/in/victorhugogarcia/" rel="noopener noreferrer"&gt;victorhugogarcia&lt;/a&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;GitHub &lt;strong&gt;&lt;a href="https://github.com/vhugogarcia" rel="noopener noreferrer"&gt;@vhugogarcia&lt;/a&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Threads  &lt;strong&gt;&lt;a href="https://www.threads.net/@ihugo" rel="noopener noreferrer"&gt;@ihugo&lt;/a&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;X &lt;strong&gt;&lt;a href="https://twitter.com/ivictorhugo" rel="noopener noreferrer"&gt;@ivictorhugo&lt;/a&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>dotnet</category>
      <category>dotnetmaui</category>
      <category>vscode</category>
    </item>
    <item>
      <title>Solving .NET MAUI Issues on macOS Sequoia with Visual Studio Code and XCode 16</title>
      <dc:creator>Victor Hugo Garcia</dc:creator>
      <pubDate>Thu, 19 Sep 2024 14:22:28 +0000</pubDate>
      <link>https://dev.to/vhugogarcia/solving-net-maui-issues-on-macos-sequoia-with-visual-studio-code-and-xcode-16-3ljd</link>
      <guid>https://dev.to/vhugogarcia/solving-net-maui-issues-on-macos-sequoia-with-visual-studio-code-and-xcode-16-3ljd</guid>
      <description>&lt;p&gt;Developing cross-platform mobile applications with .NET MAUI can be a rewarding experience, but it comes with its own set of challenges, especially when Apple releases a new version of macOS and XCode. In this blog post, I will share my personal journey of overcoming a specific issue that I encountered while trying to develop my .NET MAUI mobile app projects. Whether you’re a seasoned developer or just starting out, I hope my insights and solutions will help you navigate similar challenges and streamline your development process. Let’s dive in and explore how to get your .NET MAUI projects up and running smoothly on macOS Sequoia!&lt;/p&gt;




&lt;h2&gt;
  
  
  Tips Before Start
&lt;/h2&gt;

&lt;p&gt;Based on my experience developing mobile apps in .NET MAUI, here are a few key tips to keep in mind:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Disable macOS automatic updates&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Disable App Store automatic updates&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Enable notifications from the &lt;a href="https://github.com/xamarin/xamarin-macios" rel="noopener noreferrer"&gt;macios&lt;/a&gt; official repository&lt;/strong&gt; and regularly check for updates, especially when a new major macOS or Xcode release is approaching.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Updates
&lt;/h2&gt;

&lt;h4&gt;
  
  
  #1
&lt;/h4&gt;

&lt;p&gt;On September 26, 2024 - The macios team released the official support for macOS Sequoia, and XCode 16 in .NET 8 &lt;a href="https://github.com/xamarin/xamarin-macios/releases/tag/dotnet-8.0.1xx-xcode16.0-8303" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  #2
&lt;/h4&gt;

&lt;p&gt;If you face the following issue with the provisioning profiles:&lt;br&gt;
&lt;code&gt;The specified iOS provisioning profile '**********' could not be found&lt;/code&gt;, the solution that worked for me was to move them from &lt;em&gt;~/Library/Developer/Xcode/UserData/Provisioning  Profiles&lt;/em&gt; To &lt;em&gt;~/Library/MobileDevice/Provisioning Profiles&lt;/em&gt;, thanks to &lt;a href="https://github.com/vedatozkanTr" rel="noopener noreferrer"&gt;@vedatozkanTr&lt;/a&gt; for the help.&lt;/p&gt;
&lt;h4&gt;
  
  
  #3
&lt;/h4&gt;

&lt;p&gt;The following error may re-appear when building using XCode 16: &lt;code&gt;strip exited with code 139&lt;/code&gt;, the solution I applied was found on this &lt;a href="https://github.com/xamarin/xamarin-macios/issues/19157" rel="noopener noreferrer"&gt;post&lt;/a&gt;, what I did was just update the .csproj file and added the following property group:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;PropertyGroup&lt;/span&gt; &lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;MtouchNoSymbolStrip&lt;/span&gt; &lt;span class="na"&gt;Condition=&lt;/span&gt;&lt;span class="s"&gt;"$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'ios'"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;True&lt;span class="nt"&gt;&amp;lt;/MtouchNoSymbolStrip&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/PropertyGroup&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  The Issue
&lt;/h2&gt;

&lt;p&gt;While working on the latest version of macOS, I discovered that XCode 15.4 was incompatible, necessitating an upgrade to XCode 16. However, after updating, .NET MAUI stopped working due to compatibility issues.&lt;/p&gt;

&lt;h2&gt;
  
  
  How To Solve It
&lt;/h2&gt;

&lt;p&gt;There is an &lt;a href="https://github.com/xamarin/xamarin-macios/issues/20802" rel="noopener noreferrer"&gt;issue&lt;/a&gt; created a few months ago on the macios repository. This issue outlines the official recommendations, and helps to ask questions so other friends can provide some workarounds that may work for you. &lt;/p&gt;

&lt;h3&gt;
  
  
  Visual Studio Code
&lt;/h3&gt;

&lt;p&gt;If you are using Visual Studio Code to develop .NET MAUI projects, you might encounter a couple of issues after updating to macOS Sequoia. Below are the issues I found and their respective solutions:&lt;/p&gt;

&lt;h4&gt;
  
  
  Could not find the task 'maui: Build'
&lt;/h4&gt;

&lt;p&gt;This particular error is due to a &lt;a href="https://github.com/microsoft/vscode-dotnettools/issues/1449" rel="noopener noreferrer"&gt;known issue&lt;/a&gt; on the .NET MAUI extension with the HotReload feature. &lt;strong&gt;Solution:&lt;/strong&gt; Our friend &lt;a href="https://github.com/BretJohnson" rel="noopener noreferrer"&gt;BretJohnson&lt;/a&gt; recommended disabling XAML Hot Reload and see if the problem goes away. Uncheck the user preferences checkbox shown here. &lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F15uznd8lm7r9or3teycn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F15uznd8lm7r9or3teycn.png" alt=" " width="800" height="133"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  XCode Versions
&lt;/h3&gt;

&lt;p&gt;Our friend &lt;a href="https://github.com/BrandanN21" rel="noopener noreferrer"&gt;BrandanN21&lt;/a&gt; recommended to downgrade my xcode version by installing it via the &lt;a href="https://developer.apple.com/download/all/" rel="noopener noreferrer"&gt;Apple Developer Portal&lt;/a&gt; and finding xcode 15.4, you can have multiple xcode installs at the same time. To have multiple xcode installs at the same time, follow these steps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Once you download the .xip file from the portal, uncompress it, and the XCode.app file rename it to XCode_15.4.app&lt;/li&gt;
&lt;li&gt;Move the renamed XCode app to the Applications folder&lt;/li&gt;
&lt;li&gt;Make sure you have both XCode versions as shown here:
&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhxwbjcucmp6mvztwf36x.png" alt=" " width="314" height="72"&gt;
&lt;/li&gt;
&lt;li&gt;Open the terminal and execute the following command: &lt;code&gt;/Applications/Xcode_15.4.app/Contents/MacOS/Xcode&lt;/code&gt; this command will open XCode 15.4 correctly&lt;/li&gt;
&lt;li&gt;Go to XCode menu and click the Settings option, then go to the Locations tab and make sure to select the correct command line tools version 15.4 as shown here:
&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbzwbwpvz4ztrmfhdrc1c.png" alt=" " width="746" height="112"&gt;
&lt;/li&gt;
&lt;li&gt;Close XCode and the terminal&lt;/li&gt;
&lt;li&gt;Open the terminal again and run the following command:&lt;code&gt;xcode-select --print-path&lt;/code&gt; it should display /Applications/Xcode_15.4.app/Contents/Developer this confirms you have the correct xcode version selected as default.&lt;/li&gt;
&lt;li&gt;Now run your app by selecting the correct simulator and that's all.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; I did not install the iOS 18 simulators, since I will wait for the official support in .NET MAUI macios.&lt;/p&gt;

&lt;h2&gt;
  
  
  Additional Workarounds and Resources
&lt;/h2&gt;

&lt;p&gt;I recommend you to follow this &lt;a href="https://github.com/xamarin/xamarin-macios/issues/20802" rel="noopener noreferrer"&gt;issue thread&lt;/a&gt; to find out other workarounds that may work for you if you are using Visual Studio for Mac or Rider. A lot of friends are posting their solutions and changes they applied to solve this compatibility issue.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;By staying proactive and informed, you can overcome compatibility issues and ensure a smooth development process. Remember to disable automatic updates, stay connected with the macios community, and leverage the collective knowledge available to you.&lt;/p&gt;

&lt;p&gt;Microsoft is expected to release the official XCode 16 support on November this year. &lt;/p&gt;

&lt;p&gt;I would like also to &lt;strong&gt;thank everybody on the GitHub&lt;/strong&gt; issues who posted the workarounds and feedback, they truly helped me to workaround the issue.&lt;/p&gt;

&lt;p&gt;Follow me on social:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;LinkedIn &lt;a href="https://www.linkedin.com/in/victorhugogarcia/" rel="noopener noreferrer"&gt;victorhugogarcia&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;GitHub &lt;a href="https://github.com/vhugogarcia" rel="noopener noreferrer"&gt;vhugogarcia&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>dotnet</category>
      <category>dotnetmaui</category>
      <category>vscode</category>
    </item>
    <item>
      <title>Mastering Error Insights in .NET MAUI: Sentry vs. Firebase Crashlytics</title>
      <dc:creator>Victor Hugo Garcia</dc:creator>
      <pubDate>Mon, 22 Jul 2024 19:46:20 +0000</pubDate>
      <link>https://dev.to/vhugogarcia/mastering-error-insights-in-net-maui-sentry-vs-firebase-crashlytics-5aj3</link>
      <guid>https://dev.to/vhugogarcia/mastering-error-insights-in-net-maui-sentry-vs-firebase-crashlytics-5aj3</guid>
      <description>&lt;p&gt;As the .NET MAUI ecosystem gains momentum, developers are keen to adopt robust error monitoring solutions for their mobile apps. Two popular contenders in this space are &lt;a href="https://sentry.io/" rel="noopener noreferrer"&gt;Sentry&lt;/a&gt; and &lt;a href="https://firebase.google.com/docs/crashlytics/" rel="noopener noreferrer"&gt;Firebase Crashlytics&lt;/a&gt;. In this article, we’ll explore why Sentry stands out as a powerful choice for capturing both managed and unmanaged errors in .NET MAUI applications.&lt;/p&gt;




&lt;h2&gt;
  
  
  Features Comparison
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;Sentry&lt;/th&gt;
&lt;th&gt;Firebase Crashlytics&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Target Audience&lt;/td&gt;
&lt;td&gt;Growing teams requiring deeper context, insights, and customizable workflow tools.&lt;/td&gt;
&lt;td&gt;Hobbyists, solopreneurs, and small teams.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Insights &amp;amp; Context&lt;/td&gt;
&lt;td&gt;Provides detailed insights into solving crashes and errors.&lt;/td&gt;
&lt;td&gt;Offers basic crash reporting and error tracking.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Custom Workflow Tools&lt;/td&gt;
&lt;td&gt;Customizable workflow tools for efficient issue management.&lt;/td&gt;
&lt;td&gt;Limited customization options.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Product Investments&lt;/td&gt;
&lt;td&gt;Enables innovation and scalability through product investments.&lt;/td&gt;
&lt;td&gt;Basic functionality without extensive investment.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Real-time Monitoring&lt;/td&gt;
&lt;td&gt;Real-time monitoring of app health and performance.&lt;/td&gt;
&lt;td&gt;Real-time crash reporting.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;These service features are pointing out for .NET MAUI applications.&lt;/p&gt;

&lt;h2&gt;
  
  
  Personal Experience
&lt;/h2&gt;

&lt;p&gt;While developing mobile apps in .NET MAUI, I found out Sentry to be better than Firebase Crashlytics in a few areas outlined below:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Contexts&lt;/strong&gt;,
It is a powerful way to see and track custom data from the device itself, also user information by allowing to set custom context of a given event. As developers, as much context we get of the error such as environment, culture, etc. the better. So, context are really useful.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Breadcrumbs&lt;/strong&gt;,
We all know what breadcrumbs are for websites, in Sentry, we get these to understand from start to end, when the app started and the crash occurred, you see a graphical UI with the series of events that are helpful.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;.NET Full Stack Trace&lt;/strong&gt;,
This is probably the most wanted feature for error handling, for us as .NET developers, if we know on which code line the exception occurred then that will help us a lot.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Free for one user&lt;/strong&gt;, this means only one user per Sentry account, which is fine for most of the cases.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For Firebase Crashlytics, I found out a lot of issues trying to set the proper Bindings for iOS particularly, however, our friends Tobias and Adam helped a lot with this, but at the end it is limited on features, and most important the .NET Stack Trace. &lt;/p&gt;

&lt;h2&gt;
  
  
  Implementation
&lt;/h2&gt;

&lt;p&gt;This is pretty easy, basically add the following NuGet package into your .csproj file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;PackageReference&lt;/span&gt; &lt;span class="na"&gt;Include=&lt;/span&gt;&lt;span class="s"&gt;"Sentry.Maui"&lt;/span&gt; &lt;span class="na"&gt;Version=&lt;/span&gt;&lt;span class="s"&gt;"4.9.0"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then configure it on the startup:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Add this section anywhere on the builder:&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UseSentry&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// The DSN is the only required setting.&lt;/span&gt;
            &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Dsn&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"https://XXXXXXXXXXXX.ingest.us.sentry.io/XXXXXXX"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

            &lt;span class="c1"&gt;// Use debug mode if you want to see what the SDK is doing.&lt;/span&gt;
            &lt;span class="c1"&gt;// Debug messages are written to stdout with Console.Writeline,&lt;/span&gt;
            &lt;span class="c1"&gt;// and are viewable in your IDE's debug console or with 'adb logcat', etc.&lt;/span&gt;
            &lt;span class="c1"&gt;// This option is not recommended when deploying your application.&lt;/span&gt;
            &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Debug&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

            &lt;span class="c1"&gt;// Set TracesSampleRate to 1.0 to capture 100% of transactions for tracing.&lt;/span&gt;
            &lt;span class="c1"&gt;// We recommend adjusting this value in production.&lt;/span&gt;
            &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TracesSampleRate&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;1.0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

            &lt;span class="c1"&gt;// Other Sentry options can be set here.&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The official documentation can be found &lt;a href="https://docs.sentry.io/platforms/dotnet/guides/maui/" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  One More Thing
&lt;/h2&gt;

&lt;p&gt;It may happen that when using Sentry on debug mode you get an exception when running on emulators, to solve this issue, what I did was just to set the directive #IF RELEASE so it loads Sentry on release mode only.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In the ever-evolving world of .NET MAUI development, choosing the right error monitoring tool can make a significant difference. While Firebase Crashlytics offers a straightforward solution for basic crash reporting, Sentry stands out with its comprehensive insights and customizable workflow tools. By opting for Sentry, you equip your team with the power to swiftly identify and resolve issues, ensuring a smoother and more reliable user experience.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>ObservableRangeCollection in .NET MAUI</title>
      <dc:creator>Victor Hugo Garcia</dc:creator>
      <pubDate>Tue, 16 Apr 2024 13:27:54 +0000</pubDate>
      <link>https://dev.to/vhugogarcia/observablerangecollection-in-net-maui-k9j</link>
      <guid>https://dev.to/vhugogarcia/observablerangecollection-in-net-maui-k9j</guid>
      <description>&lt;p&gt;&lt;strong&gt;ObservableRangeCollection&lt;/strong&gt; is a versatile data structure in C# that offers seamless handling of dynamic collections. Whether you’re building a mobile app, or working on any other software project, understanding how ObservableRangeCollection works can significantly enhance your development experience.&lt;/p&gt;

&lt;p&gt;At its core, ObservableRangeCollection provides a noteworthy feature: it automatically notifies subscribers when items are added, removed, or when the entire list undergoes a refresh. This real-time feedback ensures that your UI stays up-to-date, making it ideal for scenarios where data changes frequently.&lt;/p&gt;

&lt;p&gt;In this article, I will share an extension that is going to be very helpful for mobile development in .NET MAUI.&lt;/p&gt;




&lt;h2&gt;
  
  
  Create an extension
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;On your MAUI project, create a class: &lt;em&gt;&lt;strong&gt;ObservableRangeCollection.cs&lt;/strong&gt;&lt;/em&gt;, I personally create a folder at root level called: &lt;em&gt;Extensions&lt;/em&gt; and then I add the clase under that folder.&lt;/li&gt;
&lt;li&gt;Copy and paste into your class the code below:&lt;/li&gt;
&lt;/ul&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;Now you should be able to use this new data type into your code. For example:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;ObservableRangeCollection&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Item&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;items&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;ObservableRangeCollection&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Item&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;One of the benefits of using an ObservableRangeCollection is the performance. So, I personally recommend it for all your mobile apps wherever you need a list of data with real-time UI updates, otherwise, it is most performant to use a simple List.&lt;/p&gt;

&lt;p&gt;Thank you for reading!&lt;/p&gt;

&lt;p&gt;Follow me on Social:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GitHub &lt;strong&gt;&lt;a href="https://github.com/vhugogarcia" rel="noopener noreferrer"&gt;@vhugogarcia&lt;/a&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;LinkedIn &lt;strong&gt;&lt;a href="https://www.linkedin.com/in/victorhugogarcia/" rel="noopener noreferrer"&gt;victorhugogarcia&lt;/a&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Threads  &lt;strong&gt;&lt;a href="https://www.threads.net/@ihugo" rel="noopener noreferrer"&gt;@ihugo&lt;/a&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;X &lt;strong&gt;&lt;a href="https://twitter.com/ivictorhugo" rel="noopener noreferrer"&gt;@ivictorhugo&lt;/a&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>dotnet</category>
      <category>dotnetmaui</category>
      <category>csharp</category>
    </item>
    <item>
      <title>.NET MAUI: Update NuGet Packages using Visual Studio Code</title>
      <dc:creator>Victor Hugo Garcia</dc:creator>
      <pubDate>Mon, 29 Jan 2024 19:48:08 +0000</pubDate>
      <link>https://dev.to/vhugogarcia/net-maui-update-nuget-packages-using-visual-studio-code-32al</link>
      <guid>https://dev.to/vhugogarcia/net-maui-update-nuget-packages-using-visual-studio-code-32al</guid>
      <description>&lt;p&gt;In this post, I will show you how to use Visual Studio Code in macOS, a popular and lightweight code editor, to search for your outdated NuGet packages of your project with ease and update those faster using the terminal and updating a couple of bits on your &lt;em&gt;.csproj&lt;/em&gt; file.&lt;/p&gt;

&lt;h3&gt;
  
  
  Requirements
&lt;/h3&gt;

&lt;p&gt;It is required for you to install the official .NET MAUI extension in Visual Studio Code and the dotnet-outdated tool.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://marketplace.visualstudio.com/items?itemName=ms-dotnettools.dotnet-maui" rel="noopener noreferrer"&gt;.NET MAUI extension&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/dotnet-outdated/dotnet-outdated" rel="noopener noreferrer"&gt;dotnet-outdated tool&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  How to get a list of updated packages
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Open your .NET MAUI app folder on Visual Studio Code. The .NET MAUI extension will automatically load your solution with the referenced projects.&lt;/li&gt;
&lt;li&gt;Once Visual Studio Code loaded your project's solution successfully on the &lt;strong&gt;Solution Explorer&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Open the Visual Studio Code integrated terminal and run the following command:
&lt;code&gt;dotnet outdated&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;The previous command will parse and show you a list of NuGet packages where an updated version exists based on your current project installed packages &lt;em&gt;(see image below for further details)&lt;/em&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdd4jpsolfz26swlr51zx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdd4jpsolfz26swlr51zx.png" alt=" " width="800" height="392"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;On the image above, it lists not only a specific project but any other project in the solution, and broken down into platforms, so it is easy to identify which NuGet packages being used on your project offer a new updated version.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;Version color legend:
&lt;span class="nt"&gt;&amp;lt;red&amp;gt;&lt;/span&gt;   : Major version update or pre-release version. Possible breaking changes.
&lt;span class="nt"&gt;&amp;lt;yellow&amp;gt;&lt;/span&gt;: Minor version update. Backwards-compatible features added.
&lt;span class="nt"&gt;&amp;lt;green&amp;gt;&lt;/span&gt; : Patch version update. Backwards-compatible bug fixes.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  How to update your project's NuGet packages
&lt;/h3&gt;

&lt;p&gt;It is super easy, just open your &lt;em&gt;.csproj&lt;/em&gt; file and find the Package References, for example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;ItemGroup&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;PackageReference&lt;/span&gt; &lt;span class="na"&gt;Include=&lt;/span&gt;&lt;span class="s"&gt;"Microsoft.Maui.Controls"&lt;/span&gt; &lt;span class="na"&gt;Version=&lt;/span&gt;&lt;span class="s"&gt;"8.0.6"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;PackageReference&lt;/span&gt; &lt;span class="na"&gt;Include=&lt;/span&gt;&lt;span class="s"&gt;"Microsoft.Maui.Controls.Compatibility"&lt;/span&gt; &lt;span class="na"&gt;Version=&lt;/span&gt;&lt;span class="s"&gt;"8.0.6"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/ItemGroup&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then update the key-value from Version and set the new version retrieved previously by using the command on the terminal.&lt;/p&gt;

&lt;p&gt;Finally, once all your NuGet package references are updated as your requirements, I recommend you to close Visual Studio Code and re-open it, so the extension reloads again the solution and projects. As a verification method to make sure your packages are up to date, run the command &lt;code&gt;dotnet outdated&lt;/code&gt; again, so you get an updated list.&lt;/p&gt;

&lt;p&gt;That's it!&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;In Visual Studio Code, I have tried some NuGet Managament extensions without luck, due to the nature of .NET MAUI being cross-platform, the current existing extensions do not support it, that is the main reason of me writing this article. &lt;br&gt;
I heard somewhere that the Microsoft team is working on extension/feature that will make the NuGet Management easily on projects using Visual Studio Code, so hopefully we can see a preview in the coming months.&lt;/p&gt;

&lt;p&gt;Updating NuGet packages is important to keep our projects up to date with the latest features and bug/security fixes. &lt;/p&gt;

&lt;p&gt;Thank you for reading!&lt;/p&gt;

&lt;p&gt;Follow me on Social:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GitHub &lt;strong&gt;&lt;a href="https://github.com/vhugogarcia" rel="noopener noreferrer"&gt;@vhugogarcia&lt;/a&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;LinkedIn &lt;strong&gt;&lt;a href="https://www.linkedin.com/in/victorhugogarcia/" rel="noopener noreferrer"&gt;victorhugogarcia&lt;/a&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Threads  &lt;strong&gt;&lt;a href="https://www.threads.net/@ihugo" rel="noopener noreferrer"&gt;@ihugo&lt;/a&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;X &lt;strong&gt;&lt;a href="https://twitter.com/ivictorhugo" rel="noopener noreferrer"&gt;@ivictorhugo&lt;/a&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>dotnet</category>
      <category>dotnetmaui</category>
      <category>vscode</category>
      <category>nuget</category>
    </item>
    <item>
      <title>.NET MAUI: Archive and Publish using Visual Studio Code</title>
      <dc:creator>Victor Hugo Garcia</dc:creator>
      <pubDate>Fri, 19 Jan 2024 14:40:10 +0000</pubDate>
      <link>https://dev.to/vhugogarcia/net-maui-archive-and-publish-using-visual-studio-code-3dh2</link>
      <guid>https://dev.to/vhugogarcia/net-maui-archive-and-publish-using-visual-studio-code-3dh2</guid>
      <description>&lt;p&gt;.NET MAUI (Multi-platform App UI) is a modern framework for building native cross-platform apps with C# and XAML. With .NET MAUI, you can target Android, iOS, macOS, and Windows platforms with a single codebase and a consistent user interface. In this post, I will show you how to use Visual Studio Code in &lt;strong&gt;macOS&lt;/strong&gt;, a popular and lightweight code editor, to archive and publish your .NET MAUI apps with ease and efficiency.&lt;/p&gt;




&lt;h3&gt;
  
  
  Recommendations
&lt;/h3&gt;

&lt;p&gt;It is important to highlight that the official documentation from Microsoft is very helpful, and I encourage you to read it. Additionally, it is required for you to install the official .NET MAUI extension in Visual Studio Code.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://learn.microsoft.com/en-us/dotnet/maui/ios/deployment/publish-cli?view=net-maui-8.0" rel="noopener noreferrer"&gt;Publishing using the command line for iOS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://learn.microsoft.com/en-us/dotnet/maui/android/deployment/publish-cli?view=net-maui-8.0" rel="noopener noreferrer"&gt;Publishing using the command line for Android&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://marketplace.visualstudio.com/items?itemName=ms-dotnettools.dotnet-maui" rel="noopener noreferrer"&gt;.NET MAUI extension&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  How to archive and publish for iOS
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Open your .NET MAUI app folder on Visual Studio Code. The .NET MAUI extension will automatically load your solution with the referenced projects.&lt;/li&gt;
&lt;li&gt;Once Visual Studio Code loaded your project successfully, On the &lt;strong&gt;Solution Explorer&lt;/strong&gt;, select the name of the project.&lt;/li&gt;
&lt;li&gt;Open the Visual Studio Code integrated terminal and run the following command:
&lt;code&gt;dotnet publish -f net8.0-ios -p:ArchiveOnBuild=true&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;The previous command will read your project properties you have set on your &lt;em&gt;.csproj&lt;/em&gt; file, for example:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;PropertyGroup&lt;/span&gt; &lt;span class="na"&gt;Condition=&lt;/span&gt;&lt;span class="s"&gt;"'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|net8.0-ios|AnyCPU'"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;CreatePackage&amp;gt;&lt;/span&gt;false&lt;span class="nt"&gt;&amp;lt;/CreatePackage&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;RuntimeIdentifier&amp;gt;&lt;/span&gt;ios-arm64&lt;span class="nt"&gt;&amp;lt;/RuntimeIdentifier&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;CodesignProvision&amp;gt;&lt;/span&gt;Test App Distribution&lt;span class="nt"&gt;&amp;lt;/CodesignProvision&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;CodesignKey&amp;gt;&lt;/span&gt;iPhone Distribution: Known (YYYYY123456)&lt;span class="nt"&gt;&amp;lt;/CodesignKey&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;CodesignEntitlements&amp;gt;&lt;/span&gt;Platforms\iOS\Entitlements.plist&lt;span class="nt"&gt;&amp;lt;/CodesignEntitlements&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;MtouchLink&amp;gt;&lt;/span&gt;SdkOnly&lt;span class="nt"&gt;&amp;lt;/MtouchLink&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;MtouchUseLlvm&amp;gt;&lt;/span&gt;true&lt;span class="nt"&gt;&amp;lt;/MtouchUseLlvm&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/PropertyGroup&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;If your Apple Distribution Certificate and Apple Distribution Profile are valid, the output will be successfully.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;Once it finishes archiving and publishes the application, Launch XCode on macOS and then open the Organizer by going to the Window menu.&lt;/li&gt;
&lt;li&gt;On the Organizer window, select the app and version you want to validate and click the Validate button.&lt;/li&gt;
&lt;li&gt;If the application passes the validation, then click the Upload button and select your preferences, either for TestFlight only or TestFlight &amp;amp; Store.&lt;/li&gt;
&lt;li&gt;Done.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Once the publishing process finishes on the terminal, what I love about the process above, is that I don't have to worry about the IPA location to upload it manually, and instead I use XCode to manage the upload for me. If you cannot use XCode, you can find the IPA file on the following folder path: &lt;em&gt;bin/Release/net8.0-ios/ios-arm64/publish/&lt;/em&gt; and upload it manually.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  How to archive and publish for Android
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Open your .NET MAUI app folder on Visual Studio Code. The .NET MAUI extension will automatically load your solution with the referenced projects.&lt;/li&gt;
&lt;li&gt;Once Visual Studio Code loaded your project successfully, On the &lt;strong&gt;Solution Explorer&lt;/strong&gt;, select the name of the project.&lt;/li&gt;
&lt;li&gt;Open the Visual Studio Code integrated terminal and run the following command:
&lt;code&gt;dotnet publish -f net8.0-android -p:ArchiveOnBuild=true&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;The previous command will read your project properties you have set on your &lt;em&gt;.csproj&lt;/em&gt; file, for example:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;PropertyGroup&lt;/span&gt; &lt;span class="na"&gt;Condition=&lt;/span&gt;&lt;span class="s"&gt;"'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|net8.0-android|AnyCPU'"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;AndroidKeyStore&amp;gt;&lt;/span&gt;True&lt;span class="nt"&gt;&amp;lt;/AndroidKeyStore&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;AndroidSigningKeyStore&amp;gt;&lt;/span&gt;/Users/temp/projects/Certificates/testapp-keystore.jks&lt;span class="nt"&gt;&amp;lt;/AndroidSigningKeyStore&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;AndroidSigningStorePass&amp;gt;&lt;/span&gt;123abc&lt;span class="nt"&gt;&amp;lt;/AndroidSigningStorePass&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;AndroidSigningKeyAlias&amp;gt;&lt;/span&gt;testapp&lt;span class="nt"&gt;&amp;lt;/AndroidSigningKeyAlias&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;AndroidSigningKeyPass&amp;gt;&lt;/span&gt;123def&lt;span class="nt"&gt;&amp;lt;/AndroidSigningKeyPass&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;AndroidApkSignerAdditionalArguments&amp;gt;&lt;/span&gt;123abc&lt;span class="nt"&gt;&amp;lt;/AndroidApkSignerAdditionalArguments&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/PropertyGroup&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;If your keystore information is valid, the output will be successfully. So, the signed aab or apk can be uploaded to Google Play Console manually.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;You can find the signed &lt;strong&gt;aab&lt;/strong&gt; or &lt;strong&gt;apk&lt;/strong&gt; file on the following folder path: &lt;em&gt;bin/Release/net8.0-android/&lt;/em&gt; and upload it manually.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;With these skills, you can streamline your development workflow and deliver high-quality apps to your users. Honestly, I was scared at the beginning when Visual Studio for Mac was deprecated, but then when I saw the .NET MAUI extension in VS Code, I quickly shifted and started enjoying how fast it is to develop there.  &lt;/p&gt;

&lt;p&gt;I hope you enjoyed this article and found it useful. If you have any questions or feedback, feel free to leave a comment below. &lt;/p&gt;

&lt;p&gt;Thank you for reading!&lt;/p&gt;

&lt;p&gt;Follow me on Social:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GitHub &lt;strong&gt;&lt;a href="https://github.com/vhugogarcia" rel="noopener noreferrer"&gt;@vhugogarcia&lt;/a&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;LinkedIn &lt;strong&gt;&lt;a href="https://www.linkedin.com/in/victorhugogarcia/" rel="noopener noreferrer"&gt;victorhugogarcia&lt;/a&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Threads  &lt;strong&gt;&lt;a href="https://www.threads.net/@ihugo" rel="noopener noreferrer"&gt;@ihugo&lt;/a&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;X &lt;strong&gt;&lt;a href="https://twitter.com/ivictorhugo" rel="noopener noreferrer"&gt;@ivictorhugo&lt;/a&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>dotnet</category>
      <category>dotnetmaui</category>
      <category>vscode</category>
    </item>
  </channel>
</rss>
