<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~files/atom-premium.xsl"?>
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             
<feed xmlns="http://www.w3.org/2005/Atom" xmlns:feedpress="https://feed.press/xmlns" xmlns:media="http://search.yahoo.com/mrss/" xmlns:podcast="https://podcastindex.org/namespace/1.0">
  <feedpress:locale>en</feedpress:locale>
  <feedpress:newsletterId>telerik-blogs-desktop</feedpress:newsletterId>
  <link rel="hub" href="https://feedpress.superfeedr.com/"/>
  <logo>https://static.feedpress.com/logo/telerik-blogs-desktop-5ab52c3ad3ce5.jpg</logo>
  <title type="text">Telerik Blogs | Desktop</title>
  <subtitle type="text">The official blog of Progress Telerik - expert articles and tutorials for developers.</subtitle>
  <id>uuid:65dfd773-e6e8-49db-a414-6667c0b7dbc2;id=2957</id>
  <updated>2026-07-12T05:29:41Z</updated>
  <link rel="alternate" href="https://www.telerik.com/"/>
  <link rel="self" type="application/atom+xml" href="https://feeds.telerik.com/blogs/desktop"/>
  <entry>
    <id>urn:uuid:a18a06d4-7545-4d98-b443-2c8bf61c38c4</id>
    <title type="text">5 Mistakes Teams Make When Scaling  .NET Applications</title>
    <summary type="text">Avoid these common infrastructure-related mistakes when you’re ready to scale your .NET app to keep your performance at scale too.</summary>
    <published>2026-07-10T16:44:45Z</published>
    <updated>2026-07-12T05:29:41Z</updated>
    <author>
      <name>Brien Posey </name>
    </author>
    <link rel="alternate" href="https://www.telerik.com/blogs/5-mistakes-teams-make-when-scaling-net-applications?utm_medium=feed&amp;utm_source=feedpress.me&amp;utm_campaign=Feed%3A+telerik-blogs-desktop"/>
    <content type="text"><![CDATA[<p><span class="featured">Avoid these common infrastructure-related mistakes when you&rsquo;re ready to scale your .NET app to keep your performance at scale too.</span></p><p>IT teams often assume that scaling a .NET application means moving it to a larger virtual machine or containerizing the application. While such actions do have their place, performance problems are often tied to infrastructure design rather than the application itself.</p><p>This article discusses some of the most common infrastructure-related mistakes that are often made when scaling a .NET application.</p><h2 id="adding-instances-without-thinking-about-traffic-distribution">1. Adding Instances Without Thinking About Traffic Distribution</h2><p>Application scaling very often involves adding additional nodes to handle the increased demand. However, it is a mistake to add nodes without considering how requests will reach those nodes. Oftentimes organizations will use round-robin load balancing to evenly distribute inbound requests across the available nodes. However, load balancing can break down when session affinity comes into play.</p><p>Session affinity occurs as a result of session data being stored on a specific server. This in turn causes all of a user&rsquo;s requests to be sent to that same server, because that&rsquo;s where the user&rsquo;s session lives. This isn&rsquo;t necessarily a problem by itself, but session affinity can become problematic under the right conditions, especially when there is a mixture of active and inactive users.</p><p>In such situations, a particular instance may become overloaded, even if plenty of capacity exists on other instances, simply because the session is bound to that instance. Additionally, if that instance were to fail, then the users on that instance lose their session.</p><p>A better approach is to design services to be stateless and to store session data within shared storage rather than placing it in an instance&rsquo;s memory. This allows the load balancer to freely distribute requests.</p><h2 id="assuming-that-all-requests-look-alike">2. Assuming That All Requests Look Alike</h2><p>Basic load distribution strategies, such as round robin, assume that every instance can deliver the same level of performance and that every request has the same impact. In reality though, these assumptions are na&iuml;ve.</p><p>Some requests, for example, trigger longer running operations, call external services or make more complex database queries. As such, some requests will inevitably be completed more quickly than others. This can result in some nodes being bogged down while others remain nearly idle.</p><p>The best way to avoid this type of problem is to avoid blindly distributing traffic across nodes. Instead, consider each node&rsquo;s health when making routing decisions. As an example, if a node were experiencing excessive latency or had a significant queue depth, then it would be better to route inbound requests to a node that is under less of a load rather than assigning the request to the struggling node just because it is that node&rsquo;s turn.</p><h2 id="not-having-a-load-shedding-strategy">3. Not Having a Load-Shedding Strategy</h2><p>Although it may seem counterintuitive, load shedding can sometimes be the most appropriate course of action. For those who might not be familiar with the term, load shedding refers to the practice of intentionally rejecting certain requests as a way of helping the system to stay healthy.</p><p>To use an analogy from everyday life, consider what might happen if a restaurant kept seating additional guests in spite of the kitchen and the waitstaff being completely overwhelmed. In such a situation, everyone would receive poor service. Conversely, if the restaurant were to pause and not seat anyone else until the staff had a chance to catch up, then it would result in a better overall experience for everyone.</p><p>Load shedding works similarly. When a system becomes overwhelmed with more requests than the nodes can handle, then the load balancer intentionally fails some requests so that those requests that do make it through can still be serviced normally.</p><h2 id="lack-of-visibility">4. Lack of Visibility</h2><p>This one seems so simple (and it is), yet it is so important. Organizations often make the mistake of just assuming that load balancing is working as intended without doing anything to verify their assumptions. The problem is that if an organization cannot see how requests are being routed, then scaling an application becomes guesswork.</p><p>Without proper visibility, you can&rsquo;t tell whether traffic is being evenly distributed, if there are nodes that are constantly struggling or which instances are handling slow requests. It becomes easy to misdiagnose bottlenecks and blame the application for poor performance when routing is the real problem (or vice versa).</p><p>Ideally, an organization should be able to collect per-instance metrics from its nodes including CPU and memory usage and the request count. There should also be a way to trace requests as they flow across services and there should be a way to track load distribution metrics to see how the individual nodes are being leveraged.</p><h2 id="treating-load-balancing-as-an-afterthought">5. Treating Load Balancing as an Afterthought</h2><p>One of the single biggest mistakes that is often made when scaling an application is treating load balancing as an afterthought. Typically, an application is deployed and works fine. Eventually though, demand increases and the application begins to struggle. IT distributes the application across several nodes and places a basic load balancer in front of those nodes. In these types of situations, load balancers often use default settings because, &ldquo;round robin is good enough for not&rdquo; or &ldquo;the cloud provider&rsquo;s defaults should be fine.&rdquo;</p><p>The end result is that while the application has indeed been scaled, there is a good chance that some of the original problems still exist. The added infrastructure now makes those problems more difficult to diagnose.</p><p>True load balancing is not about spreading traffic evenly. It&rsquo;s about making informed decisions as to where each inbound request should be routed. This informed decision making means using application aware routing to base routing decisions on application behavior, not just routing rules. It also means taking instance health and readiness into account and continually adjusting routing decisions based on latency, errors and available capacity.</p><aside><hr data-sf-ec-immutable="" /><div class="row"><div class="col-4 u-normal-full u-small-mb0"><h4 class="u-fs20 u-fw5 u-lh125 u-mb0">Using AI to Build a Blazor App 1: Start With the Problem
</h4></div><div class="col-8"><p class="u-fs16 u-mb0">Many AI-assisted projects fail before a line of code is written because the idea was never properly defined. <a target="_blank" href="https://www.telerik.com https://www.telerik.com/blogs/using-ai-build-blazor-app-1-start-problem">Here&rsquo;s how to use an LLM to interrogate your own thinking until a vague premise becomes something you can actually build.</a></p></div></div></aside>]]></content>
  </entry>
  <entry>
    <id>urn:uuid:3688cfa4-c260-412e-918e-9889e5046f2a</id>
    <title type="text">Available Now in .NET 11 for .NET MAUI</title>
    <summary type="text">Explore the .NET 11 updates available now in .NET MAUI, including map enhancements, long press recognition, animation improvements and more.</summary>
    <published>2026-07-08T15:35:21Z</published>
    <updated>2026-07-12T05:29:41Z</updated>
    <author>
      <name>Leomaris Reyes </name>
    </author>
    <link rel="alternate" href="https://www.telerik.com/blogs/available-now-net-11-net-maui?utm_medium=feed&amp;utm_source=feedpress.me&amp;utm_campaign=Feed%3A+telerik-blogs-desktop"/>
    <content type="text"><![CDATA[<p><span class="featured">Explore the .NET 11 updates available now in .NET MAUI, including map enhancements, long press recognition, animation improvements and more.</span></p><p>Oh yeahhh!!  .NET 11 for .NET MAUI is here!</p><p>And, as always, my recommendation is to stay up to date with every new release. What changed? What&rsquo;s new? What has been improved? Keeping up with these updates helps us build better apps and keeps our code inline with the latest recommendations from the Microsoft team.</p><p>For .NET 11, the team&rsquo;s main focus has been improving the overall quality of .NET MAUI, making it faster and easier for us as developers, to build amazing applications. In this article, you&rsquo;ll discover some of my favorite improvements that Microsoft has introduced for .NET MAUI in .NET 11!</p><h2 id="maps-improvements">1. Maps Improvements</h2><p>This is one of my favorite updates in .NET 11!  Let&rsquo;s start by exploring the <strong><a target="_blank" href="https://learn.microsoft.com/es-es/dotnet/api/microsoft.maui.controls.maps.map?view=net-maui-10.0">Map</a></strong> control, which has received some really nice improvements. Here are some of the highlights!</p><h3 id="pin-clustering">Pin Clustering</h3><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-07/01_improvement_map.png?sfvrsn=9f323c91_2" title=".NET MAUI 11 Map Improvement: Pin Clustering" alt="Illustrated maps. Without clustering the pins, they are everywhere. With clustering enabled, blue circles have numbers for how many pins are in that area" /><br /><span style="font-size:11px;">For educational purposes, this image was generated with AI</span></p><p>Imagine you&rsquo;re building a restaurant app where users can view nearby restaurants on a map. You may have <strong>300, 400 or even more locations</strong> to display. If the user opens the map while zoomed out, it could look something like this: </p><p>This quickly becomes overwhelming because many pins overlap, making it difficult to select a specific location.</p><p>With <strong>.NET 11,</strong> you can simply use this property:</p><pre class=" language-xml"><code class="prism  language-xml">IsClusteringEnabled="True"
</code></pre><p>And with that, .NET MAUI will automatically group nearby pins into clusters. So instead of displaying multiple overlapping pins like , users will see something like (5), indicating that five locations are grouped together.</p><p>As users zoom in, those clusters gradually split into individual pins, creating a much cleaner experience and making it much easier to interact with the map.</p><p>Using it in .NET MAUI is incredibly simple:</p><pre class=" language-xml"><code class="prism  language-xml">&lt;maps:Map IsClusteringEnabled="True"

    ClusterClicked="OnClusterClicked" /&gt;
</code></pre><h3 id="custom-location-markers">Custom Location Markers</h3><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-07/02_improvement_map.png?sfvrsn=74e1d38_2" title=".NET MAUI 11 Map Improvement: Custom Location Markers" alt="Illustrated maps showing custom location markers for hospitals and pharmacies, instead of the simple pin" /><br /><span style="font-size:11px;">For educational purposes, this image was generated with AI</span></p><p>Yay!!  Another great addition is the ability to <strong>customize your map markers</strong>.</p><p>Instead of using the default pin for every location, you can now display a custom image for each marker, making your maps much more intuitive and visually appealing.</p><p>For example, imagine you&rsquo;re building a healthcare app. You could use one icon for <strong>hospitals</strong> and a different one for <strong>pharmacies</strong>, allowing users to quickly identify each type of location without even reading the labels.</p><p>This is possible by simply setting the <strong>ImageSource</strong> property on the pin.</p><p>Here&rsquo;s what it looks like in code:</p><pre class=" language-csharp"><code class="prism  language-csharp">var pin = new Pin
{ 
    Label = "Custom pin", 
    Location = new Location(18.4861, -69.9312), 
    ImageSource = ImageSource.FromFile("hospitals.png") 
};
</code></pre><h3 id="json-map-style-android">JSON Map Style (Android)</h3><p>Google Maps allows you to customize the map using a JSON file. This means you can change colors, switch between light and dark mode, customize labels and much more.</p><p>Previously, this was much more complicated in .NET MAUI. Now, all you have to do is assign your JSON file to the <strong>MapStyle</strong> property, and you&rsquo;re done! </p><h2 id="cancel-animations-with-cancellationtoken">2. Cancel Animations with CancellationToken</h2><p>This improvement may seem small, but it&rsquo;s actually a very useful one, especially when you have multiple animations running at the same time.</p><p>Before .NET 11, if you started an animation and later wanted to stop it, your only option was to do something like this:</p><pre class=" language-csharp"><code class="prism  language-csharp">image.CancelAnimations();
</code></pre><p>However, there was a small problem.  This method <strong>canceled every animation</strong> running on that control.</p><p>Imagine your image is running two animations simultaneously: a rotation animation and a fade animation. If you only wanted to stop the rotation while keeping the fade animation running, that simply wasn&rsquo;t possible.</p><p>Starting with .NET 11, the animation methods now optionally accept a <strong>CancellationToken</strong>. This means you can cancel a specific animation without affecting the others.</p><p>For example:</p><pre class=" language-csharp"><code class="prism  language-csharp">var cts = new CancellationTokenSource();

await image.FadeToAsync( 
opacity: 0, 
cancellationToken: cts.Token);
</code></pre><p>And when you want to stop that animation:</p><pre class=" language-csharp"><code class="prism  language-csharp">cts.Cancel();
</code></pre><p>That&rsquo;s it! Only the animation associated with that <strong>CancellationToken</strong> will be canceled, while any other animations on the same control will continue running normally.</p><h3 id="methods-without-async-are-now-obsolete">Methods Without Async Are Now Obsolete</h3><p>Another important change is that animation methods without the <strong>Async</strong> suffix have now been marked as obsolete. Methods such as <strong>FadeTo(), RotateTo() and ScaleTo()</strong> are now marked as <strong>[Obsolete].</strong> Instead, Microsoft recommends using their asynchronous counterparts:</p><ul><li>await FadeToAsync(&hellip;);</li><li>await RotateToAsync(&hellip;);</li><li>await ScaleToAsync(&hellip;);</li></ul><p>Of course, these methods also support the new <strong>CancellationToken</strong>, giving you much greater control over your animations.</p><h2 id="longpressgesturerecognizer">3. LongPressGestureRecognizer</h2><p>Have you noticed that some actions in mobile apps are only triggered when you press and hold a control for some seconds? Thanks to <strong>.NET 11</strong>, .NET MAUI now includes the <strong>LongPressGestureRecognizer</strong>, making it easy to detect this gesture.</p><p>It provides several useful features:</p><ul><li>Detects long-press gestures</li><li>Configurable press duration</li><li>Movement threshold to cancel the gesture if the finger moves too far</li><li>Gesture state tracking through GestureState</li><li>Support for Command and CommandParameter</li></ul><p>Using it is as simple as this:</p><pre class=" language-xml"><code class="prism  language-xml">&lt;Image Source="flower.png"&gt; 
&lt;Image.GestureRecognizers&gt; 
&lt;LongPressGestureRecognizer 
    Duration="500" 
    LongPressed="OnLongPressed"/&gt; 
    &lt;/Image.GestureRecognizers&gt; 
&lt;/Image&gt;
</code></pre><p>The event:</p><pre class=" language-csharp"><code class="prism  language-csharp">void OnLongPressed(object sender, LongPressGestureRecognizerEventArgs e) 
{ 
    if (e.State == GestureState.Completed) 
    { 
    // Your code goes here 
    } 
}
</code></pre><h2 id="we-can-finally-use-gradients-in-boxview">4. We Can Finally Use Gradients in BoxView!</h2><p>BoxView is a super useful control that gives us a lot of flexibility when building UI. However, before .NET 11, it had one important limitation: <strong>it could only display a solid color.</strong> So, if you wanted a gradient, you had to rely on other controls or custom solutions.</p><p>With .NET 11, BoxView now includes the Fill property, which is of type Brush. This means you can finally apply gradients directly to a BoxView! And don&rsquo;t worry, if you only need a solid color, you can continue using the BackgroundColor property as before.</p><p>Here&rsquo;s a simple example:</p><pre class=" language-xml"><code class="prism  language-xml">&lt;BoxView HeightRequest="260"&gt; 
    &lt;BoxView.Fill&gt; 
    &lt;LinearGradientBrush&gt; 
    ... 
    &lt;/LinearGradientBrush&gt; 
    &lt;/BoxView.Fill&gt; 
&lt;/BoxView&gt;
</code></pre><h2 id="trimmable-css">5. Trimmable CSS</h2><p>I don&rsquo;t know if you knew this, but .NET MAUI has supported CSS for quite some time. The problem was that even if your application didn&rsquo;t use CSS, .NET MAUI still had to include all the infrastructure required to support it, increasing the final size of your app.</p><p>With .NET 11, that&rsquo;s no longer the case. If your application doesn&rsquo;t use CSS stylesheets, the CSS infrastructure is automatically removed during the publishing process. In short, if you don&rsquo;t use CSS, your application becomes smaller <strong>without you having to do anything</strong>.</p><h2 id="material-3-on-android">6. Material 3 on Android</h2><p>Previously, some .NET MAUI controls on Android were not fully aligned with Material 3. Starting with .NET 11 Preview 4, several Android handlers now use <strong>Material 3</strong> by default. This applies to controls such as:</p><ul><li>ImageButton</li><li>DatePicker</li><li>Entry</li><li>Slider</li></ul><p>In short, it was common to find controls that didn&rsquo;t fully follow Android&rsquo;s modern design guidelines. With .NET 11, that changes. These controls are now much more aligned with Material 3, resulting in a more modern, consistent look that feels fully integrated with the Android ecosystem. </p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-07/03_improvement_material_controls.png?sfvrsn=9620bef2_2" title=".NET MAUI 11 Material 3 on Android" alt="Material 3 on Android in dark and light mode on .NET MAUI now in >NET 11" /><br /><span style="font-size:11px;">Image obtained from the official documentation</span></p><h2 id="conclusion">Conclusion</h2><p>And that&rsquo;s it! I hope this article helps you discover some of the exciting new features coming to .NET MAUI with .NET 11.</p><p>Throughout this article, we explored some of my favorite improvements, including the new LongPressGestureRecognizer, Map enhancements, BoxView gradients, animation improvements and Android Material 3 support.</p><p>Of course, these are just a few of my favorites! I encourage you to explore the article &ldquo;<a target="_blank" href="https://learn.microsoft.com/en-us/dotnet/maui/whats-new/dotnet-11?view=net-maui-10.0">What&rsquo;s new in .NET MAUI for .NET 11</a>&rdquo; from the official documentation to discover even more improvements and enhancements included in this release.</p><p>I also encourage you to keep experimenting with these new features and continue learning something new every day. </p><p>See you in the next article! &zwj;♀️</p><aside><hr data-sf-ec-immutable="" /><div class="row"><div class="col-4 u-normal-full u-small-mb0"><h4 class="u-fs20 u-fw5 u-lh125 u-mb0">What&rsquo;s New for Blazor in .NET 11 Preview Releases 1 and 2</h4></div><div class="col-8"><p class="u-fs16 u-mb0">Tour the <a target="_blank" href="https://www.telerik.com/blogs/whats-new-blazor-net-11-preview-releases-1-2">notable Blazor changes and new features in .NET 11 Previews 1 and 2</a> for an early glimpse into what&rsquo;s coming for Blazor in .NET 11.</p></div></div></aside>]]></content>
  </entry>
  <entry>
    <id>urn:uuid:679fe682-4514-4e7a-94ff-ef3f94efed17</id>
    <title type="text">Replicating a Travel App in .NET MAUI</title>
    <summary type="text">Practice thoughtful planning before you begin coding with this .NET MAUI travel app. We’ll divide the design into blocks and code each one.</summary>
    <published>2026-07-01T16:48:23Z</published>
    <updated>2026-07-12T05:29:41Z</updated>
    <author>
      <name>Leomaris Reyes </name>
    </author>
    <link rel="alternate" href="https://www.telerik.com/blogs/replicating-travel-app-net-maui?utm_medium=feed&amp;utm_source=feedpress.me&amp;utm_campaign=Feed%3A+telerik-blogs-desktop"/>
    <content type="text"><![CDATA[<p><span class="featured">Practice thoughtful planning before you begin coding with this .NET MAUI travel app. We&rsquo;ll divide the design into blocks and code each one.</span></p><p>Take note of this: always&mdash;always&mdash;absolutely always&mdash;when you start developing an app, take a moment to step back and analyze what you truly need. That way, you avoid writing the same code two, three or even N times.</p><p>Once you begin, aim to keep your code as clean and optimized as possible. Remember that every component you choose is a decision that shapes the quality of your app from the layout you select (where everything begins) to the components you use and the reasoning behind them. And of course, becoming more comfortable with XAML every day is key. With creativity and a willingness to think outside the box, anything can be achieved in a UI.</p><p>With practice, this process becomes easier, as experience gives you the insight needed to make faster and more confident decisions. That&rsquo;s why in this article we will replicate a travel UI from scratch, inspired by a design obtained from <a target="_blank" href="https://dribbble.com/shots/26145161-Travel-app-design">Dribbble</a>.</p><p><strong>How will the explanation work?</strong></p><p>So you can understand everything 100%, I&rsquo;ll explain how the process will work:</p><p>➖<strong>Visual diagram:</strong> Before we start, you&rsquo;ll see a diagram with a screenshot of the design we want to achieve. This design will be divided into blocks, each identified with a name and a color. Each block will be explained individually.</p><p>➖<strong>Code explanation per block:</strong> In addition to the text explanation, each block will include the exact code snippet you need to write to achieve the result.</p><p>➖<strong>Step-by-step visual progress:</strong> Each explanation will have its corresponding screenshot, so you can see the progress as we build the UI.</p><p>⚠️ For the purposes of these articles, there will be some changes to the original user interface.</p><h2 id="-environment-setup"> Environment Setup</h2><p>You&rsquo;ll learn how to take advantage of some of the powerful components provided in the Progress Telerik UI for <a target="_blank" href="https://www.telerik.com/maui-ui">.NET MAUI component library</a>. Before we dive in, let&rsquo;s get your environment ready, just keep these two key points in mind:</p><ol><li><p><strong>If you don&rsquo;t have a <a target="_blank" href="https://www.telerik.com/account/">Telerik account</a> yet, you can create one for free.</strong> You&rsquo;ll get access to a trial license so you can explore not only RadBorder and RadButton, but all the Telerik controls for .NET MAUI.</p></li><li><p><strong>You need to install Telerik UI for .NET MAUI.</strong> This is a one-time setup, meaning you don&rsquo;t need to do it for every component you use. (If you don&rsquo;t have it installed yet, I&rsquo;ve included an article where it is explained step by step how to set it up in both <a target="_blank" href="https://www.telerik.com/maui-ui/documentation/get-started/first-steps-vs">Visual Studio</a> and <a target="_blank" href="https://www.telerik.com/maui-ui/documentation/get-started/first-steps-vs-code">Visual Studio Code</a>.)</p></li></ol><h2 id="breaking-down-the-design-into-blocks">Breaking Down the Design into Blocks</h2><p>To make this easier to follow, I&rsquo;ve divided the design into clear blocks. We&rsquo;ll build each part one at a time, in the order you see below.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/01_visual_structure.png?sfvrsn=6c886051_2" title="Visual structure" alt=".NET MAUI travel app structure" /></p><p>Alright, we&rsquo;ve now divided our UI into blocks. Grab a cup of coffee (or hot chocolate), and let&rsquo;s start writing some code! </p><h2 id="main-image">1. Main Image</h2><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/02_main_image_block.png?sfvrsn=308faa3_2" title="Main imagen block" alt=".NET MAUI travel app main image" /></p><p>When starting to build a UI, the first thing you should evaluate is which layout best fits your needs. In this case, we need a flexible layout that allows us to create overlapping effects both for positioning text on top of the image and for building the overlapping effect in the second block.</p><p>For this, we&rsquo;ll use a Grid, structured as follows:</p><pre class=" language-xml"><code class="prism  language-xml">&lt;Grid RowDefinitions="auto,*"&gt;  
    &lt;!-- Place here the remaining elements that belong to the first block--&gt; 
    &lt;!-- Insert here the code for the next block --&gt;     
&lt;/Grid&gt;
</code></pre><p>Now, let&rsquo;s add the main image along with the two text elements displayed on top of it. Place this code in the section indicated by the comment: <code>&lt;!-- Place here the remaining elements that belong to the first block --&gt;</code>.</p><pre class=" language-xml"><code class="prism  language-xml">&lt;Image Grid.Row="0" Source="homebg" Aspect="Fill" HeightRequest="500"/&gt; 

&lt;Label Grid.Row="0" Text="Wanna Go List" TextColor="White" FontSize="24" FontAttributes="Bold" 
    TranslationY="-40" 
    HorizontalTextAlignment="Center" 
    VerticalTextAlignment="Center"/&gt; 

&lt;Label Grid.Row="0" Text="Save only your favorite hotels.&amp;#10;Search only your favorite hotels." 
    TextColor="White" FontSize="17" TranslationY="-65" 
    HorizontalTextAlignment="Center" 
    VerticalTextAlignment="End"/&gt;
</code></pre><p>✍️ To help create the overlapping effect across the Grid areas, I used the <code>TranslationY</code> property to position the element exactly where needed.</p><h2 id="sign-in-details">2. Sign-in Details</h2><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/03_sign_in_details_block.png?sfvrsn=d4b404c0_2" title="Sign In details block" alt=".NET MAUI travel app sign in" /></p><p>For this second block, we&rsquo;ll work with several elements, all contained within a white background with rounded top corners. This is where Telerik RadBorder plays a key role.</p><p>Inside this container, we&rsquo;ll include:</p><ul><li>Rounded and rectangular buttons (using Telerik RadButton)</li><li>Simple labels and styled text (using FormattedText)</li></ul><h3 id="white-background-with-rounded-corners">White Background with Rounded Corners</h3><p>To get started with RadBorder, add the corresponding namespace:</p><pre class=" language-xml"><code class="prism  language-xml">xmlns:telerik="clr-namespace:Telerik.Maui.Controls;assembly=Telerik.Maui.Controls"
</code></pre><p>Once that&rsquo;s set up, add the component as shown below.</p><pre class=" language-xml"><code class="prism  language-xml">&lt;telerik:RadBorder Grid.Row="1" 
    BackgroundColor="White" 
    VerticalOptions="Fill" 
    Margin="0,-40,0,0" 
    CornerRadius="30" 
    Padding="30"&gt; 
    &lt;!-- Add the Grid here-- &gt; 
&lt;/telerik:RadBorder&gt;
</code></pre><p>Inside the RadBorder, we&rsquo;ll use a Grid to structure the content. This Grid will consist of four rows and three columns, with a spacing of 20 between elements to maintain a clean and well-organized layout.</p><pre class=" language-xml"><code class="prism  language-xml">&lt;Grid RowDefinitions="auto,auto,auto,auto" ColumnDefinitions="*,*,*" RowSpacing="20"&gt; 
    &lt;!-- Add all remaining elements for the second block here --&gt; 
&lt;/Grid&gt;
</code></pre><p>Finally, let&rsquo;s add all the remaining elements inside the Grid. Here are a few key points to keep in mind:</p><p>➖ For the buttons, we&rsquo;ll use Telerik RadButton. Since you already added the namespace earlier, there&rsquo;s no need to include it again.</p><p>➖ To achieve a rounded button, simply set the <code>WidthRequest</code> and <code>HeightRequest</code> to the same value, and define the <code>CornerRadius</code> as half of that value.</p><p>➖ For the label with multiple colors, instead of using several separate labels, we&rsquo;ll use <code>FormattedText</code>. This helps keep the code cleaner and more efficient.</p><pre class=" language-xml"><code class="prism  language-xml">&lt;telerik:RadButton Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="3" Text="Sign In Via Email" TextColor="White" BackgroundColor="#0c538f" CornerRadius="8"/&gt;

&lt;Label Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="3" Text="or sign in with" FontSize="13" HorizontalTextAlignment="Center" TextColor="Grey"/&gt;

&lt;telerik:RadButton Grid.Row="2" Grid.Column="0" ImageSource="google" BackgroundColor="#def0f5" HeightRequest="60" WidthRequest="60" CornerRadius="30" HorizontalOptions="End"/&gt;
 
&lt;telerik:RadButton Grid.Row="2" Grid.Column="1" ImageSource="apple" BackgroundColor="#def0f5" HeightRequest="60" WidthRequest="60" CornerRadius="30"/&gt;
 
&lt;telerik:RadButton Grid.Row="2" Grid.Column="2" ImageSource="facebook" BackgroundColor="#def0f5" HeightRequest="60" WidthRequest="60" CornerRadius="30" HorizontalOptions="Start"/&gt;
 
&lt;Label Grid.Row="3" Grid.Column="0" Grid.ColumnSpan="3" HorizontalTextAlignment="Center"&gt;

&lt;Label.FormattedText&gt; 
    &lt;FormattedString&gt; 
    &lt;Span Text="Don't have an account? " TextColor="Grey"/&gt; 
    &lt;Span Text="Sign Up" FontAttributes="Bold" TextColor="#0c538f"/&gt; 
    &lt;/FormattedString&gt; 
    &lt;/Label.FormattedText&gt; 
&lt;/Label&gt;
</code></pre><h2 id="header">3. Header</h2><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/04_header_block.png?sfvrsn=77918cc2_2" title="Header block" alt=".NET MAUI travel app header" /></p><p>Woohoo!!!  Our first screen is ready.  Now, in this third block, we&rsquo;ll start building the second screen packed with some really interesting elements!</p><p>Let&rsquo;s begin with the main layout. We&rsquo;ll create a three row Grid where we&rsquo;ll position the header image, a VerticalStackLayout to hold the plans and benefits and the footer.</p><pre class=" language-xml"><code class="prism  language-xml">&lt;Grid RowDefinitions="auto,*,auto,auto" RowSpacing="20" Padding="20,0"&gt; 
    &lt;!-- Add the header image code here --&gt; 
    &lt;!-- Add the VerticalStackLayout here &rarr; 
    &lt;!-- Add the footer code here --&gt; 
&lt;/Grid&gt;
</code></pre><p>To get started, we&rsquo;ll focus on placing the header image and the primary label.</p><h3 id="header-image">Header Image</h3><p>You can either use an image that already has a diagonal effect or take a regular image and create that effect through code. For this demo, I used a regular image and rotated it to show you how it works. This effect comes from combining <code>Rotation</code>, <code>TranslationY</code>, and <code>TranslationX</code> properties, along with adjusting the width and height.</p><pre class=" language-xml"><code class="prism  language-xml">&lt;Image Grid.Row="0" Source="header" HeightRequest="370" WidthRequest="500" Aspect="AspectFit" 
    Rotation="-15" 
    TranslationX="-20" 
    TranslationY="-300"/&gt;
</code></pre><h3 id="main-label">Main Label</h3><p>Before adding the label itself, we&rsquo;ll set up the layout that will contain it. Add a VerticalStackLayout, and inside it place a Label with FormattedText. This allows you to apply different colors, sizes and styles within a single label, keeping your UI clean and flexible.</p><pre class=" language-xml"><code class="prism  language-xml">&lt;VerticalStackLayout Grid.Row="0" Margin="0,140,0,0"&gt; 
&lt;Label HorizontalTextAlignment="Center" FontSize="28" CharacterSpacing="18"&gt; 
&lt;Label.FormattedText&gt; 
    &lt;FormattedString&gt; 
    &lt;Span Text="Unlock " FontAttributes="Bold"/&gt; 
    &lt;Span Text="Pro&amp;#10;" FontAttributes="Bold" TextColor="#4b9db4"/&gt; 
    &lt;Span Text="Features! " FontAttributes="Bold"/&gt; 
    &lt;/FormattedString&gt; 
&lt;/Label.FormattedText&gt; 
&lt;/Label&gt;
 
&lt;!-- Add the Benefits code block here --&gt; 
&lt;!-- Add the Plans code block here --&gt;
 
&lt;/VerticalStackLayout&gt;
</code></pre><h2 id="benefits--plans">4. Benefits &amp; Plans</h2><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/05_benefits_and_plans.png?sfvrsn=897d8827_2" title="Benefits and plans block" alt=".NET MAUI travel app benefits and plans" /></p><p>For this block, we&rsquo;ll also use Telerik RadBorder, so make sure to include the same namespace used on the previous page here as well. This section is composed of the following elements:</p><p>➖ <strong>Benefits:</strong> We&rsquo;ll use a CollectionView so the information can be loaded from a flexible list, instead of adding each item manually in XAML. Each item will include a checkmark image and a label with the benefit name.</p><pre class=" language-xml"><code class="prism  language-xml">&lt;CollectionView.ItemTemplate&gt; 
&lt;DataTemplate&gt; 
    &lt;HorizontalStackLayout Spacing="10" Padding="0,8"&gt; 
    &lt;Image Source="check" HeightRequest="20" WidthRequest="20"/&gt; 
    &lt;Label Text="{Binding Description}" FontSize="12"/&gt; 
    &lt;/HorizontalStackLayout&gt; 
    &lt;/DataTemplate&gt; 
&lt;/CollectionView.ItemTemplate&gt; 
&lt;/CollectionView
</code></pre><p>➖<strong>Plans:</strong> We&rsquo;ll also use a CollectionView for the plan selector. Each item will be displayed inside a box with rounded blue borders and will contain the plan name, the discount, the current price and the previous price.</p><pre class=" language-xml"><code class="prism  language-xml">&lt;CollectionView VerticalScrollBarVisibility="Never" 
ItemsSource="{Binding plans}"&gt; 
    &lt;CollectionView.ItemTemplate&gt; 
    &lt;DataTemplate&gt; 
    &lt;telerik:RadBorder Grid.Row="1" 
    BorderColor="#b9d7e1" 
    BorderThickness="2" 
    CornerRadius="20" 
    Margin="0,10,0,0" 
    Padding="10,15"&gt; 
    &lt;Grid ColumnDefinitions="auto,auto,*,auto" VerticalOptions="Center"&gt; 
    &lt;Label Grid.Column="0" Text="{Binding Name}" FontSize="14" FontAttributes="Bold" VerticalTextAlignment="Center" /&gt;
     
    &lt;telerik:RadBorder Grid.Column="1" 
    BackgroundColor="#F2555A" 
    BorderThickness="2" 
    CornerRadius="50" 
    Padding="10,6"&gt;
    
    &lt;Label 
    Text="{Binding Discount}" 
    TextColor="White" 
    FontAttributes="Bold" 
    FontSize="12" 
    HorizontalTextAlignment="Center" 
    VerticalTextAlignment="Center" /&gt; 
    &lt;/telerik:RadBorder&gt;
     
    &lt;Label Grid.Column="2" Text="{Binding Price} " FontSize="14" VerticalTextAlignment="Center" HorizontalTextAlignment="End" FontAttributes="Bold"/&gt;
    
    &lt;Label Grid.Column="3" Text="{Binding OldPrice}" VerticalTextAlignment="Center" TextDecorations="Strikethrough" FontSize="14" TextColor="Gray"/&gt; 
    &lt;/Grid&gt; 
    &lt;/telerik:RadBorder&gt; 
    &lt;/DataTemplate&gt; 
    &lt;/CollectionView.ItemTemplate&gt; 
&lt;/CollectionView&gt;
</code></pre><h2 id="footer">5. Footer</h2><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/06_footer.png?sfvrsn=c66819db_2" title="Footer block" alt=".NET MAUI travel app footer" /></p><p>Oh yeah! We&rsquo;ve reached the final block, the footer. This section includes a centered label and a button (using Telerik RadButton). To add it, go to the main Grid of this screen and locate the comment <code>&lt;!-- Add the footer code here --&gt;</code>.</p><p>Then, place the following code in that section:</p><pre class=" language-xml"><code class="prism  language-xml">&lt;Label Grid.Row="1" Text="Can be cancelled at any time" FontSize="13" TextColor="Grey" VerticalOptions="End" HorizontalTextAlignment="Center"/&gt;

&lt;telerik:RadButton Grid.Row="2" Text="Become Member" BackgroundColor="#0c538f" CornerRadius="10" VerticalOptions="End"/&gt;
</code></pre><p>And that&rsquo;s it&mdash;we&rsquo;re all done!  Below, you can see the final result of both screens.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/07_final_results.png?sfvrsn=ed18f275_2" title="Final results" alt=".NET MAUI travel app final result" /></p><h2 id="conclusion">Conclusion</h2><p>And that&rsquo;s it!  In this article, we explored how to build a travel UI using .NET MAUI with XAML, inspired by a modern design.</p><p>I hope this guide helps you take these ideas and practices and apply them to your own UI implementations, especially when working with layouts, overlapping elements, and Telerik components.</p><p>If you have any questions or would like me to dive deeper into a specific part, feel free to leave a comment, I&rsquo;ll be happy to help! </p><p>See you in the next article! &zwj;♀️</p><p>Remember, Telerik UI for .NET MAUI comes with a free 30-day trial. See what you can create:</p><p><a target="_blank" href="https://www.telerik.com/try/ui-for-maui" class="Btn">Try Now</a></p>]]></content>
  </entry>
  <entry>
    <id>urn:uuid:80b15211-473c-45fd-8937-2de83c237f13</id>
    <title type="text">Replicating a Ticket Screen in .NET MAUI</title>
    <summary type="text">Travel! It’s one of our favorite things, and here is how to build a flight ticket screen in .NET MAUI.</summary>
    <published>2026-06-22T17:00:48Z</published>
    <updated>2026-07-12T05:29:41Z</updated>
    <author>
      <name>Leomaris Reyes </name>
    </author>
    <link rel="alternate" href="https://www.telerik.com/blogs/replicating-ticket-screen-net-maui?utm_medium=feed&amp;utm_source=feedpress.me&amp;utm_campaign=Feed%3A+telerik-blogs-desktop"/>
    <content type="text"><![CDATA[<p><span class="featured">Travel! It&rsquo;s one of our favorite things, and here is how to build a flight ticket screen in .NET MAUI.</span></p><p>I dare to say that one of the most loved hobbies, and one of the reasons we want vacations to arrive quickly, is traveling.  Guilty as charged, haha.</p><p>But personally, beyond the trip itself, I really enjoy being involved in the whole experience&mdash;from packing my bags to having my flight ticket in an app. But you know what&rsquo;s the most fun part? Besides having my ticket in an app, I can also combine my passion for traveling with my profession, by programming and replicating an app that brings these two things together.</p><p>For this reason, in this article you will continue strengthening your UI skills in .NET MAUI. Get it out of your head that you can&rsquo;t build beautiful and creative UIs, because you absolutely can.  Today we will replicate a ticket UI inspired by a <a target="_blank" href="https://dribbble.com/shots/17661430-Ticket-App-Mobile-application-concept">Dribbble</a> design, which will allow us to practice using several .NET MAUI components such as <strong>Shapes, Grid, Label</strong>, and especially a super special component: the <a target="_blank" href="https://www.telerik.com/maui-ui/border">.NET MAUI Border</a> from Progress Telerik UI. All of this in a very simple way. We&rsquo;ll break it down step by step!</p><p><strong>How will the explanation work?</strong></p><p>So you can understand everything 100%, I&rsquo;ll explain how the process will work:</p><p>➖<strong>Visual diagram:</strong> Before we start, you&rsquo;ll see a diagram with a screenshot of the design we want to achieve. This design will be divided into blocks, each identified with a name and a color. Each block will be explained individually.</p><p>➖<strong>Code explanation per block:</strong> In addition to the text explanation, each block will include the exact code snippet you need to write to achieve the result.</p><p>➖<strong>Step-by-step visual progress:</strong> Each explanation will have its corresponding screenshot, so you can see the progress as we build the UI.</p><p>⚠️ For the purposes of these articles, there will be some changes to the original user interface.</p><h2 id="breaking-down-the-dribbble-design-into-blocks">Breaking Down the Dribbble Design into Blocks</h2><p>To make this easier to follow, I&rsquo;ve divided the original design into clear blocks. We&rsquo;ll build each part one at a time, in the order you see below.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/00_visual_structure.png?sfvrsn=a4b7e5c4_2" title="Visual structure" alt="Visual structure of ticket app. Main border, passenger info, perforated edges" /></p><h2 id="main-border-block">1. Main Border Block</h2><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/01_first_block_design.png?sfvrsn=3bc792c5_2" title="First block design" alt="First block design - blue background" /></p><p>Let&rsquo;s start building the first block. This block is the most important one, since it contains all the elements of the remaining blocks.</p><p>To replicate the element in this block, we need a control that allows us to add a background color and apply rounded corners.</p><p>We will use the <a target="_blank" href="https://www.telerik.com/maui-ui/border">RadBorder</a> control from Progress Telerik. This control makes it easy to manage border color, thickness and even apply different corner radius values for each side. It&rsquo;s super useful!</p><p><strong>To use it, keep the following in mind:</strong></p><ol><li><p><strong>If you don&rsquo;t have a Telerik account yet, you can create one <a target="_blank" href="https://www.telerik.com/account/">for free</a></strong>. You&rsquo;ll get access to a trial license so you can explore not only RadBorder, but all the Telerik UI for .NET MAUI controls.</p></li><li><p><strong>You need to install Telerik UI for .NET MAUI.</strong> This is a one-time setup, meaning you don&rsquo;t need to do it for every component you use. (If you don&rsquo;t have it installed yet, I&rsquo;ve included an article where it is explained step by step how to set it up in both <a target="_blank" href="https://www.telerik.com/maui-ui/documentation/get-started/first-steps-vs">Visual Studio</a> and <a target="_blank" href="https://www.telerik.com/maui-ui/documentation/get-started/first-steps-vs-code">Visual Studio Code</a>).</p></li></ol><p>Once you have these two points ready, go to your XAML and follow these steps:</p><ol><li>Add the following namespace:</li></ol><pre class=" language-xml"><code class="prism  language-xml">xmlns:telerik="clr-namespace:Telerik.Maui.Controls;assembly=Telerik.Maui.Controls"
</code></pre><ol start="2"><li>Add a RadBorder to serve as the main container. Configure it with a background color of #29b7fc, a CornerRadius of 30, and apply Padding and Margin to control internal and external spacing, respectively.</li></ol><pre class=" language-xml"><code class="prism  language-xml">&lt;telerik:RadBorder VerticalOptions="Fill" 
    BackgroundColor="#29b7fc" 
    CornerRadius="30" 
    Padding="30" 
    Margin="20"&gt; 
    
&lt;!-- Please add the code for the following block here. --&gt;     

&lt;/telerik:RadBorder&gt;
</code></pre><h2 id="passenger-information-block">2. Passenger Information Block</h2><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/02_second_block_design.png?sfvrsn=8856c19b_2" title="Second block design" alt="Second block design: passenger info" /></p><p>This second block contains approximately 95% of the remaining UI design. This is where we will display the ticket details, such as the airline name, origin and destination (from, to), gate and the customer&rsquo;s name.</p><p>We will start by adding a Grid. This will allow us, in the next block, to apply the rounded side cut effect that makes the design resemble a ticket.</p><p>⚠️ <strong>Note:</strong> This Grid must be added exactly on the line in the previous code block that says:</p><pre class=" language-xml"><code class="prism  language-xml">&lt;!-- Please add the code for the following block here. --&gt;

&lt;Grid RowDefinitions="auto,auto" 
    ColumnDefinitions="*,*"&gt;" 
    &lt;!-- Add the border here --&gt; 
&lt;/Grid&gt;
</code></pre><p>Now, add a border with a white background. We will continue using the Telerik <strong>RadBorder</strong> control to maintain design consistency.</p><pre class=" language-xml"><code class="prism  language-xml">    &lt;telerik:RadBorder Grid.Row="0" Grid.Column="0" 
    Grid.ColumnSpan="2" 
    BackgroundColor="White" 
    VerticalOptions="Fill" 
    CornerRadius="30" 
    Padding="30"&gt; 

    &lt;!-- Add the Grid here --&gt; 
    
    &lt;/telerik:RadBorder&gt; 
    
    &lt;!-- Add the circles here --&gt;
</code></pre><p>Inside this RadBorder, we will add another Grid to organize all the ticket information.</p><p>This Grid will have three columns and fourteen rows, giving us the structure needed to properly arrange each element in the UI.</p><pre class=" language-xml"><code class="prism  language-xml">&lt;Grid ColumnDefinitions="*,auto,*" 
    RowDefinitions="auto,auto,auto,auto,auto,auto,auto,auto,auto,auto,auto,auto,auto,auto" 
    RowSpacing="20"&gt;
 
    &lt;!--Add all the information here -- &gt; 

&lt;/Grid&gt;
</code></pre><p>Finally, let&rsquo;s add all the passenger information. For the first section, we will use a HorizontalStackLayout, while the remaining structure will be built using Label elements, Line elements and a sample image to represent the barcode.</p><pre class=" language-xml"><code class="prism  language-xml">&lt;HorizontalStackLayout Grid.Column="0" 
    Grid.ColumnSpan="3" Grid.Row="0" 
    Spacing="20" 
    VerticalOptions="Center"&gt; 
    &lt;Image Source="arrowlogo.png" 
    HeightRequest="40" 
    Aspect="AspectFill" 
    WidthRequest="40" /&gt; 
    &lt;Label Text="United Airlines" FontSize="15" FontAttributes="Bold" VerticalTextAlignment="Center"/&gt; 
&lt;/HorizontalStackLayout&gt;
 
&lt;Line Grid.Row="1" Stroke="LightGrey" StrokeThickness="0.6" X2="800" HorizontalOptions="Center"/&gt;
 
&lt;Image Grid.Row="2" Grid.Column="1" Source="airplane" HeightRequest="13" WidthRequest="13"/&gt; 

&lt;Label Grid.Row="2" Grid.Column="0" Text="From" FontSize="10" TextColor="Gray"/&gt;

&lt;Label Grid.Row="3" Grid.Column="0" Text="LAX" FontSize="16" FontAttributes="Bold" /&gt;

&lt;Label Grid.Row="4" Grid.Column="0" Text="Los Angeles, USA &amp;#10;5:05, Mon 16 Aug&amp;#10;Terminal 1" FontSize="10" TextColor="Gray" /&gt;

&lt;Label Grid.Row="2" Grid.Column="2" Text="NYC" HorizontalTextAlignment="End" FontSize="10" TextColor="Gray" /&gt;

&lt;Label Grid.Row="3" Grid.Column="2" Text="LAX" HorizontalTextAlignment="End" FontSize="16" FontAttributes="Bold"/&gt;

&lt;Label Grid.Row="4" Grid.Column="2" Text="New York, USA&amp;#10;10:55, Mon. 15 Aug&amp;#10;Terminal 1" HorizontalTextAlignment="End" FontSize="10" TextColor="Gray" /&gt;
 
&lt;Line Grid.Row="5" Stroke="LightGrey" StrokeThickness="0.6" X2="800" HorizontalOptions="Center"/&gt; 

&lt;Label Grid.Row="6" Grid.Column="0" Text="Gate" FontSize="10" TextColor="Gray" /&gt;

&lt;Label Grid.Row="7" Grid.Column="0" Text="C2" FontSize="15" FontAttributes="Bold"/&gt;
 
&lt;Label Grid.Row="6" Grid.Column="2" Text="Seat Place" FontSize="10" TextColor="Gray"/&gt;

&lt;Label Grid.Row="7" Grid.Column="2" Text="B2" FontSize="15" FontAttributes="Bold" /&gt;
 
&lt;Line Grid.Row="8" Stroke="LightGrey" StrokeThickness="0.6" X2="800" HorizontalOptions="Center" /&gt;
 
&lt;Label Grid.Row="9" Grid.Column="0" Text="Full Name" FontSize="10" TextColor="Gray" /&gt;

&lt;Label Grid.Row="10" Grid.Column="0" Text="Tom Smith" FontSize="15" FontAttributes="Bold"/&gt; 

&lt;Label Grid.Row="9" Grid.Column="2" Text="Class" FontSize="10" TextColor="Gray"/&gt;

&lt;Label Grid.Row="10" Grid.Column="2" Text="Economy" FontSize="15" FontAttributes="Bold" /&gt;
 
&lt;Line Grid.Row="11" Stroke="LightGrey" StrokeThickness="0.6" X2="800" HorizontalOptions="Center" /&gt; 

&lt;Label Grid.Row="12" Grid.Column="0" Text="Booking Code" FontSize="15" FontAttributes="Bold"/&gt;

&lt;Label Grid.Row="12" Grid.Column="2" Text="G1540D4" FontSize="15" FontAttributes="Bold" /&gt; 

&lt;Image Grid.Row="13" Grid.Column="0" Grid.ColumnSpan="3" Source="barcodesample" Aspect="Fill"/&gt;
</code></pre><h2 id="perforated-edges-block">3. Perforated Edges Block</h2><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/03_third_block_design.png?sfvrsn=a6c89f1e_2" title="Third block design" alt="Third block design - perforated edges" /></p><p>Now, we are adding the finishing touch to this UI: simulating the ticket side cutouts on the white background Border. To achieve this, we will use the Ellipse shape from .NET MAUI.</p><p>We will add two Ellipse elements, one on each side, to recreate the visual effect of a ticket.</p><pre class=" language-xml"><code class="prism  language-xml">&lt;Ellipse Grid.Row="0" Grid.Column="0" 
    HeightRequest="60" 
    TranslationX="-130" 
    TranslationY="130" 
    Fill="#29b7fc"/&gt;
 
&lt;Ellipse Grid.Row="0" Grid.Column="1" 
    HeightRequest="60" 
    TranslationX="130" 
    TranslationY="130" 
    Fill="#29b7fc"/&gt;
</code></pre><p>⚠️ Please note: this code must be placed exactly in one of the sections of the second block where it says: <code>&lt;!-- Add the circles here --&gt;</code>.</p><h2 id="conclusion">Conclusion</h2><p>And that&rsquo;s it!  In this article, we explored how to build a ticket screen using .NET MAUI with XAML, recreating a modern and visually appealing boarding pass design.</p><p>I hope this guide helps you understand how to approach similar UI challenges and inspires you to recreate more complex designs in your own .NET MAUI applications.</p><p>If you have any questions or would like me to explore a specific part in more detail, feel free to leave a comment&mdash;I&rsquo;ll be happy to help! </p><p>See you in the next article! &zwj;♀️</p><p>If you want to learn more about Ellipse in .NET MAUI, I invite you to read the <a target="_blank" href="https://learn.microsoft.com/en-us/dotnet/maui/user-interface/controls/shapes/ellipse?view=net-maui-10.0">Microsoft Learn article</a>. It is a very useful element for creating creative UI designs.</p><h3 id="additional-resources">Additional Resources</h3><p>I invite you to learn more about the Telerik RadBorder.</p><ul><li><a target="_blank" href="https://www.telerik.com/maui-ui/border">Here you can explore the main features and benefits of the product.</a></li><li><a target="_blank" href="https://www.telerik.com/maui-ui/documentation/controls/border/getting-started">Here you can review its technical implementation.</a></li><li>And, don&rsquo;t forget: You can <a target="_blank" href="https://www.telerik.com/try/ui-for-maui"><strong>try Telerik UI for .NET MAUI free for 30 days</strong></a>. </li></ul>]]></content>
  </entry>
  <entry>
    <id>urn:uuid:edd3110a-7b4d-4f43-8db1-b9001b1e73be</id>
    <title type="text">Creating Localized .NET MAUI Applications</title>
    <summary type="text">Reach more people with your apps: Learn how to localize .NET MAUI applications, including XAML text elements, view models and prebuilt Telerik controls for .NET MAUI.</summary>
    <published>2026-06-17T20:17:33Z</published>
    <updated>2026-07-12T05:29:41Z</updated>
    <author>
      <name>Héctor Pérez </name>
    </author>
    <link rel="alternate" href="https://www.telerik.com/blogs/creating-localized-net-maui-applications?utm_medium=feed&amp;utm_source=feedpress.me&amp;utm_campaign=Feed%3A+telerik-blogs-desktop"/>
    <content type="text"><![CDATA[<p><span class="featured">Reach more people with your apps: Learn how to localize .NET MAUI applications, including XAML text elements, view models and prebuilt Telerik controls for .NET MAUI.</span></p><p>Making our mobile applications accessible to users who speak a different language than us can make a huge difference in their usage. Fortunately, .NET MAUI offers the power to deliver multi-language applications thanks to the use of resources files.</p><p>Likewise, prebuilt controls such as those from Progress <a href="https://www.telerik.com/maui-ui">Telerik UI for .NET MAUI</a> can be adapted to support localization, allowing you to build and deliver native language experiences quickly. Let&rsquo;s see how to do it!</p><h2 id="understanding-localization-in-.net-maui-apps">Understanding Localization in .NET MAUI Apps</h2><p>Localization is the process of enabling an application to support different languages and cultures; that is, it&rsquo;s not only about translating text strings to other languages, but also adapting date formats, numbers, etc.</p><p>There are some key elements for localizing applications, the first of which are the resource files <strong>.resx</strong>, which are XML files composed of key-value pairs for each language.</p><p>Likewise, we have the class <code>CultureInfo</code>, which represents the user&rsquo;s cultural information. Finally, the class <code>ResourceManager</code> is a class that allows us at runtime to retrieve localized strings according to the language selected on the user&rsquo;s device.</p><h2 id="creating-a-sample-app-to-localize">Creating a Sample App to Localize</h2><p>To show you in a practical way how to integrate localization into your own projects, let&rsquo;s create a test project. To do so, create a new .NET MAUI project without example content, and follow the <a href="https://www.telerik.com/maui-ui/documentation/get-started/first-steps-vs#step-1-set-up-your-net-maui-application">installation guide to add Telerik controls for .NET MAUI</a> to the project.</p><p>Also install the NuGet package <code>CommunityToolkit.Mvvm</code> to create viewmodels cleanly. Once the project has been configured, create a data model to represent a <code>Product</code>:</p><pre class=" language-csharp"><code class="prism  language-csharp"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">Product</span>
<span class="token punctuation">{</span>
    <span class="token keyword">public</span> <span class="token keyword">string</span> Name <span class="token punctuation">{</span> <span class="token keyword">get</span><span class="token punctuation">;</span> <span class="token keyword">set</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token keyword">string</span><span class="token punctuation">.</span>Empty<span class="token punctuation">;</span>
    <span class="token keyword">public</span> <span class="token keyword">string</span> Category <span class="token punctuation">{</span> <span class="token keyword">get</span><span class="token punctuation">;</span> <span class="token keyword">set</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token keyword">string</span><span class="token punctuation">.</span>Empty<span class="token punctuation">;</span>
    <span class="token keyword">public</span> <span class="token keyword">decimal</span> Price <span class="token punctuation">{</span> <span class="token keyword">get</span><span class="token punctuation">;</span> <span class="token keyword">set</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
    <span class="token keyword">public</span> DateTime CreatedDate <span class="token punctuation">{</span> <span class="token keyword">get</span><span class="token punctuation">;</span> <span class="token keyword">set</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><p>Next, let&rsquo;s create a viewmodel that will display information in the UI for a set of fictitious products:</p><pre class=" language-csharp"><code class="prism  language-csharp"><span class="token keyword">public</span> <span class="token keyword">partial</span> <span class="token keyword">class</span> <span class="token class-name">MainViewModel</span> <span class="token punctuation">:</span> ObservableObject
<span class="token punctuation">{</span>
    <span class="token punctuation">[</span>ObservableProperty<span class="token punctuation">]</span>
    <span class="token keyword">private</span> ObservableCollection<span class="token operator">&lt;</span>Product<span class="token operator">&gt;</span> products <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span>

    <span class="token punctuation">[</span>ObservableProperty<span class="token punctuation">]</span>
    <span class="token keyword">private</span> DateTime<span class="token operator">?</span> selectedDate<span class="token punctuation">;</span>

    <span class="token keyword">public</span> <span class="token function">MainViewModel</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
    <span class="token punctuation">{</span>
        SelectedDate <span class="token operator">=</span> DateTime<span class="token punctuation">.</span>Now<span class="token punctuation">;</span>
        <span class="token function">LoadProducts</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token keyword">private</span> <span class="token keyword">void</span> <span class="token function">LoadProducts</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
    <span class="token punctuation">{</span>
        Products <span class="token operator">=</span>
        <span class="token punctuation">[</span>
            <span class="token keyword">new</span> <span class="token class-name">Product</span>
            <span class="token punctuation">{</span>
                Name <span class="token operator">=</span> <span class="token string">"Laptop Pro 15"</span><span class="token punctuation">,</span>
                Category <span class="token operator">=</span> <span class="token string">"Electronics"</span><span class="token punctuation">,</span>
                Price <span class="token operator">=</span> <span class="token number">1299</span><span class="token punctuation">.</span>99m<span class="token punctuation">,</span>
                CreatedDate <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">DateTime</span><span class="token punctuation">(</span><span class="token number">2026</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">15</span><span class="token punctuation">)</span>
            <span class="token punctuation">}</span><span class="token punctuation">,</span>
            <span class="token keyword">new</span> <span class="token class-name">Product</span>
            <span class="token punctuation">{</span>
                Name <span class="token operator">=</span> <span class="token string">"Running Shoes"</span><span class="token punctuation">,</span>
                Category <span class="token operator">=</span> <span class="token string">"Clothing"</span><span class="token punctuation">,</span>
                Price <span class="token operator">=</span> <span class="token number">89</span><span class="token punctuation">.</span>95m<span class="token punctuation">,</span>
                CreatedDate <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">DateTime</span><span class="token punctuation">(</span><span class="token number">2026</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">20</span><span class="token punctuation">)</span>
            <span class="token punctuation">}</span><span class="token punctuation">,</span>
            <span class="token keyword">new</span> <span class="token class-name">Product</span>
            <span class="token punctuation">{</span>
                Name <span class="token operator">=</span> <span class="token string">"Organic Coffee Beans"</span><span class="token punctuation">,</span>
                Category <span class="token operator">=</span> <span class="token string">"Food"</span><span class="token punctuation">,</span>
                Price <span class="token operator">=</span> <span class="token number">24</span><span class="token punctuation">.</span>50m<span class="token punctuation">,</span>
                CreatedDate <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">DateTime</span><span class="token punctuation">(</span><span class="token number">2026</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">,</span> <span class="token number">10</span><span class="token punctuation">)</span>
            <span class="token punctuation">}</span><span class="token punctuation">,</span>
            <span class="token keyword">new</span> <span class="token class-name">Product</span>
            <span class="token punctuation">{</span>
                Name <span class="token operator">=</span> <span class="token string">"Wireless Mouse"</span><span class="token punctuation">,</span>
                Category <span class="token operator">=</span> <span class="token string">"Electronics"</span><span class="token punctuation">,</span>
                Price <span class="token operator">=</span> <span class="token number">45</span><span class="token punctuation">.</span>00m<span class="token punctuation">,</span>
                CreatedDate <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">DateTime</span><span class="token punctuation">(</span><span class="token number">2025</span><span class="token punctuation">,</span> <span class="token number">12</span><span class="token punctuation">,</span> <span class="token number">5</span><span class="token punctuation">)</span>
            <span class="token punctuation">}</span><span class="token punctuation">,</span>
            <span class="token keyword">new</span> <span class="token class-name">Product</span>
            <span class="token punctuation">{</span>
                Name <span class="token operator">=</span> <span class="token string">"Winter Jacket"</span><span class="token punctuation">,</span>
                Category <span class="token operator">=</span> <span class="token string">"Clothing"</span><span class="token punctuation">,</span>
                Price <span class="token operator">=</span> <span class="token number">159</span><span class="token punctuation">.</span>99m<span class="token punctuation">,</span>
                CreatedDate <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">DateTime</span><span class="token punctuation">(</span><span class="token number">2026</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">28</span><span class="token punctuation">)</span>
            <span class="token punctuation">}</span>
        <span class="token punctuation">]</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><p>In the code above, you can notice that hard-coded strings in English are used to display information to users only in that language. Now, let&rsquo;s create an example UI, using a <a href="https://www.telerik.com/maui-ui/datepicker">.NET MAUI RadDatePicker</a> (which is an enhanced DatePicker) and a <a href="https://www.telerik.com/maui-ui/datagrid">MAUI RadDataGrid</a> to easily display data tables:</p><pre class=" language-xml"><code class="prism  language-xml"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>Grid</span>
 <span class="token attr-name">Padding</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>16<span class="token punctuation">"</span></span>
 <span class="token attr-name">RowDefinitions</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Auto,Auto,*<span class="token punctuation">"</span></span>
 <span class="token attr-name">RowSpacing</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>12<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
 <span class="token comment">&lt;!--  Welcome message  --&gt;</span>
 <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>Label</span>
     <span class="token attr-name">FontAttributes</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Bold<span class="token punctuation">"</span></span>
     <span class="token attr-name">FontSize</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>20<span class="token punctuation">"</span></span>
     <span class="token attr-name">HorizontalOptions</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Center<span class="token punctuation">"</span></span>
     <span class="token attr-name">Text</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Welcome to the app<span class="token punctuation">"</span></span> <span class="token punctuation">/&gt;</span></span>
 <span class="token comment">&lt;!--  Date picker  --&gt;</span>
 <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>HorizontalStackLayout</span>
     <span class="token attr-name">Grid.Row</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>1<span class="token punctuation">"</span></span>
     <span class="token attr-name">HorizontalOptions</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Center<span class="token punctuation">"</span></span>
     <span class="token attr-name">Spacing</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>10<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
     <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>Label</span>
         <span class="token attr-name">FontSize</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>16<span class="token punctuation">"</span></span>
         <span class="token attr-name">Text</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Created Date<span class="token punctuation">"</span></span>
         <span class="token attr-name">VerticalOptions</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Center<span class="token punctuation">"</span></span> <span class="token punctuation">/&gt;</span></span>
     <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span><span class="token namespace">telerik:</span>RadDatePicker</span>
         <span class="token attr-name">Date</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>{Binding SelectedDate}<span class="token punctuation">"</span></span>         
         <span class="token attr-name">WidthRequest</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>250<span class="token punctuation">"</span></span> <span class="token punctuation">/&gt;</span></span>
 <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>HorizontalStackLayout</span><span class="token punctuation">&gt;</span></span>
 <span class="token comment">&lt;!--  Product grid  --&gt;</span>
 <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span><span class="token namespace">telerik:</span>RadDataGrid</span>
     <span class="token attr-name">Grid.Row</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>2<span class="token punctuation">"</span></span>
     <span class="token attr-name">AutoGenerateColumns</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>False<span class="token punctuation">"</span></span>
     <span class="token attr-name">ItemsSource</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>{Binding Products}<span class="token punctuation">"</span></span>
     <span class="token attr-name">UserFilterMode</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Auto<span class="token punctuation">"</span></span>
     <span class="token attr-name">UserGroupMode</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Auto<span class="token punctuation">"</span></span>
     <span class="token attr-name">UserSortMode</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Auto<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
     <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span><span class="token namespace">telerik:</span>RadDataGrid.Columns</span><span class="token punctuation">&gt;</span></span>
         <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span><span class="token namespace">telerik:</span>DataGridTextColumn</span> <span class="token attr-name">HeaderText</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Product Name<span class="token punctuation">"</span></span> <span class="token attr-name">PropertyName</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Name<span class="token punctuation">"</span></span> <span class="token punctuation">/&gt;</span></span>
         <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span><span class="token namespace">telerik:</span>DataGridTextColumn</span> <span class="token attr-name">HeaderText</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Category<span class="token punctuation">"</span></span> <span class="token attr-name">PropertyName</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Category<span class="token punctuation">"</span></span> <span class="token punctuation">/&gt;</span></span>
         <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span><span class="token namespace">telerik:</span>DataGridNumericalColumn</span>
             <span class="token attr-name">CellContentFormat</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>{}{0:C}<span class="token punctuation">"</span></span>
             <span class="token attr-name">HeaderText</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Price<span class="token punctuation">"</span></span>
             <span class="token attr-name">PropertyName</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Price<span class="token punctuation">"</span></span> <span class="token punctuation">/&gt;</span></span>
         <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span><span class="token namespace">telerik:</span>DataGridDateColumn</span>
             <span class="token attr-name">CellContentFormat</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>{}{0:d}<span class="token punctuation">"</span></span>
             <span class="token attr-name">HeaderText</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Created Date<span class="token punctuation">"</span></span>
             <span class="token attr-name">PropertyName</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>CreatedDate<span class="token punctuation">"</span></span> <span class="token punctuation">/&gt;</span></span>
     <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span><span class="token namespace">telerik:</span>RadDataGrid.Columns</span><span class="token punctuation">&gt;</span></span>
 <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span><span class="token namespace">telerik:</span>RadDataGrid</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>Grid</span><span class="token punctuation">&gt;</span></span>
</code></pre><p>Don&rsquo;t forget to register both <code>MainPage</code> and <code>MainPageViewModel</code> in the dependency container:</p><pre class=" language-csharp"><code class="prism  language-csharp"><span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">class</span> <span class="token class-name">MauiProgram</span>
<span class="token punctuation">{</span>
    <span class="token keyword">public</span> <span class="token keyword">static</span> MauiApp <span class="token function">CreateMauiApp</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
    <span class="token punctuation">{</span>
        <span class="token keyword">var</span> builder <span class="token operator">=</span> MauiApp<span class="token punctuation">.</span><span class="token function">CreateBuilder</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>       
        <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>
        builder<span class="token punctuation">.</span>Services<span class="token punctuation">.</span><span class="token generic-method function">AddTransient<span class="token punctuation">&lt;</span>MainPage<span class="token punctuation">&gt;</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        builder<span class="token punctuation">.</span>Services<span class="token punctuation">.</span><span class="token generic-method function">AddTransient<span class="token punctuation">&lt;</span>MainViewModel<span class="token punctuation">&gt;</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>
        <span class="token keyword">return</span> builder<span class="token punctuation">.</span><span class="token function">Build</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><p>Finally, let&rsquo;s inject the view model into the page&rsquo;s code-behind, while assigning the injected reference to <code>BindingContext</code>:</p><pre class=" language-csharp"><code class="prism  language-csharp"><span class="token keyword">public</span> <span class="token keyword">partial</span> <span class="token keyword">class</span> <span class="token class-name">MainPage</span> <span class="token punctuation">:</span> ContentPage
<span class="token punctuation">{</span>
    <span class="token keyword">public</span> <span class="token function">MainPage</span><span class="token punctuation">(</span>MainViewModel viewModel<span class="token punctuation">)</span>
    <span class="token punctuation">{</span>
        <span class="token function">InitializeComponent</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        BindingContext <span class="token operator">=</span> viewModel<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><p>After implementing the above changes, we will have a UI like the following:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/base-app-product-grid-english.png?sfvrsn=287ffbd9_2" alt="Product grid in base app with English labels" /></p><p>As we anticipated, all the UI content is in English. Some text chunks we might want to internationalize could be the page title, the welcome message, column headers, product categories, etc. Let&rsquo;s see how to achieve it.</p><h2 id="creating-resource-files-to-localize-a-.net-maui-app">Creating Resource Files to Localize a .NET MAUI App</h2><p>Localization of .NET applications is based on resource files. To create these files, you must start by creating a file with the extension <code>.resx</code>, which will contain the strings in the original language.</p><p>In our example, we are going to create a new folder <code>Resources/Strings</code>, and inside create a file named <code>AppStrings.resx</code>. You can achieve this using the context menu on the created folder, selecting <strong>Add</strong> | <strong>New Item</strong>. Then, in the search box enter the term <strong>resources</strong>, which will filter the template for the resource file:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/selecting-resource-template.png?sfvrsn=943723e7_2" alt="Selecting the appropriate template for a resource file" /></p><p>Once you have created the file, you can open it and start adding the application&rsquo;s strings in their original language, using the <strong>+</strong> button. This will open a new window where you can enter information such as the string key, the data type, the value and optionally comments:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/adding-localization-string.png?sfvrsn=68f8fbaf_2" alt="Developer adding a new localization string in editor" /></p><p>Another way to add strings more quickly is to paste them in the format: <strong>Key name</strong> + <strong>tab</strong> + <strong>value</strong>. For example, you can copy and paste the following content, and paste it directly into the resource editor, which will create a series of rows in the file:</p><pre class=" language-text"><code class="prism  language-text">LanguageLabelLanguage
ProductNameProduct Name
CategoryCategory
PricePrice
CreatedDateCreated Date
SelectLanguageSelect a language
ElectronicsElectronics
ClothingClothing
FoodFood
FilterProductsFilter Products
WelcomeWelcome to the localized app
</code></pre><p>After having the base file, the next step is to create an additional resource file for each translation you want to perform. For the example, I will create a new file in <code>Resources/Strings</code> called <code>AppStrings.es.resx</code>. You can notice that each new file must be named the same as the main one, adding the ISO code of the language you want to translate to.</p><p>When you open the file, you will see that a new column has been added, where you can enter the information of the file, as in the following example:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/resx-translation-strings.png?sfvrsn=9ced7f57_2" alt="Resx files showing original and translated string values" /></p><p>With the resource files created, it is time to connect the strings with the UI.</p><h2 id="localizing-elements-in-the-ui">Localizing Elements in the UI</h2><p>With the strings correctly localized, let&rsquo;s go to the UI page. There, you need to add a namespace for the path where the localized files are located, similar to this:</p><pre class=" language-xml"><code class="prism  language-xml"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>ContentPage</span>
    <span class="token attr-name">...</span>
    <span class="token attr-name"><span class="token namespace">xmlns:</span>resx</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>clr-namespace:MauiLocalizedApps.Resources.Strings<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
</code></pre><p>Then, on each element you want to localize you must use the markup extension <code>x:Static</code>, using the key of the resource you want to replace. This is an example of the Label control corresponding to the localized welcome message:</p><pre class=" language-xml"><code class="prism  language-xml"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>Label</span>
<span class="token attr-name">...</span>
    <span class="token attr-name">Text</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>{x:Static resx:AppStrings.Welcome}<span class="token punctuation">"</span></span> <span class="token punctuation">/&gt;</span></span>
</code></pre><p>Other strings we will replace will be the creation date and the welcome one, as shown below:</p><pre class=" language-xml"><code class="prism  language-xml"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>ContentPage</span> <span class="token attr-name">...</span>
    <span class="token attr-name">Title</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>{x:Static resx:AppStrings.AppTitle}<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>

 <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>Grid</span>
     <span class="token attr-name">Padding</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>16<span class="token punctuation">"</span></span>
     <span class="token attr-name">RowDefinitions</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Auto,Auto,*<span class="token punctuation">"</span></span>
     <span class="token attr-name">RowSpacing</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>12<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
     <span class="token comment">&lt;!--  Welcome message  --&gt;</span>
     <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>Label</span>
         <span class="token attr-name">FontAttributes</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Bold<span class="token punctuation">"</span></span>
         <span class="token attr-name">FontSize</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>20<span class="token punctuation">"</span></span>
         <span class="token attr-name">HorizontalOptions</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Center<span class="token punctuation">"</span></span>
         <span class="token attr-name">Text</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>{x:Static resx:AppStrings.Welcome}<span class="token punctuation">"</span></span> <span class="token punctuation">/&gt;</span></span>
     <span class="token comment">&lt;!--  Date picker  --&gt;</span>
     <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>HorizontalStackLayout</span>
         <span class="token attr-name">Grid.Row</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>1<span class="token punctuation">"</span></span>
         <span class="token attr-name">HorizontalOptions</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Center<span class="token punctuation">"</span></span>
         <span class="token attr-name">Spacing</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>10<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
         <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>Label</span>
             <span class="token attr-name">FontSize</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>16<span class="token punctuation">"</span></span>
             <span class="token attr-name">Text</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>{x:Static resx:AppStrings.CreatedDate}<span class="token punctuation">"</span></span>
             <span class="token attr-name">VerticalOptions</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Center<span class="token punctuation">"</span></span> <span class="token punctuation">/&gt;</span></span>
         <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span><span class="token namespace">telerik:</span>RadDatePicker</span> <span class="token attr-name">Date</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>{Binding SelectedDate}<span class="token punctuation">"</span></span> <span class="token attr-name">WidthRequest</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>250<span class="token punctuation">"</span></span> <span class="token punctuation">/&gt;</span></span>
     <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>HorizontalStackLayout</span><span class="token punctuation">&gt;</span></span>
     ...
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>Grid</span><span class="token punctuation">&gt;</span></span>     
</code></pre><p>After applying the changes and changing the device language to Spanish, we get the following result:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/xaml-spanish-localized-strings.png?sfvrsn=7b00648d_2" alt="Screenshot of XAML file with Spanish localized strings" /></p><p>Now, let&rsquo;s see how to localize the view model strings.</p><h2 id="localizing-data-strings-from-the-viewmodel">Localizing Data Strings from the viewmodel</h2><p>In addition to localizing elements in the XAML file, we can also load translated strings that are found in the view model. For example, suppose we want to translate the names of the categories shown in the DataGrid.</p><p>To achieve this, we can use the static class that is created when we create a resource file, which takes the same name as the created file. In our case it is called <code>AppStrings</code>, and we will use it as follows:</p><pre class=" language-csharp"><code class="prism  language-csharp"><span class="token keyword">private</span> <span class="token keyword">void</span> <span class="token function">LoadProducts</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
    Products <span class="token operator">=</span>
    <span class="token punctuation">[</span>
        <span class="token keyword">new</span> <span class="token class-name">Product</span>
        <span class="token punctuation">{</span>
            <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>
            Category <span class="token operator">=</span> AppStrings<span class="token punctuation">.</span>Electronics
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
        <span class="token keyword">new</span> <span class="token class-name">Product</span>
        <span class="token punctuation">{</span>
            <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>
            Category <span class="token operator">=</span> AppStrings<span class="token punctuation">.</span>Clothing<span class="token punctuation">,</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
        <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>
    <span class="token punctuation">]</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><p>With the previous changes, we have seen how to display translated strings to the user found in XAML files and view models:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/localized-viewmodel-text.png?sfvrsn=f3f493dc_2" alt="Localized text rendered from view models in interface" /></p><p>However, we still have strings in the graphical controls that have not been localized. Let&rsquo;s see how to translate them.</p><h2 id="localizing-internal-strings-of-telerik-controls-for-.net-maui">Localizing Internal Strings of Telerik Controls for .NET MAUI</h2><p>In case you also want to localize the strings of Telerik controls, such as those that show options in the DataGrid, you can see all the keys used in the controls on the <a href="https://www.telerik.com/maui-ui/documentation/globalization-localization">.NET MAUI globalization and localization</a> page. On that page you will find links for each control and their respective strings.</p><p>For example, to localize the .NET MAUI DataGrid, we must copy a series of keys that start with <code>DataGrid_...</code>, such as <code>DataGrid_DistinctValues_SelectAll</code>, <code>DataGrid_Filter_ApplyFilter</code>, <code>DataGrid_Filter_ResetFilter</code>, etc. These are the keys that I will add to the file <code>AppStrings.resx</code>.</p><p>After doing this, you must create a class that inherits from <code>TelerikLocalizationManager</code>, like the one shown below:</p><pre class=" language-csharp"><code class="prism  language-csharp"><span class="token keyword">internal</span> <span class="token keyword">class</span> <span class="token class-name">CustomLocalizationManager</span> <span class="token punctuation">:</span> TelerikLocalizationManager
<span class="token punctuation">{</span>
    <span class="token keyword">public</span> <span class="token keyword">override</span> <span class="token keyword">string</span> <span class="token function">GetString</span><span class="token punctuation">(</span><span class="token keyword">string</span> key<span class="token punctuation">)</span>
    <span class="token punctuation">{</span>
        <span class="token keyword">string</span><span class="token operator">?</span> localizedValue <span class="token operator">=</span> AppStrings<span class="token punctuation">.</span>ResourceManager<span class="token punctuation">.</span><span class="token function">GetString</span><span class="token punctuation">(</span>
            key<span class="token punctuation">,</span> CultureInfo<span class="token punctuation">.</span>CurrentUICulture<span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span><span class="token keyword">string</span><span class="token punctuation">.</span><span class="token function">IsNullOrEmpty</span><span class="token punctuation">(</span>localizedValue<span class="token punctuation">)</span><span class="token punctuation">)</span>
        <span class="token punctuation">{</span>
            <span class="token keyword">return</span> localizedValue<span class="token punctuation">;</span>
        <span class="token punctuation">}</span>

        <span class="token keyword">return</span> <span class="token keyword">base</span><span class="token punctuation">.</span><span class="token function">GetString</span><span class="token punctuation">(</span>key<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><p>In the code above, we use the <code>GetString</code> method to attempt to retrieve a key and its translated value in the device&rsquo;s language. If a translated string is found it is returned; otherwise the original value is returned.</p><p>Finally, you must register the created manager in <code>MauiProgram.cs</code> as follows:</p><pre class=" language-csharp"><code class="prism  language-csharp"><span class="token keyword">public</span> <span class="token keyword">static</span> MauiApp <span class="token function">CreateMauiApp</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
    <span class="token keyword">var</span> builder <span class="token operator">=</span> MauiApp<span class="token punctuation">.</span><span class="token function">CreateBuilder</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>
    TelerikLocalizationManager<span class="token punctuation">.</span>Manager <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">CustomLocalizationManager</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>
    <span class="token keyword">return</span> builder<span class="token punctuation">.</span><span class="token function">Build</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><p>When running the app, we will get the following result:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/telerik-datagrid-spanish-strings.gif?sfvrsn=cd4718ff_2" alt="Telerik DataGrid displaying Spanish localization strings" /></p><p>In the image above you can see how the DataGrid options are displayed translated into Spanish. With this, we have finished localizing the strings in our application.</p><h2 id="conclusion">Conclusion</h2><p>Throughout this article you&rsquo;ve seen how to localize .NET MAUI applications. You&rsquo;ve seen how to translate text elements found in XAML files, view models and even prebuilt Telerik controls for .NET MAUI. Now it&rsquo;s your time to reach more people with your apps by using localization through resource files.</p><blockquote><p>Try out Telerik UI for .NET MAUI free for 30 days.</p><p>&nbsp;</p><p><a target="_blank" href="https://www.telerik.com/try/ui-for-maui" class="Btn">Try Now</a></p></blockquote>]]></content>
  </entry>
  <entry>
    <id>urn:uuid:9c42fac5-42a2-417f-b5a6-e359bcaadc44</id>
    <title type="text">SCIM Provisioning for DevCraft Subscriptions: Automating License Management for Your Teams</title>
    <summary type="text">Progress DevCraft Complete and DevCraft Ultimate subscription licenses just got a whole lot easier to manage across your team with SCIM provisioning.</summary>
    <published>2026-06-10T18:13:57Z</published>
    <updated>2026-07-12T05:29:41Z</updated>
    <author>
      <name>Dragan Grigorov </name>
    </author>
    <link rel="alternate" href="https://www.telerik.com/blogs/scim-provisioning-telerik-kendo-ui-licenses?utm_medium=feed&amp;utm_source=feedpress.me&amp;utm_campaign=Feed%3A+telerik-blogs-desktop"/>
    <content type="text"><![CDATA[<p><span class="featured">Progress DevCraft Complete and DevCraft Ultimate subscription licenses just got a whole lot easier to manage across your team with SCIM provisioning.</span></p><p>Managing access across growing development teams can quickly become time-consuming when done manually.</p><p>That&rsquo;s why we&rsquo;re introducing <strong>System for Cross-domain Identity Management (SCIM)</strong> for Progress DevCraft Complete and DevCraft Ultimate subscription licenses, along with Fiddler and ThemeBuilder Enterprise licenses&mdash;bringing automated license seat management directly into your organization&rsquo;s Identity Provider.</p><p>If <strong>SSO simplified how your team signs in</strong>, SCIM extends that experience by <strong>automating how access is assigned and maintained</strong>.</p><p> If you haven&rsquo;t set up SSO yet, follow the steps in our <a target="_blank" href="https://www.telerik.com/blogs/sso-telerik-kendo-ui-simpler-more-secure-access-account">SSO guide</a>.</p><h2 id="what-is-scim-and-why-it-matters">What Is SCIM and Why It Matters</h2><p>For customers using <strong>DevCraft Complete and Ultimate subscription licenses</strong>, as well as <strong>Fiddler</strong> and <strong>ThemeBuilder Enterprise licenses</strong>, SCIM allows license access to be managed directly through your organization&rsquo;s Identity Provider (IdP), such as Microsoft Entra ID or Okta.</p><p>Instead of managing users separately in Telerik, access becomes part of your existing internal processes. When developers are assigned to the right group in your IdP, they automatically receive access to their DevCraft subscription. When they are removed, their access is updated accordingly.</p><p>This helps organizations:</p><ul><li>Keep license access aligned with internal systems</li><li>Eliminate manual seat management</li><li>Reduce the risk of unused or outdated assignments</li></ul><p> Your Identity Provider becomes the <strong>single place to manage access</strong> to your licenses.</p><h2 id="how-to-set-it-up">How to Set It Up</h2><p>SCIM builds on top of SSO and is designed to be quick to configure.</p><h3 id="enable-sso">1. Enable SSO</h3><p>SCIM requires SSO to be already configured for your domain.</p><p>If you haven&rsquo;t enabled it yet, follow the steps in our <a target="_blank" href="https://www.telerik.com/blogs/sso-telerik-kendo-ui-simpler-more-secure-access-account">SSO guide</a>.</p><h3 id="open-scim-setup-in-your-telerik-account">2. Open SCIM Setup in Your Telerik Account</h3><ul><li>Go to <a target="_blank" href="https://www.telerik.com/account/sso-management"><strong>Manage SSO and SCIM</strong></a> in your Telerik account.</li><li>Click on <strong>SCIM Setup</strong>.</li></ul><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/scim-setup.png?sfvrsn=5f9e7cc_2" alt="Configure SSO & SCIM: SCIM Setup" /></p><h3 id="generate-your-scim-key">3. Generate Your SCIM Key</h3><p>In the SCIM Setup screen:</p><ul><li>Copy the SCIM URL and use it when configuring your Identity Provider.</li><li>Add a Key Note that should help differentiate your keys in the future.</li><li>Generate and copy the <strong>SCIM API key</strong> and <strong>Finish Setup</strong></li></ul><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/generate-scim-key.png?sfvrsn=8870d1e8_2" alt="SCIM URL, Key Note, Key" /></p><blockquote><p>⚠️ <strong>Important:</strong> Please copy the key, as once the setup is complete, you will no longer have access to the full key.</p></blockquote><p>The generated SCIM API Key will be used as a Bearer authentication token in your IdP.</p><h3 id="configure-scim-in-your-identity-provider">4. Configure SCIM in Your Identity Provider</h3><p>This step connects your Identity Provider with Telerik, allowing it to send user and group updates automatically.</p><p>In your Identity Provider (for example, Okta):</p><ul><li>Add the Telerik SCIM URL.</li><li>Use the generated API key for authentication.</li></ul><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/scim-provision-integration.png?sfvrsn=7651526f_2" alt="Okta window for Telerik SCIM Test App. Provisioning, Integration tab. SCIM 2.0 Base Url, OAuth Bearer Token" /></p><ul><li>Enable provisioning&mdash;verify the Create, Update and Deactivate are enabled.</li></ul><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/okta-scim-provision.png?sfvrsn=59e4ccad_2" alt="Okta window for Telerik SCIM Test App. Provisioning, To App tab. Okta to SCIM. Create users, update user attributes, deactivate users are enabled" /></p><h3 id="map-your-devcraft-license-to-your-idp-group">5. Map Your DevCraft License to Your IdP Group</h3><p>In <a target="_blank" href="https://www.telerik.com/account/sso-management">Manage SSO &amp; SCIM</a> in Your Account:</p><ul><li>Identify your DevCraft Complete or Ultimate subscription license that you want to enable the SCIM feature, and click on <strong>Configure</strong>.</li><li><strong>Enable SCIM Provisioning</strong>.</li><li>Copy the <strong>IdP Group Identifier</strong> and <strong>Apply</strong>.</li></ul><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/configure-sso-scim-provisioning.png?sfvrsn=73394aee_2" alt="Configure SSO & SCIM Provisioning for License Name" /></p><p> From this point on, access is controlled through group membership.</p><ul><li>Use the IdP Group Identifier to <strong>create a group with the same name in your IdP Provider</strong> and assign that group to the SCIM App. Optionally, add a group description as a human-readable name in the IdP.</li></ul><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/okta-group-idp-provider.png?sfvrsn=4af0484b_2" alt="Okta window for Telerik SCIM Test App. Assignments, Groups. Subscription key." /></p><ul><li>You can start adding users to the IdP group. For a start, if there are already seated users on the Telerik side, add those users to the IdP group as well. From there on, any IdP group change will be reflected on the Telerik side.</li></ul><h3 id="verify-user-synchronization">6. Verify User Synchronization</h3><p>After completing the setup, you can verify that the configuration is correct and that users are syncing as expected from the <a target="_blank" href="https://www.telerik.com/account/manage-licensed-users/product-list">Licensed Users</a> view.</p><ul><li>Users added to the mapped IdP group will start appearing automatically.</li><li>Existing users (with Telerik accounts) should show as <strong>Assigned</strong>, and can continue signing in via SSO as before.</li><li>New users (without a Telerik account) will appear with an <strong>Invited</strong> status. They will receive an email invitation. They need to complete their account setup on their first login.</li></ul><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/devcraft-complete-subscription-developer-list.png?sfvrsn=b22a1a8e_2" alt="Licensed Users page. DevCraft Complete Subscriptions. List of developers with states invited or assigned." /></p><p> This handles both new and existing users seamlessly.</p><h2 id="what-happens-after-scim-is-enabled">What Happens After SCIM Is Enabled?</h2><p>Once SCIM is enabled for your license, access management becomes fully automated.</p><p>User access is driven entirely by group membership in your Identity Provider, while Telerik reflects those changes automatically. New users are guided through a simple onboarding experience at login, and the Licensed Users view becomes read-only for visibility and reporting.</p><p> There&rsquo;s no need to manually manage seats in Telerik.-Your Identity Provider handles all updates.</p><h2 id="bring-automated-access-to-your-telerik-licenses">Bring Automated Access to Your Telerik Licenses</h2><p>SCIM makes it easier to manage access to your licenses by extending your existing identity management into license management.</p><p>Once combined with SSO, it provides a smooth experience where both authentication and access are handled together&mdash;directly from your Identity Provider.</p><p>Whether you&rsquo;re looking to reduce manual work, keep access aligned with your organization or scale more efficiently as your team grows, SCIM is designed to help you get there!</p><p>Head to the <a target="_blank" href="https://www.telerik.com/account/sso-management">Manage SSO and SCIM</a> page now to get started.</p>]]></content>
  </entry>
  <entry>
    <id>urn:uuid:95c1b59f-0f37-46a9-a08b-2560c179c4bf</id>
    <title type="text">Getting Contact Information with .NET MAUI</title>
    <summary type="text">Let users easily pull contact info (like name, number, email) from one app and save it to their device’s contact list in .NET MAUI.</summary>
    <published>2026-06-08T17:06:18Z</published>
    <updated>2026-07-12T05:29:41Z</updated>
    <author>
      <name>Leomaris Reyes </name>
    </author>
    <link rel="alternate" href="https://www.telerik.com/blogs/getting-contact-information-net-maui?utm_medium=feed&amp;utm_source=feedpress.me&amp;utm_campaign=Feed%3A+telerik-blogs-desktop"/>
    <content type="text"><![CDATA[<p><span class="featured">Let users easily pull contact info (like name, number, email) from one app and save it to their device&rsquo;s contact list in .NET MAUI.</span></p><p>Let&rsquo;s be honest, the only &ldquo;accessory&rdquo; you take with you everywhere&mdash;no matter the activity you&rsquo;re doing or the type of event it is, and something that never bothers you to carry&mdash;is your mobile device. </p><p>OK &hellip; and what does this mean? It means that a large part of the things you need to do in your day-to-day life are covered by your phone: from super basic operations like calculating amounts and saving contacts, to talking with your friends or even ordering food.</p><p>Now, think about this: imagine you have an application with a form where you need to enter contact information&mdash;the same information you already saved on your phone when creating that contact. Having to type everything again can feel tedious, right?</p><p>This is where things get interesting. A simple action like saving a contact opens the door for multiple applications to obtain that information and work together with the data that already exists on the device. If your app could &ldquo;pull&rdquo; that information directly, without the user having to type it again, that would be a win! </p><p>So get excited, because in this article I&rsquo;ll show you how to obtain that contact information to use it in your .NET MAUI apps. </p><h2 id="what-do-i-need-before-i-start">What Do I Need Before I Start?</h2><p>Before we begin, it&rsquo;s important to configure a few platform-specific steps. Let&rsquo;s go through each one, step by step:</p><h3 id="android">Android</h3><p>To be able to read contacts, you must explicitly request the <code>READ_CONTACTS</code> permission. There are three different ways to add this permission on Android:</p><p><strong>Option 1: Add the permission directly in the AndroidManifest.xml</strong></p><p>Go to Platforms &rarr; Android, open the AndroidManifest.xml file, and add the following node:</p><pre class=" language-xml"><code class="prism  language-xml">&lt;uses-permission android:name="android.permission.READ_CONTACTS" /&gt;
</code></pre><p><strong>Option 2: Use the Android Manifest graphical editor</strong></p><p>Go to <strong>Platforms &rarr; Android,</strong> double-click the <strong>AndroidManifest.xml</strong> file, and locate the <strong>Required permissions</strong> section. Find the permission labeled <strong>READ_CONTACTS</strong> and simply check the option, as shown below.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-05/01_readcontacts.png?sfvrsn=6ec6edc6_2" title="Read Contacts Permissions" alt="" /></p><p><strong>Option 3: Add the assembly-based permission</strong></p><p>Go to <strong>Platforms &rarr; Android &rarr; MainApplication.cs</strong> and add the permission as follows:</p><pre class=" language-csharp"><code class="prism  language-csharp">[assembly: UsesPermission(Android.Manifest.Permission.ReadContacts)]
</code></pre><h3 id="iosmac-catalyst">iOS/Mac Catalyst</h3><p>On <strong>iOS</strong> and <strong>Mac Catalyst</strong>, we also need a very similar configuration to be able to access contacts. Follow these steps:</p><p><strong>Step 1:</strong><br />Right-click on <strong>Platforms &rarr; iOS &rarr; Info.plist</strong> and on <strong>Platforms &rarr; MacCatalyst &rarr; Info.plist</strong> (yes, each configuration is done per platform) and open the file with the editor.</p><p><strong>Step 2:</strong><br />Once the file is open, add the <strong>NSContactsUsageDescription</strong> key along with its description. This step is mandatory to comply with Apple&rsquo;s guidelines. Keep in mind that this text must be very precise, as it will be the message shown to the user when the app requests permission to access their contacts.</p><pre class=" language-xml"><code class="prism  language-xml">&lt;key&gt;NSContactsUsageDescription&lt;/key&gt;
&lt;string&gt;This app needs access to your contacts to select a contact and retrieve its information.&lt;/string&gt;
</code></pre><h3 id="windows">Windows</h3><p>Contact picking is not supported on Windows.</p><h2 id="let’s-start">Let&rsquo;s Start!</h2><p>All set! We&rsquo;ve prepared the initial configuration to get started! </p><p>.NET MAUI provides the IContacts interface, which allows us to select and retrieve information from the contacts stored on the device.</p><p>This interface is part of the Microsoft.Maui.ApplicationModel.Communication namespace and is available through the Default property, which gives us access to the ready-to-use implementation provided by .NET MAUI.</p><h3 id="important-considerations-for-ios-and-macos">Important Considerations for iOS and macOS</h3><p>There is a namespace conflict because multiple classes named Contacts exist. As a result, if you write only <code>Contacts</code>, .NET doesn&rsquo;t know exactly which one you are referring to, and you might think there is an issue with your code when in reality you are just using the wrong class.</p><p><strong>What&rsquo;s the Solution?</strong></p><p>To avoid this conflict, you must tell .NET exactly where the class you want to use comes from. This is done by using the fully qualified name:</p><pre class=" language-csharp"><code class="prism  language-csharp">Microsoft.Maui.ApplicationModel.Communication.Contacts
</code></pre><p><strong>A Cleaner Solution</strong></p><p>There is also a cleaner way to handle this. Instead of writing the full name every time you use it, you can create an alias with a using directive, like this:</p><pre class=" language-csharp"><code class="prism  language-csharp">using Communication = Microsoft.Maui.ApplicationModel.Communication;
</code></pre><p>This gives the namespace a shorter name. Then, you can use that alias directly in your code:</p><pre class=" language-csharp"><code class="prism  language-csharp">var contact = await Communication.Contacts.Default.PickContactAsync();
</code></pre><h2 id="what-contact-information-can-we-retrieve-exactly">What Contact Information Can We Retrieve Exactly?</h2><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-05/02_contact.png?sfvrsn=23e5e456_2" title="Contacts" alt="" /></p><p>Let&rsquo;s take a look at the data that can be retrieved from a contact. The following are the available fields:</p><ul><li><strong>Id:</strong> The internal identifier of the contact on the device.</li><li><strong>NamePrefix:</strong> The name prefix (Mr., Mrs., Eng., Dr., etc.)</li><li><strong>GivenName:</strong> The contact&rsquo;s first name.</li><li><strong>MiddleName:</strong> The contact&rsquo;s middle name.</li><li><strong>FamilyName:</strong> The contact&rsquo;s last name.</li><li><strong>NameSuffix:</strong> The name suffix (if any), for example, Jr.</li><li><strong>Phones:</strong> The list of phone numbers associated with the contact.</li><li><strong>Emails:</strong> The list of email addresses associated with the contact.</li><li><strong>DisplayName:</strong> The full name displayed on the phone. For example: Eng. Maris Lopez.</li></ul><h2 id="getting-your-device-contact-list">Getting Your Device Contact List</h2><p>To retrieve the full list of contacts stored on your device, you can use the <code>GetAllAsync()</code> method. This method returns a collection containing all available contacts.</p><p>Below is an example showing how to retrieve them:</p><pre class=" language-csharp"><code class="prism  language-csharp">public async IAsyncEnumerable&lt;string&gt; GetContactNames() 
{ 
    var contacts = await Contacts.Default.GetAllAsync(); 
// No contacts 
if (contacts == null) 
    yield break;
 
foreach (var contact in contacts) 
    yield return contact.DisplayName; 
}
</code></pre><h3 id="but-how-can-i-select-a-specific-contact-">But How Can I Select a Specific Contact? </h3><p>To ask the user to select a specific contact from their device, we use the <code>PickContactAsync()</code> method. This method opens the system&rsquo;s contact list, where the user can simply choose a contact.</p><blockquote><p>⚠️ If the user does not select any contact or cancels the action, the method returns null.</p></blockquote><p>In the following example, you can see how to retrieve the different pieces of information from the selected contact:</p><pre class=" language-csharp"><code class="prism  language-csharp">private async void SelectContactButton_Clicked(object sender, EventArgs e) 
{ 
    try 
    { 
    var contact = await Contacts.Default.PickContactAsync(); 
    
    if (contact == null) 
    return; 
    string id = contact.Id; 
    string namePrefix = contact.NamePrefix; 
    string givenName = contact.GivenName; 
    string middleName = contact.MiddleName; 
    string familyName = contact.FamilyName; 
    string nameSuffix = contact.NameSuffix; 
    string displayName = contact.DisplayName; 
    List&lt;ContactPhone&gt; phones = contact.Phones; 
    List&lt;ContactEmail&gt; emails = contact.Emails; 
    }
    
    catch (Exception ex) 
    { 
    // Most likely permission denied 
    } 
}
</code></pre><h2 id="✍️-platform-differences-you-should-know">✍️ Platform Differences You Should Know</h2><h3 id="android-1">Android</h3><ul><li><code>GetAllAsync</code> does not support the <code>cancellationToken</code> parameter.</li></ul><h3 id="ios--mac-catalyst">iOS / Mac Catalyst</h3><ul><li><code>GetAllAsync</code> does not support the <code>cancellationToken</code> parameter.</li><li>The <code>DisplayName</code> property is not supported natively. Instead, its value is constructed using <code>GivenName FamilyName</code>.</li></ul><h2 id="conclusion">Conclusion</h2><p>And that&rsquo;s it!  In this article, you learned how to work with device contacts in .NET MAUI, from selecting a specific contact to retrieving the full contact list. You also explored key platform differences and important considerations to keep in mind when targeting Windows, Android, iOS and Mac Catalyst.</p><p>With this knowledge, you can now integrate contact access into your apps in a clear and reliable way, improving the user experience while handling platform-specific behaviors correctly.</p><p>See you in the next article! &zwj;♀️✨</p><h3 id="reference">Reference</h3><p>Code samples and explanations were based on the official documentation.</p><ul><li><a target="_blank" href="https://learn.microsoft.com/en-us/dotnet/maui/platform-integration/communication/contacts?view=net-maui-10.0&amp;tabs=macios">https://learn.microsoft.com/en-us/dotnet/maui/platform-integration/communication/contacts?view=net-maui-10.0&amp;tabs=macios</a></li></ul><aside><hr data-sf-ec-immutable="" /><div class="row"><div class="col-4 u-normal-full u-small-mb0"><h4 class="u-fs20 u-fw5 u-lh125 u-mb0">Share Functionality in Your .NET MAUI Apps</h4></div><div class="col-8"><p class="u-fs16 u-mb0"><a target="_blank" href="https://www.telerik.com https://www.telerik.com/blogs/share-functionality-net-maui-apps">Learn how to add share functionality to your .NET MAUI app</a> whether in iOS, Android or Windows.</p></div></div></aside>]]></content>
  </entry>
  <entry>
    <id>urn:uuid:9de19443-4354-4fcc-a3a2-b2f1b2c55cc7</id>
    <title type="text">From Classic WinForms to Telerik in Minutes: Meet the AI-Powered Converter</title>
    <summary type="text">Transform your MS WinForms application to use the Telerik UI for WinForms controls reliably and within minutes using the new WinForms Converter in the MCP Server.</summary>
    <published>2026-06-04T14:07:53Z</published>
    <updated>2026-07-12T05:29:41Z</updated>
    <author>
      <name>Hristo Merdjanov </name>
    </author>
    <link rel="alternate" href="https://www.telerik.com/blogs/classic-winforms-telerik-minutes-meet-ai-powered-converter?utm_medium=feed&amp;utm_source=feedpress.me&amp;utm_campaign=Feed%3A+telerik-blogs-desktop"/>
    <content type="text"><![CDATA[<p><span class="featured">Transform your MS WinForms application to use the Telerik UI for WinForms controls reliably and within minutes using the new WinForms Converter in the MCP Server.</span></p><p>If you&rsquo;ve ever faced the task of migrating a WinForms application from standard Microsoft controls to Progress <a target="_blank" href="https://www.telerik.com/products/winforms.aspx">Telerik UI for WinForms</a>, you know the drill. Open a form, find a button, replace it with RadButton, update the namespace, rename a handful of properties, hope you didn&rsquo;t miss anything in the designer file, build, fix errors; repeat. For a simple form with a dozen controls, that&rsquo;s manageable. For an application with multiple forms, user controls and hundreds of control instances, it&rsquo;s a time-sink that nobody looks forward to.</p><p>Imagine that you have an existing application built with the Microsoft controls&mdash;even a very simple one, like the one below&mdash;but the manual effort and domain expertise it requires converting it to Telerik UI kept it out of reach. Well, that changes now.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/order-management-system.png?sfvrsn=5bc5f96f_2" alt="Order Management System. A demo application for managing products and orders. Built with Windows Forms and .NET Framework 4.8" /></p><p>What if you could let AI handle the heavy lifting? That&rsquo;s exactly what we built. The <a target="_blank" href="https://www.telerik.com/products/winforms/documentation/ai-coding-assistant/converter/converter">Telerik WinForms Converter</a> is a new tool integrated into our MCP Server that automates WinForms-to-Telerik migration. It handles Microsoft WinForms control types, runs right inside your IDE and uses Roslyn for surgical, deterministic code transformations. In this post, I&rsquo;ll walk you through why we built it, how it works and the value it brings.</p><aside><hr data-sf-ec-immutable="" /><div class="row"><div class="col-4 u-normal-full u-small-mb0"><h4 class="u-fs20 u-fw5 u-lh125 u-mb0">Meet WinForms Converter</h4></div><div class="col-8"><p class="u-fs16 u-mb0">Join the <a target="_blank" href="https://www.telerik.com/campaigns/telerik-and-kendo-ui-2026-q2-release-webinar">Telerik and Kendo UI 2026 Q2 Release Webinar</a> on June 16 to see fast and deterministic conversion of standard WinForms apps to modern Telerik UI.</p></div></div><hr class="u-mb3" /></aside><h2 id="why-can’t-i-just-ask-an-llm">Why: Can&rsquo;t I Just Ask an LLM?</h2><p>Fair question. AI coding assistants are excellent at many tasks, so the first thing we explored was: can an LLM just do this migration from scratch?</p><p>We tested all leading LLM models on real WinForms migration scenarios. The results were consistent, and consistently problematic. Almost all models got the Telerik references wrong on multiple attempts.</p><p>But wrong packages were just the beginning. The lack of structured guidance was a big problem. Some models decided to stop the conversion mid-process, leaving the application in a non-stable state. Others created stub classes&mdash;empty wrappers like <code>public class RadButton : Button { }</code>&mdash;that compiled successfully but had zero Telerik functionality.</p><p>Quality was also an issue. Many models missed the non-obvious patterns inside <code>.Designer.cs</code> files, where serialized control declarations follow conventions that aren&rsquo;t documented in typical training data.</p><p>The takeaway? LLMs are great at coding, but WinForms migration requires domain-specific knowledge that pure language models simply don&rsquo;t have. The control mappings, property translations, designer serialization patterns and container-aware type resolution&mdash;these need to be encoded deterministically as expert tooling, and not left to probabilistic generation.</p><h2 id="how-the-converter-in-action">How: The Converter in Action</h2><p>The Telerik WinForms Converter is a Roslyn-based engine integrated into the Telerik <a target="_blank" href="https://www.telerik.com/products/winforms/documentation/ai-coding-assistant/mcp-server">WinForms MCP Server</a>. It works in Visual Studio, VS Code with GitHub Copilot in Agent mode, Copilot CLI or any other MCP-compatible AI host application. You configure the MCP server, open Copilot Chat, select a migration prompt, and the AI agent takes care of the rest.</p><p>We have tools that return a strict migration plan, do a project analysis, help add Telerik references and also set up a modern theme. As for our star, the converter tool itself, under the hood, it parses your C# or VB.NET source code into an Abstract Syntax Tree using Roslyn, then walks the tree and applies precise, rule-driven transformations. It knows that a <code>DataGridView</code> becomes a <code>RadGridView</code>, that <code>DataPropertyName</code> maps to <code>FieldName</code> and that <code>DataGridViewAutoSizeColumnsMode</code> translates to <code>GridViewAutoSizeColumnsMode</code>.</p><p>Here&rsquo;s what a typical conversion looks like:</p><p><strong>Before:</strong></p><pre class=" language-csharp"><code class="prism  language-csharp"><span class="token keyword">private</span> System<span class="token punctuation">.</span>Windows<span class="token punctuation">.</span>Forms<span class="token punctuation">.</span>DataGridView productsGrid<span class="token punctuation">;</span>  
  
<span class="token keyword">this</span><span class="token punctuation">.</span>productsGrid<span class="token punctuation">.</span>AutoSizeColumnsMode <span class="token operator">=</span> DataGridViewAutoSizeColumnsMode<span class="token punctuation">.</span>Fill<span class="token punctuation">;</span>  
<span class="token keyword">this</span><span class="token punctuation">.</span>productsGrid<span class="token punctuation">.</span>Columns<span class="token punctuation">.</span><span class="token function">AddRange</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">DataGridViewColumn</span><span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token punctuation">{</span>  
<span class="token keyword">this</span><span class="token punctuation">.</span>nameColumn<span class="token punctuation">,</span>  
<span class="token keyword">this</span><span class="token punctuation">.</span>priceColumn  
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p><strong>After:</strong></p><pre class=" language-csharp"><code class="prism  language-csharp"><span class="token keyword">private</span> Telerik<span class="token punctuation">.</span>WinControls<span class="token punctuation">.</span>UI<span class="token punctuation">.</span>RadGridView productsGrid<span class="token punctuation">;</span>  
  
<span class="token keyword">this</span><span class="token punctuation">.</span>productsGrid<span class="token punctuation">.</span>AutoSizeColumnsMode <span class="token operator">=</span> GridViewAutoSizeColumnsMode<span class="token punctuation">.</span>Fill<span class="token punctuation">;</span>  
<span class="token keyword">this</span><span class="token punctuation">.</span>productsGrid<span class="token punctuation">.</span>Columns<span class="token punctuation">.</span><span class="token function">AddRange</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">GridViewDataColumn</span><span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token punctuation">{</span>  
<span class="token keyword">this</span><span class="token punctuation">.</span>nameColumn<span class="token punctuation">,</span>  
<span class="token keyword">this</span><span class="token punctuation">.</span>priceColumn  
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>Notice how the converter handles not just the type rename, but also the column array type, the enum type and the property mappings&mdash;all in one pass. The converter is also context-aware: a <code>ToolStripButton</code> inside a <code>MenuStrip</code> maps to <code>RadMenuItem</code>, but the same <code>ToolStripButton</code> inside a <code>ToolStrip</code> becomes a <code>CommandBarButton</code>. This kind of parent-child awareness is something LLMs consistently get wrong.</p><p>The migration follows a divide-and-conquer strategy. The AI agent converts one form at a time&mdash;the Designer file first, then the corresponding source file&mdash;builds after each pair and fixes any compilation errors before moving on. This keeps the error surface small and helps prevent issues from cascading across the project.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/run-telerik-convert-file-winforms.png?sfvrsn=85999964_2" alt="GitHub Copilot Chat window. Migrate this Winforms application to Telerik UI for WinForms. … Run Telerik_convert_file. This is a tool from Telerik.WinForms.MCP" /></p><p>The converter supports various Microsoft WinForms control types including Form, Button, TextBox, ComboBox, DataGridView, TreeView, MenuStrip, ToolStrip, TabControl, SplitContainer and many more. It handles both C# and VB.NET, supports .NET Framework and modern .NET, and offers a dry-run mode so you can preview all changes before they&rsquo;re applied. Backups (.bak files) are created automatically before any file is modified.</p><h2 id="the-numbers">The Numbers</h2><p>We ran benchmarks with multiple AI models against various applications. Very simple ones and also complex real-world line-of-business apps. The data below shows the results after converting the simple Orders Management application consisting of two screens and several views and screenshotted at the beginning of the blog. ⬆️⬆️⬆️</p><p>We did the test harness with Opus 4.6, Sonnet 4.6 and Haiku 4.5. Each tested with and without our MCP tooling on the same sample Orders Management WinForms application.</p><p>A few things stand out here.</p><p><strong>Output tokens tell the real story.</strong> Output tokens are the expensive ones. They cost significantly more than input tokens across all major providers. With MCP and the sample app in question, models generate only ~10K output tokens versus ~48K without. That&rsquo;s a 4.6x reduction. The reason is straightforward: our converter handles the bulk of the transformation deterministically. The LLM doesn&rsquo;t need to generate conversion code token-by-token; it just calls our tools and orchestrates the workflow.</p><p><strong>Less capable models become fully capable.</strong> This is perhaps the most exciting finding. Haiku 4.5&mdash;a lightweight, cost-efficient model&mdash;can achieve full conversions with our MCP tooling. The same quality as Opus. Without MCP? It managed only 22%, converting just 4 out of 18 controls. Our tooling can level the playing field: you don&rsquo;t need the most powerful (and expensive) model to get excellent results.</p><p><strong>More complete conversions, every time.</strong> With MCP, all 18 controls were converted across every model we tested. Without MCP, coverage was variable: models would skip controls, miss designer serialization patterns or leave standard WinForms types untouched. The deterministic nature of our converter means you get consistent, complete results regardless of which model you&rsquo;re using. Time is also a factor, and our MCP tooling significantly reduces the conversion time.</p><p>Below is the result after converting the simple Orders Management app. It is fully functional, has the Telerik Fluent theme applied and the whole process only took just couple of minutes.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/order-management-system-converted-winforms-telerik.png?sfvrsn=c9e363ba_2" alt="The Order Management System converted from WinForms to Telerik controls" /></p><h2 id="deterministic--ai-the-best-of-both-worlds">Deterministic + AI: The Best of Both Worlds</h2><p>This is where the real value proposition becomes clear. The conversion engine is deterministic&mdash;the same input always produces the same output. No hallucinations, no randomness, no guessing. The MCP tools handle the bulk mechanical transformation with great accuracy: type mappings, property translations, enum conversions, namespace additions, designer serialization patterns.</p><p>The AI agent&rsquo;s responsibility is to orchestrate&mdash;call the converter tools in the right order, analyze the project structure and then handle what remains. After the converter does its work, the LLM steps in to fix edge cases, resolve compilation errors and adapt to project-specific quirks. For finding Telerik alternatives to removed properties, the agent can also use the <code>telerik_winforms_assistant</code> coding assistant tool that ships with the same MCP Server.</p><p>This separation of concerns is key. Our tooling does what tooling does best: deterministic, repeatable, accurate transformations. While the LLM does what LLMs do best: reasoning about context, adapting to the unexpected, making judgment calls. The combination is more reliable than <strong>either approach alone</strong>.</p><p>And it works incrementally. You can migrate your entire project in one go or convert a single form to test the waters. Either way, only the UI layer changes. Your business logic, data access, and service code stay untouched. The Fluent theme is auto-configured, and both .NET Framework 4.8 and modern .NET are fully supported.</p><h2 id="getting-started">Getting Started</h2><p>Getting up and running takes just a few steps. Add a .mcp.json configuration to your project with the Telerik.WinForms.MCP server enabled. Then open Copilot Chat in Agent mode and pick one of three pre-built prompts:</p><ul><li>Migrate WinForms Project to Telerik &ndash; full project migration</li><li>Migrate WinForms Project to Telerik (Dry Run) &ndash; preview changes before applying</li><li>Convert Single File to Telerik &ndash; convert one file at a time</li></ul><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/mcp-prompts.png?sfvrsn=574f5f36_2" alt="Copilot Chat in Agent mode – MCP prompts" /></p><p>For the full setup guide and detailed documentation, head to our <a target="_blank" href="https://www.telerik.com/products/winforms/documentation/ai-coding-assistant/converter/converter">WinForms converter documentation</a>.</p><h2 id="try-it-out">Try It Out</h2><p>The WinForms Converter is available now as part of the Telerik WinForms MCP Server. <a target="_blank" href="https://www.telerik.com/download-trial-file/v2-b/ui-for-winforms">Download and try the latest version of Telerik UI for WinForms</a> to explore the converter and all the other features our MCP Server offers.</p><p>We&rsquo;d love to hear how this works for you, so please let us know your thoughts by visiting our <a target="_blank" href="https://feedback.telerik.com/winforms">Feedback Portal</a> or by leaving a comment below.</p>]]></content>
  </entry>
  <entry>
    <id>urn:uuid:862be530-d5bf-4f83-a53d-21c09f5f4a84</id>
    <title type="text">5 Heart Animations Using .NET MAUI</title>
    <summary type="text">Try your hand at some simple, engaging animations in .NET MAUI. Here are five heart animations you can master today!</summary>
    <published>2026-06-02T16:28:18Z</published>
    <updated>2026-07-12T05:29:41Z</updated>
    <author>
      <name>Leomaris Reyes </name>
    </author>
    <link rel="alternate" href="https://www.telerik.com/blogs/5-heart-animations-using-net-maui?utm_medium=feed&amp;utm_source=feedpress.me&amp;utm_campaign=Feed%3A+telerik-blogs-desktop"/>
    <content type="text"><![CDATA[<p><span class="featured">Try your hand at some simple, engaging animations in .NET MAUI. Here are five heart animations you can master today!</span></p><p>I&rsquo;m a big fan of animations that capture the user&rsquo;s attention&mdash;the kind that don&rsquo;t just make an app look pretty, but also have the ability to guide users and clearly communicate what&rsquo;s happening. When used correctly, animations become a key part of design and usability. ✨</p><p>In .NET MAUI, we have simple yet very powerful animations that allow us to add that dynamic touch without unnecessary complexity. With just a few lines of code, we can transform common interactions into more natural and enjoyable experiences.</p><p>I genuinely love this article, because in it we&rsquo;ll learn how to create five super-creative animations that elevate our application and showcase the beautiful and powerful things we can achieve using the basic animations available in .NET MAUI </p><h2 id="heart-ecg-monitor">1. Heart ECG Monitor</h2><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-04/01-heartecgmonitor.gif?sfvrsn=fd1f81d3_2" title="Heart ECG Monitor Demo" alt="Heart ECG Monitor Demo" /></p><p><strong>OMG, can we do this in .NET MAUI??</strong> Yess!!!  (This is my favorite animation, hahaha).</p><p>Let&rsquo;s create an ECG monitor&ndash;style animation, where we can see the movement of the line. To achieve this, we&rsquo;ll work with both XAML and code-behind.</p><p><strong>Let&rsquo;s start with the XAML. </strong></p><p>The design includes a heart and some lines that simulate the monitor&rsquo;s movement. Both elements will be vertically aligned, so the layout that will contain our design is a <strong>VerticalStackLayout.</strong></p><p>Inside this layout, we&rsquo;ll add:</p><p>➖ An Image for the heart<br />➖ And a GraphicsView to draw and animate the monitor lines</p><pre class=" language-xml"><code class="prism  language-xml">&lt;VerticalStackLayout Padding="24" Spacing="16"
   
    &lt;!-- Heart --&gt; 
    &lt;Image x:Name="Heart" 
    Source="redheart" 
    WidthRequest="35" 
    HeightRequest="35" 
    HorizontalOptions="Center" /&gt;
    
    &lt;!-- ECG --&gt; 
    &lt;GraphicsView x:Name="Ecg" 
    HeightRequest="120" /&gt;

&lt;/VerticalStackLayout&gt;
</code></pre><p>Perfect! Now we&rsquo;ll continue with the code that brings the monitor and the heart to life. For the purpose of this example, we&rsquo;ll add everything directly in the code-behind. And how do we locate the code-behind?  For example, if your XAML file is called MainPage.xaml, the code-behind is in MainPage.xaml.cs.</p><h3 id="variable-declaration">Variable Declaration</h3><p>➖ <strong>WindowSize:</strong> This variable allows us to control how many heartbeats can be displayed on the screen at the same time. The higher this value is, the more heartbeats will be visible before they move out of view. As a result, a larger WindowSize makes the heartbeat appear slower on the monitor.</p><p>➖ <strong>Beat:</strong> We define an array to represent a complete heartbeat. Values close to zero represent the baseline, while higher values represent the peaks.</p><p>➖ <strong>_samples:</strong> This variable represents what should be displayed on the screen. Initially, we fill it with zeros to display a flat line.</p><p>➖ <strong>EcgDrawable:</strong> This holds the object responsible for drawing the monitor signal.</p><p>➖ <strong>_i:</strong> Finally, we have the index that will be used to iterate through the Beat array.</p><pre class=" language-csharp"><code class="prism  language-csharp">// Variables
 
const int WindowSize = 140; 
static readonly float[] Beat = 
    { 
    0,0,0, .12f,.25f,.12f, 0, -.25f,1f,-.35f, 0,0, .20f,.35f,.20f, 0,0,0,0 
};

readonly List&lt;float&gt; _samples = Enumerable.Repeat(0f, WindowSize).ToList(); 
readonly EcgDrawable _drawable; 
int _i;
</code></pre><h3 id="continuing-with-the-constructor">Continuing with the Constructor</h3><p>Once we have all the required variables defined, the next step is to connect the components and start the animation inside the constructor.</p><p>First, we create an instance of <code>EcgDrawable</code> and assign it to the <code>GraphicsView</code>. This allows the view to know how to render the ECG signal based on the provided samples.</p><p>Next, we configure a timer using the Dispatcher. This timer is responsible for updating the signal at a regular interval, which helps us achieve a smooth and continuous animation.</p><p>On each timer tick:</p><ul><li>The next value from the heartbeat pattern is added to the samples list.</li><li>The window size is preserved by removing the oldest value.</li><li>The <code>GraphicsView</code> is invalidated to force a redraw.</li></ul><p>Finally, we start the timer, and the heart monitor animation begins automatically.</p><p>In code, it looks like this:</p><pre class=" language-csharp"><code class="prism  language-csharp">public HeartAnimations() 
{ 
    InitializeComponent(); 
    _drawable = new EcgDrawable(_samples); 
    Ecg.Drawable = _drawable; 
    var t = Dispatcher.CreateTimer(); 
    t.Interval = TimeSpan.FromMilliseconds(16); 
    t.Tick += (_, __) =&gt; 
    { 
    _samples.Add(Beat[_i++ % Beat.Length]); 
    if (_samples.Count &gt; WindowSize) _samples.RemoveAt(0); 
    Ecg.Invalidate(); 
    }; 
    t.Start(); 
}
</code></pre><p>Finally, let&rsquo;s add the <code>EcgDrawable</code> class.</p><p>This class is responsible for <strong>visually rendering the ECG signal</strong> inside the GraphicsView component. It takes the list of values that represent the heart signal and transforms them into a continuous line, automatically calculating:</p><ul><li>The vertical position of the signal</li><li>The horizontal distribution of each point</li></ul><p>In code, this translates to the following:</p><pre class=" language-csharp"><code class="prism  language-csharp">class EcgDrawable(IReadOnlyList&lt;float&gt; samples) : IDrawable 
{ 
    public void Draw(ICanvas c, RectF r) 
    { 
    if (samples.Count &lt; 2) return; 
    c.StrokeColor = Colors.Red; 
    c.StrokeSize = 2; 
    var baseline = r.Top + r.Height * .55f; 
    var amp = r.Height * .35f; 
    var dx = r.Width / (samples.Count - 1); 
    var p = new PathF(); 
    p.MoveTo(r.Left, baseline - samples[0] * amp);  
    for (int i = 1; i &lt; samples.Count; i++) 
    p.LineTo(r.Left + i * dx, baseline - samples[i] * amp);
     
    c.DrawPath(p); 
    } 
}
</code></pre><p>And that&rsquo;s it!  We&rsquo;ve just finished building the Heart ECG Monitor animation. See? It wasn&rsquo;t that hard! I encourage you to try it out and experiment with it on your own.</p><p>Now, let&rsquo;s move on to the next animation! </p><h2 id="heart-ripple-pulse">2. Heart Ripple Pulse</h2><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-04/02-heartripple.gif?sfvrsn=bc351843_2" title="Heart Ripple Pulse" alt="Heart Ripple Pulse" /></p><p>This animation represents the heartbeat and the waves generated by that pulse.</p><p>Here, we combine several simple animations and use a Grid as the main container to overlay all the elements in the same space, making them feel like a single, unified animation.</p><p>We&rsquo;ll start with the XAML, where we will define:</p><p>➖ Two Border components in red color, representing the ripple waves.</p><p>➖ A heart image, which will act as the main element at the center.</p><pre class=" language-xml"><code class="prism  language-xml">&lt;Grid HorizontalOptions="Center" 
    VerticalOptions="Start" 
    Margin="0,100" 
    WidthRequest="140" 
    HeightRequest="140"&gt;
    
    &lt;Border x:Name="Ripple1" 
    Stroke="Red" 
    StrokeThickness="3" 
    Opacity="0" 
    Scale="0.2" 
    StrokeShape="RoundRectangle 999" /&gt;
     
    &lt;Border x:Name="Ripple2" 
    Stroke="Red" 
    StrokeThickness="3" 
    Opacity="0" 
    Scale="0.2" 
    StrokeShape="RoundRectangle 999" /&gt;
     
    &lt;Image x:Name="Heart" 
    Source="redheart.png" 
    WidthRequest="48" 
    HeightRequest="48" 
    HorizontalOptions="Center" 
    VerticalOptions="Center" /&gt;

&lt;/Grid&gt;
</code></pre><p>To bring our animation to life, we&rsquo;ll work with the OnAppearing and in a method called Loop.</p><p>➖ <strong>OnAppearing:</strong> To explore something different, this time we&rsquo;ll work with the <code>OnAppearing</code> method (✍️ please make sure to declare the <code>_running</code> bool variable).</p><p>When the screen appears, we call the <code>Loop</code> method, which is responsible for running the animation cycle.</p><pre class=" language-csharp"><code class="prism  language-csharp">protected override void OnAppearing() 
{ 
    base.OnAppearing(); 
    _running = true; 
    _ = Loop(); 
}
</code></pre><p>➖ <strong>Loop():</strong> This is where the magic happens. ✨ Inside this method:</p><ul><li>We trigger the <strong>heart pop,</strong> a subtle scale effect on the heart</li><li>We animate the <strong>two circular lines</strong> to create the ripple effect</li><li>We use a <strong>delay</strong> to give each animation enough time and make them clearly distinguishable</li></ul><p>Thanks to this approach, we achieve a smooth, easy-to-follow and well-synchronized animation.</p><p>In code, this would look like the following:</p><pre class=" language-csharp"><code class="prism  language-csharp">async Task Loop() 
{ 
    while (_running) 
    { 
    // Reset 
    Ripple1.Opacity = Ripple2.Opacity = 0; 
    Ripple1.Scale = Ripple2.Scale = 0.2; 
    Heart.Scale = 1;
     
    // Heart pop 
    _ = Heart.ScaleTo(1.12, 90, Easing.CubicOut)
    
    .ContinueWith(_ =&gt; MainThread.InvokeOnMainThreadAsync( 
    () =&gt; Heart.ScaleTo(1.0, 120, Easing.CubicInOut)));
    
    // Ripple 1 
    _ = Task.WhenAll( 
    Ripple1.FadeTo(0.45, 60, Easing.CubicOut), 
    Ripple1.ScaleTo(1.8, 700, Easing.CubicOut) 
    ).ContinueWith(_ =&gt; MainThread.InvokeOnMainThreadAsync( 
    () =&gt; Ripple1.FadeTo(0, 250, Easing.CubicIn)));

    // Ripple 2 
    await Task.Delay(120); 
    _ = Task.WhenAll( 
    Ripple2.FadeTo(0.35, 60, Easing.CubicOut), 
    Ripple2.ScaleTo(1.8, 700, Easing.CubicOut) 
    ).ContinueWith(_ =&gt; MainThread.InvokeOnMainThreadAsync( 
    () =&gt; Ripple2.FadeTo(0, 250, Easing.CubicIn)));
     
    await Task.Delay(650); 
    } 
}
</code></pre><p>And that&rsquo;s it! Let&rsquo;s keep going and jump into the next animation! </p><h2 id="blinking-heart">3. Blinking Heart</h2><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-04/03-blinkingheart.gif?sfvrsn=12221562_2" title="Blinking Heart" alt="Blinking Heart" /></p><p>In this animation, we&rsquo;ll make a heart blink in a subtle and elegant way. We&rsquo;ll start with the XAML. In this case, the structure is very simple, since we only need a single heart image, centered on the screen. From this single element, we&rsquo;ll build the entire animation.</p><pre class=" language-xml"><code class="prism  language-xml">&lt;Image x:Name="Heart"  
    Source="redheart.png"  
    WidthRequest="56"  
    HeightRequest="56"  
    HorizontalOptions="Center"  
    VerticalOptions="Center" /&gt;
</code></pre><p>We&rsquo;ll continue working with <code>OnAppearing</code> to start the animation, and additionally we&rsquo;ll create a method called <code>BlinkLoop()</code> to handle the animation logic. This one is composed of <code>FadeTo</code> and <code>ScaleTo</code> animations, which allow us to play with the icon&rsquo;s opacity and size, creating the blinking effect.</p><p>In code, it would look like the following:</p><pre class=" language-csharp"><code class="prism  language-csharp">protected override void OnAppearing() 
{ 
    base.OnAppearing(); 
    _running = true; 
    _ = BlinkLoop(); 
} 
async Task BlinkLoop() 
{

    while (_running) 
    { 
    await Task.WhenAll( 
    Heart.FadeTo(0.35, 220, Easing.CubicInOut), 
    Heart.ScaleTo(0.95, 220, Easing.CubicInOut) 
    ); 
    
    await Task.WhenAll( 
    Heart.FadeTo(1, 220, Easing.CubicInOut), 
    Heart.ScaleTo(1, 220, Easing.CubicInOut) 
    ); 
    } 
}
</code></pre><p>All set! Ready to move on to the next animation ✨</p><h2 id="rotating-heart">4. Rotating Heart</h2><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-04/04-rotateheart.gif?sfvrsn=59e48923_2" title="Rotate Heart" alt="Rotate Heart" /></p><p>Now we&rsquo;ll create an animation where our heart rotates. ❤️ This type of animation is very useful, for example, as a loading indicator in your screens.</p><p>To get started with the implementation, we&rsquo;ll begin by adding the Image in XAML, as shown below:</p><pre class=" language-xml"><code class="prism  language-xml">&lt;Image x:Name="Heart" 
    Source="redheart.png" 
    WidthRequest="64" 
    HeightRequest="64" 
    HorizontalOptions="Center" 
    VerticalOptions="Center" /&gt;
</code></pre><p>And in the code-behind, it&rsquo;s time to bring the heart to life! ❤️</p><p>We&rsquo;ll use the <code>OnAppearing</code> method, and for the animation (✍️ please make sure to declare the <code>_isRunning</code> bool variable), we&rsquo;ll rely on <code>RotateTo()</code>, as shown below:</p><pre class=" language-csharp"><code class="prism  language-csharp">protected override async void OnAppearing() 
{ 
    base.OnAppearing(); 
    _isRunning = true; 
    
    while (_isRunning) 
    { 
    await Heart.RotateTo(360, 4000, Easing.Linear); 
    Heart.Rotation = 0; 
    } 
}
</code></pre><p>Done! Let&rsquo;s bring the next animation to life ✨</p><h2 id="jumping-heart">5. Jumping Heart</h2><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-04/05-heartjumping.gif?sfvrsn=5be8d95b_2" title="Heart Jumping" alt="Heart Jumping" /></p><p>For our final animation, we&rsquo;ll make the heart jump up and down in a continuous loop.</p><p>This animation also works great as a loading indicator, adding a playful touch to your screen.</p><p>Let&rsquo;s start by adding the Image to the XAML:</p><pre class=" language-xml"><code class="prism  language-xml">&lt;Image x:Name="Heart" 
    Source="redheart.png" 
    WidthRequest="64" 
    HeightRequest="64" 
    HorizontalOptions="Center" 
    VerticalOptions="Center" /&gt;
</code></pre><p>In the code-behind, we&rsquo;ll create the animation by working with <code>TranslationTo</code> and the <code>TranslationY</code> methods, as shown below:</p><pre class=" language-csharp"><code class="prism  language-csharp">protected override async void OnAppearing() 
{ 
    base.OnAppearing(); 
    _isRunning = true; 
    Heart.TranslationY = -120;
 
    while (_isRunning)
    
    { 
    await Heart.TranslateTo(0, 0, 600, Easing.CubicOut); 
    await Heart.TranslateTo(0, -12, 120, Easing.CubicInOut); 
    await Heart.TranslateTo(0, 0, 120, Easing.CubicInOut); 
    await Heart.TranslateTo(0, -120, 450, Easing.CubicIn); 
    } 
}
</code></pre><p>And that&rsquo;s all&mdash;thanks for building this with me! </p><h2 id="conclusion">Conclusion</h2><p>And that&rsquo;s it!  We&rsquo;ve successfully created <strong>five awesome, ready-to-use animations</strong> with .NET MAUI. Each one was designed to be easy to implement, demonstrating just how powerful even the most basic animations can be when used correctly.</p><p>I hope this article has inspired you and sparked <strong>new ideas</strong> for incorporating animations into your current and future <strong>.NET MAUI projects ✨</strong></p><p>As always, if you have any questions or would like me to explore any of these animations in more detail, feel free to leave a comment &mdash; I&rsquo;d be happy to help! </p><p>See you in the next article! &zwj;♀️</p><aside><hr data-sf-ec-immutable="" /><div class="row"><div class="col-4 u-normal-full u-small-mb0"><h4 class="u-fs20 u-fw5 u-lh125 u-mb0">Building an Instagram-Style Like Animation in .NET MAUI</h4></div><div class="col-8"><p class="u-fs16 u-mb0">Learn how to make your .NET MAUI app a little more engaging with interactive animations. We&rsquo;ll see how to <a target="_blank" href="https://www.telerik.com/blogs/building-instagram-style-like-animation-net-maui">animate a heart for a like action</a>.</p></div></div></aside>]]></content>
  </entry>
  <entry>
    <id>urn:uuid:6808d742-f423-4697-ad7b-0da3008181c4</id>
    <title type="text">Share Functionality in Your .NET MAUI Apps</title>
    <summary type="text">Learn how to add share functionality to your .NET MAUI app whether in iOS, Android or Windows.</summary>
    <published>2026-05-26T13:50:18Z</published>
    <updated>2026-07-12T05:29:41Z</updated>
    <author>
      <name>Leomaris Reyes </name>
    </author>
    <link rel="alternate" href="https://www.telerik.com/blogs/share-functionality-net-maui-apps?utm_medium=feed&amp;utm_source=feedpress.me&amp;utm_campaign=Feed%3A+telerik-blogs-desktop"/>
    <content type="text"><![CDATA[<p><span class="featured">Learn how to add share functionality to your .NET MAUI app whether in iOS, Android or Windows.</span></p><p>In recent years, many large companies have decided to rely on technology and move a big part&mdash;or even all&mdash;of their processes to mobile applications.</p><p>For example, not long ago, sending money from one bank account to another meant physically going to the bank and spending hours waiting in line. Today, that same process can be completed in just a few seconds using a mobile app. </p><p><strong>But&hellip; What happens next? </strong></p><p>How do we send a confirmation or receipt to the account owner so they can validate the transfer?</p><p>To solve this, applications usually include a <strong>share</strong> functionality, which allows users to send information through the familiar share sheet we all know&mdash;via WhatsApp, email, social media and more.</p><p>It&rsquo;s important to design the user experience from start to finish. It&rsquo;s not just about completing an action, but also about enabling users to easily share or confirm the result of that action.</p><p>In this article, you&rsquo;ll learn how to open the share sheet in your .NET MAUI apps, so you can share information quickly and effortlessly.</p><h2 id="what-is-ishare">What Is IShare?</h2><p>IShare is an interface that provides an API that allows you to share data such as links, files or text using the system&rsquo;s share functionality. When invoked, it opens a button sheet where the user can choose how and with whom they want to share that information.</p><p>The IShare interface is already available through the <code>Share.Default</code> property and is located in the Microsoft.Maui.ApplicationModel.DataTransfer namespace.</p><p>When the user interacts with this feature, they will see something like the following:</p><p><img sf-image-responsive="true" src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-05/share.png?sfvrsn=a83f43eb_2" height="500" style="max-width:100%;height:auto;" title=".NET MAUI share" width="1136" alt=".NET MAUI share in Android, iOS, Windows" sf-size="113426" /></p><p><span style="font-size:11px;">Image obtained from the official documentation.</span></p><h3 id="platform-settings">Platform Settings</h3><p>To implement the share functionality, some platforms require additional configuration. These are the supported platforms and their requirements:</p><ul><li><strong>Android and Windows:</strong> No setup is required.</li><li><strong>iOS / Mac Catalyst:</strong> To be able to access photos and videos, you need to add the appropriate permissions. To do this, go to:
        <ul><li>Platforms/iOS/Info.plist</li><li>And Platforms/MacCatalyst/Info.plist</li></ul></li></ul><p>Then add the permission keys along with their descriptions. Keep in mind that this description will be shown to the user when requesting permission, so it&rsquo;s important to use clear and user-friendly text. Below is an example of how the configuration should look:</p><pre><code>&lt;key&gt;NSPhotoLibraryAddUsageDescription&lt;/key&gt; 
&lt;string&gt;This app needs access to the photo gallery to save photos and videos.&lt;/string&gt; 

&lt;key&gt;NSPhotoLibraryUsageDescription&lt;/key&gt; 
&lt;string&gt;This app needs access to the photo gallery to save photos and videos.&lt;/string&gt;
</code></pre><h2 id="what-information-can-i-share-">What Information Can I Share? </h2><p>You can share text, links, files or even multiple files at the same time, depending on your needs. .NET MAUI provides different request types to handle each scenario.</p><p>Below are the most common use cases and how to implement them.</p><h3 id="-text"> Text</h3><p>To share plain text, you can use the <code>ShareTextRequest</code> class. This allows you to pass the text you want to share along with a title.</p><pre><code>public async Task ShareText(string text) 
{ 
    await Share.Default.RequestAsync(new ShareTextRequest 
    { 
    Text = text, 
    Title = "I&rsquo;m the title" 
    }); 
}
</code></pre><h3 id="-links"> Links</h3><p>You can also share a link by using the <code>Uri</code> property of <code>ShareTextRequest</code>. Simply provide the URI and a title.</p><pre><code>public async Task ShareUri(string uri, IShare share) 
{ 
    await share.RequestAsync(new ShareTextRequest 
    { 
    Uri = uri, 
    Title = "I&rsquo;m the title" 
    }); 
}
</code></pre><h3 id="-files"> Files</h3><p>.NET MAUI automatically detects the file type (MIME) and handles the sharing process accordingly. However, keep in mind that each operating system may decide whether a specific file type can be shared or not, depending on platform restrictions.</p><p>To share a single file, use the <code>ShareFileRequest</code> type, as shown below:</p><pre><code>public async Task ShareFile() 
{ 
    string fn = "MyFile.txt"; 
    string file = Path.Combine(FileSystem.CacheDirectory, fn); 
    File.WriteAllText(file, "This is a file"); 
    await Share.Default.RequestAsync(new ShareFileRequest 
    { 
    Title = "Share text file", 
    File = new ShareFile(file) 
    }); 
}
</code></pre><h3 id="️-multiple-files">️ Multiple Files</h3><p>Oh yeah!!  We also have the option to share multiple files using the <code>ShareFileRequest</code> type. Let&rsquo;s look at the following example:</p><pre><code>public async Task ShareMultipleFiles() 
{ 
    string file1 = Path.Combine(FileSystem.CacheDirectory, "File1.txt"); 
    string file2 = Path.Combine(FileSystem.CacheDirectory, "File2.txt");  
    File.WriteAllText(file1, "Hello 1"); 
    File.WriteAllText(file2, "Hello 2");
     
    await Share.Default.RequestAsync(new ShareMultipleFilesRequest 
    { 
    Title = "I&rsquo;m sharing multiple files", 
    Files = new List&lt;ShareFile&gt; { new ShareFile(file1), new ShareFile(file2) } 
    }); 
}
</code></pre><h2 id="android-control-file-locations">Android Control File Locations</h2><p>On Android, there are scenarios where a file is located in the app&rsquo;s private storage. In these cases, Android temporarily copies the file to the app cache and shares it using a FileProvider.</p><p>This behavior is very useful, but it&rsquo;s important to be careful. If it&rsquo;s not configured correctly, it can expose more information than intended, including data that should not be publicly accessible.</p><p>The good news is that this can be prevented by following the steps below.</p><h3 id="step-1-add-the-fileprovider-path-file">Step 1: Add the FileProvider Path File</h3><p>Inside the following folder:</p><pre><code>Platforms/Android/Resources/xml
</code></pre><p>And add a file with the exact name:</p><p><code>microsoft_maui_essentials_fileprovider_file_paths.xml</code></p><h3 id="step-2-what-will-this-file-contain">Step 2: What Will This File Contain?</h3><p>This file defines the allowed locations from which files can be shared.</p><p>Example configuration:</p><pre><code>&lt;?xml version="1.0" encoding="UTF-8" ?&gt; 
&lt;paths&gt; 
    &lt;external-path name="external_files" path="sharing-root" /&gt; 
    &lt;cache-path name="internal_cache" path="sharing-root" /&gt; 
    &lt;external-cache-path name="external_cache" path="sharing-root" /&gt; 
&lt;/paths&gt;
</code></pre><p><strong>What does each line mean?</strong></p><ul><li><strong><code>&lt;external-path&gt;:</code></strong> Allows sharing files from external storage. Useful when the file is stored in a location accessible to the user.</li><li><strong><code>&lt;cache-path&gt;:</code></strong> Allows sharing files from the app&rsquo;s internal cache. This is the most common and safest option, ideal for temporary files such as PDFs, images, or receipts.</li><li><strong><code>&lt;external-cache-path&gt;:</code></strong> Allows sharing files from the external cache. It is still a temporary location, but outside the internal storage.</li><li><strong>sharing-root:</strong> Is a folder that you define and that acts as a <strong>secure area for sharing files.</strong> Only files located inside this folder can be shared.</li></ul><h2 id="ipados-presentation-location">iPadOS Presentation Location</h2><p>When requesting a share or opening launcher on iPadOS, the system displays the action as a popover. To control where this popover appears on the screen and where its arrow points, you must specify a position using the <code>PresentationSourceBounds</code> property.</p><p>You can do it in the following way:</p><p><strong>Share</strong></p><pre><code>await Share.RequestAsync(new ShareFileRequest 
{ 
    Title = Title, 
    File = new ShareFile(file), 
    PresentationSourceBounds = 
    DeviceInfo.Platform == DevicePlatform.iOS &amp;&amp; 
    DeviceInfo.Idiom == DeviceIdiom.Tablet 
    ? new Rect(0, 20, 0, 0) 
    : Rect.Zero 
});
</code></pre><p><strong>Launcher</strong></p><pre><code>await Launcher.OpenAsync(new OpenFileRequest 
{ 
    File = new ReadOnlyFile(file), 
    PresentationSourceBounds = 
    DeviceInfo.Platform == DevicePlatform.iOS &amp;&amp; 
    DeviceInfo.Idiom == DeviceIdiom.Tablet 
    ? new Rect(0, 20, 0, 0) 
    : Rect.Zero 
})
</code></pre><h2 id="conclusion">Conclusion</h2><p>And that&rsquo;s it!  In this article, you learned how to implement share functionality in your .NET MAUI apps, allowing users to easily share text, links, files and even multiple files across platforms.</p><p>You also explored important platform-specific considerations, such as additional permissions on iOS and Mac Catalyst, secure file sharing on Android using FileProvider, and how to properly handle popover presentation on iPadOS to avoid unexpected issues.</p><p>With these concepts in mind, you now have a clearer understanding of how to create a complete and secure sharing experience, taking care of both user experience and platform requirements.</p><p>If you have any questions or would like me to cover more .NET MAUI topics, feel free to leave a comment&mdash;I&rsquo;d be happy to help! </p><p>See you in the next article! &zwj;♀️✨</p><h3 id="reference">Reference</h3><p>Sample codes and explanation was based on the official documentation:</p><ul><li><a target="_blank" href="https://learn.microsoft.com/en-us/dotnet/maui/platform-integration/data/share?view=net-maui-10.0&amp;tabs=android">https://learn.microsoft.com/en-us/dotnet/maui/platform-integration/data/share?view=net-maui-10.0&amp;tabs=android</a></li></ul><aside><hr data-sf-ec-immutable="" /><div class="row"><div class="col-4 u-normal-full u-small-mb0"><h4 class="u-fs20 u-fw5 u-lh125 u-mb0">Get Your .NET MAUI App Up More Quickly</h4></div><div class="col-8"><p class="u-fs16 u-mb0">Deliver native apps for every platform in half the time with 70+ customizable UI components, an AI Coding Assistant and unmatched productivity tools. <a href="https://www.telerik.com/maui-ui" target="_blank">Check out Progress Telerik UI for .NET MAUI</a>.</p></div></div></aside>]]></content>
  </entry>
  <entry>
    <id>urn:uuid:b761f26f-90ec-497a-8858-043a53dedcdd</id>
    <title type="text">Installing and Basics of Telerik UI for .NET MAUI AI Coding Assistant</title>
    <summary type="text">Check out the Telerik UI for .NET MAUI AI Coding Assistant, the MCP server native to Telerik controls and MAUI.</summary>
    <published>2026-05-18T14:25:07Z</published>
    <updated>2026-07-12T05:29:41Z</updated>
    <author>
      <name>Héctor Pérez </name>
    </author>
    <link rel="alternate" href="https://www.telerik.com/blogs/installing-basics-telerik-ui-net-maui-ai-coding-assistant?utm_medium=feed&amp;utm_source=feedpress.me&amp;utm_campaign=Feed%3A+telerik-blogs-desktop"/>
    <content type="text"><![CDATA[<p><span class="featured">Check out the Telerik UI for .NET MAUI AI Coding Assistant, the MCP server native to Telerik controls and MAUI.</span></p><p>Code generation using artificial intelligence has improved impressively over the past few months. One of the features that has helped this growth are MCP servers, which allow connecting an AI to information sources quickly. From consulting Microsoft Learn documentation, to those that perform actions on a calendar, to MCP servers for retrieving information from databases, these servers help improve the accuracy of results by obtaining up-to-date and reliable information.</p><p>The team at Progress has released an <a target="_blank" href="https://www.telerik.com/maui-ui/documentation/ai/mcp-server">AI Coding Assistant for .NET MAUI</a>, which helps create and improve graphical interfaces, using the latest features of its UI controls reliably. Let&rsquo;s see it in action.</p><h2 id="what-is-telerik-ui-for-.net-maui-ai-coding-assistant-mcp-server">What Is Telerik UI for .NET MAUI AI Coding Assistant (MCP Server)?</h2><p>Telerik AI Coding Assistant for .NET MAUI is an MCP server that allows retrieving information provided directly by Progress, with the purpose of letting users learn about the use of a specific component or, alternatively, create high-quality graphical interfaces using the latest features and capabilities of the controls in the Telerik suite. Some available features are:</p><ul><li><strong>Prompt handling</strong>: Handles complex prompts</li><li><strong>Client compatibility</strong>: You can use it in different clients, such as VS Code, Cursor, etc.</li><li><strong>Code suggestions</strong>: It can suggest code and perform automatic rebuilds to check for errors</li><li><strong>Response focus</strong>: Focused on code generation</li></ul><p>The above features enable a variety of use cases, including:</p><ul><li><strong>Generation of complex interfaces</strong>: You can rely on the MCP server to generate dashboards, specific pages, etc., requesting the use of specific controls to be used</li><li><strong>Advanced Grid configuration</strong>: Specify which features you need to include in a DataGrid</li><li><strong>Better testing using mock data</strong>: Get a more robust preview by entering test data before connecting to a data source</li><li><strong>Modernization of graphical interfaces</strong>: Refactor your UI, improving it for modern times and better user experiences</li></ul><p>Let&rsquo;s see how to use it.</p><h2 id="installing-telerik-ui-for-.net-maui-ai-coding-assistant-mcp-server">Installing Telerik UI for .NET MAUI AI Coding Assistant (MCP Server)</h2><p>To be able to use Telerik MCP server for .NET MAUI, you must meet some prerequisites:</p><ol><li>A version of .NET equal or greater than 9</li><li>A client compatible with the MCP protocol, such as VS Code, Visual Studio 2026, Cursor, etc.</li><li>A Telerik account</li><li>An active Telerik license (including a trial account)</li><li>A .NET MAUI app that includes the Telerik UI for .NET MAUI controls</li></ol><h2 id="installing-a-license-key">Installing a License Key</h2><p>Before running any command, I recommend that you obtain a <strong>License Key</strong> so your account can be verified and you can use the MCP server. There are several ways to do this. For example, you can go to your <a target="_blank" href="https://www.telerik.com/account">Progress account</a>, where you select the <strong>License Keys</strong> option:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-05/progress-dashboard-license-keys.png?sfvrsn=bf495214_2" alt="User dashboard showing download area for license keys." /></p><p>On the <strong>License Keys</strong> page, click the <strong>Download License Key</strong> button:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-05/download-license-key-button.png?sfvrsn=de79abe1_2" alt="Download license key button on settings page" /></p><p>The downloaded file <strong>telerik-license.txt</strong> should be placed in <code>%AppData%\Telerik\telerik-license.txt</code> if you&rsquo;re using Windows, as in my case, or in <code>~/.telerik/telerik-license.txt</code> if you&rsquo;re on Linux. Now, it&rsquo;s time to install the MCP server.</p><h2 id="installing-the-mcp-server">Installing the MCP Server</h2><p>With a License Key on your machine, installing the server is quite simple. In my case I will run the command for <strong>.NET 10</strong>:</p><pre class=" language-text"><code class="prism  language-text">dnx Telerik.MAUI.MCP
</code></pre><p>Once the Telerik MCP for MAUI is installed, the next step is to configure your preferred editor. In the case of VS Code, you should first open the folder containing the .NET MAUI project you&rsquo;ll be working on.</p><p>Then, create a folder at the root named <code>.vscode</code>, inside which you should create a file <code>mcp.json</code>. This file must be replaced or adapted (if you already have previous MCP servers), adding the following entry valid for .NET 10:</p><pre class=" language-json"><code class="prism  language-json"><span class="token punctuation">{</span>
  <span class="token string">"servers"</span><span class="token punctuation">:</span> <span class="token punctuation">{</span>
    <span class="token string">"telerik-maui-assistant"</span><span class="token punctuation">:</span> <span class="token punctuation">{</span>
      <span class="token string">"type"</span><span class="token punctuation">:</span> <span class="token string">"stdio"</span><span class="token punctuation">,</span>
      <span class="token string">"command"</span><span class="token punctuation">:</span> <span class="token string">"dnx"</span><span class="token punctuation">,</span>
      <span class="token string">"args"</span><span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token string">"Telerik.MAUI.MCP"</span><span class="token punctuation">,</span> <span class="token string">"--yes"</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><p>Alternatively, to use it in Visual Studio, you must create the file <code>.mcp.json</code> at the solution level and add the following content inside:</p><pre class=" language-json"><code class="prism  language-json"><span class="token punctuation">{</span>
  <span class="token string">"servers"</span><span class="token punctuation">:</span> <span class="token punctuation">{</span>
    <span class="token string">"telerik-maui-assistant"</span><span class="token punctuation">:</span> <span class="token punctuation">{</span>
      <span class="token string">"type"</span><span class="token punctuation">:</span> <span class="token string">"stdio"</span><span class="token punctuation">,</span>
      <span class="token string">"command"</span><span class="token punctuation">:</span> <span class="token string">"dnx"</span><span class="token punctuation">,</span>
      <span class="token string">"args"</span><span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token string">"Telerik.MAUI.MCP"</span><span class="token punctuation">,</span> <span class="token string">"--yes"</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><p>Once done, you will be able to find the new MCP server as part of the tools in both VS Code and Visual Studio 2026:</p><p><strong>VS Code</strong></p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-05/telerik-mcp-server-net-maui-vscode.png?sfvrsn=35a1a02c_2" alt="Telerik MCP server running for .NET MAUI in VS Code" /></p><p><strong>Visual Studio 2026</strong></p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-05/telerik-mcp-setup-maui-vs2026.png?sfvrsn=32760bb7_2" alt="Telerik MCP server setup for .NET MAUI project" /></p><p>With the MCP server configured, we&rsquo;re ready to continue.</p><h2 id="testing-the-telerik-mcp-server-to-create-.net-maui-apps">Testing the Telerik MCP Server to Create .NET MAUI Apps</h2><p>As I mentioned before, the Telerik MCP server can help us perform different tasks.</p><p>For example, suppose you have a page you made using standard .NET MAUI controls, using code similar to the following:</p><pre class=" language-xml"><code class="prism  language-xml"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>Grid</span> <span class="token attr-name">RowDefinitions</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Auto,*<span class="token punctuation">"</span></span> <span class="token attr-name">Padding</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>16<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>

    <span class="token comment">&lt;!-- Header --&gt;</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>Label</span>
        <span class="token attr-name">Grid.Row</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>0<span class="token punctuation">"</span></span>
        <span class="token attr-name">Text</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Product List<span class="token punctuation">"</span></span>
        <span class="token attr-name">FontSize</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>22<span class="token punctuation">"</span></span>
        <span class="token attr-name">FontAttributes</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Bold<span class="token punctuation">"</span></span>
        <span class="token attr-name">Margin</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>0,0,0,12<span class="token punctuation">"</span></span> <span class="token punctuation">/&gt;</span></span>

    <span class="token comment">&lt;!-- Loading indicator --&gt;</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>ActivityIndicator</span>
        <span class="token attr-name">Grid.Row</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>1<span class="token punctuation">"</span></span>
        <span class="token attr-name">IsRunning</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>{Binding IsBusy}<span class="token punctuation">"</span></span>
        <span class="token attr-name">IsVisible</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>{Binding IsBusy}<span class="token punctuation">"</span></span>
        <span class="token attr-name">HorizontalOptions</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Center<span class="token punctuation">"</span></span>
        <span class="token attr-name">VerticalOptions</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Center<span class="token punctuation">"</span></span> <span class="token punctuation">/&gt;</span></span>

    <span class="token comment">&lt;!-- CollectionView --&gt;</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>CollectionView</span>
        <span class="token attr-name">Grid.Row</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>1<span class="token punctuation">"</span></span>
        <span class="token attr-name">ItemsSource</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>{Binding Products}<span class="token punctuation">"</span></span>
        <span class="token attr-name">SelectedItem</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>{Binding SelectedProduct}<span class="token punctuation">"</span></span>
        <span class="token attr-name">SelectionMode</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Single<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>

        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>CollectionView.ItemTemplate</span><span class="token punctuation">&gt;</span></span>
            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>DataTemplate</span> <span class="token attr-name"><span class="token namespace">x:</span>DataType</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>models:ProductModel<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
                <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>Border</span>
                    <span class="token attr-name">Margin</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>0,4<span class="token punctuation">"</span></span>
                    <span class="token attr-name">Padding</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>12<span class="token punctuation">"</span></span>
                    <span class="token attr-name">BackgroundColor</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>{AppThemeBinding Light=White, Dark=#1E1E1E}<span class="token punctuation">"</span></span>
                    <span class="token attr-name">StrokeShape</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>RoundRectangle 8<span class="token punctuation">"</span></span>
                    <span class="token attr-name">Stroke</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>#E0E0E0<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>

                    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>Grid</span> <span class="token attr-name">ColumnDefinitions</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>*,Auto<span class="token punctuation">"</span></span> <span class="token attr-name">RowDefinitions</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Auto,Auto<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>

                        <span class="token comment">&lt;!-- Product name --&gt;</span>
                        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>Label</span>
                            <span class="token attr-name">Grid.Row</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>0<span class="token punctuation">"</span></span> <span class="token attr-name">Grid.Column</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>0<span class="token punctuation">"</span></span>
                            <span class="token attr-name">Text</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>{Binding Name}<span class="token punctuation">"</span></span>
                            <span class="token attr-name">FontSize</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>16<span class="token punctuation">"</span></span>
                            <span class="token attr-name">FontAttributes</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Bold<span class="token punctuation">"</span></span> <span class="token punctuation">/&gt;</span></span>

                        <span class="token comment">&lt;!-- Price --&gt;</span>
                        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>Label</span>
                            <span class="token attr-name">Grid.Row</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>0<span class="token punctuation">"</span></span> <span class="token attr-name">Grid.Column</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>1<span class="token punctuation">"</span></span>
                            <span class="token attr-name">Text</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>{Binding Price, StringFormat=<span class="token punctuation">'</span>${0:F2}<span class="token punctuation">'</span>}<span class="token punctuation">"</span></span>
                            <span class="token attr-name">FontSize</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>16<span class="token punctuation">"</span></span>
                            <span class="token attr-name">FontAttributes</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Bold<span class="token punctuation">"</span></span>
                            <span class="token attr-name">TextColor</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>#512BD4<span class="token punctuation">"</span></span>
                            <span class="token attr-name">HorizontalOptions</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>End<span class="token punctuation">"</span></span> <span class="token punctuation">/&gt;</span></span>

                        <span class="token comment">&lt;!-- Category --&gt;</span>
                        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>Label</span>
                            <span class="token attr-name">Grid.Row</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>1<span class="token punctuation">"</span></span> <span class="token attr-name">Grid.Column</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>0<span class="token punctuation">"</span></span>
                            <span class="token attr-name">Text</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>{Binding Category}<span class="token punctuation">"</span></span>
                            <span class="token attr-name">FontSize</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>13<span class="token punctuation">"</span></span>
                            <span class="token attr-name">TextColor</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Gray<span class="token punctuation">"</span></span> <span class="token punctuation">/&gt;</span></span>

                        <span class="token comment">&lt;!-- In Stock badge --&gt;</span>
                        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>Label</span>
                            <span class="token attr-name">Grid.Row</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>1<span class="token punctuation">"</span></span> <span class="token attr-name">Grid.Column</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>1<span class="token punctuation">"</span></span>
                            <span class="token attr-name">Text</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>{Binding InStock, Converter={StaticResource BoolToStockConverter}}<span class="token punctuation">"</span></span>
                            <span class="token attr-name">FontSize</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>12<span class="token punctuation">"</span></span>
                            <span class="token attr-name">TextColor</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>{Binding InStock, Converter={StaticResource BoolToStockColorConverter}}<span class="token punctuation">"</span></span>
                            <span class="token attr-name">HorizontalOptions</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>End<span class="token punctuation">"</span></span> <span class="token punctuation">/&gt;</span></span>
                    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>Grid</span><span class="token punctuation">&gt;</span></span>
                <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>Border</span><span class="token punctuation">&gt;</span></span>
            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>DataTemplate</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>CollectionView.ItemTemplate</span><span class="token punctuation">&gt;</span></span>

    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>CollectionView</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>Grid</span><span class="token punctuation">&gt;</span></span>
</code></pre><p>In the previous code there isn&rsquo;t much customization, because an unmodified <code>CollectionView</code> is being used:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-05/dotnet-maui-collectionview-vertical-list.png?sfvrsn=95310cd6_2" alt="Native .NET MAUI CollectionView displaying a vertical list" /></p><p>Although it&rsquo;s true that we could customize it manually through a <code>DataTemplate</code>, most of the time what is required is a quick but robust implementation. Let&rsquo;s use the MCP server to modify the look and feel by giving the following instruction:</p><pre class=" language-text"><code class="prism  language-text">#telerik-maui-assistant  I need you to improve the ProductsPageTelerik page. Replace the CollectionView with a DataGrid. I need the page and its controls to look modern and interactive.
</code></pre><p>When running the instruction and having the Telerik MCP server selected, we will receive a request to run tools, whose information is obtained automatically based on the query made:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-05/telerik-mcp-maui-permission-prompt.png?sfvrsn=2d8aa7cf_2" alt="Telerik MCP server permission dialog requesting tool execution" /></p><p>With the evolution of AI models, we can achieve that in a single call our instruction is executed, with the GitHub Copilot agent responsible for modifying the code, compiling and testing that everything works correctly. In just a few minutes, the replacement is very precise:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-05/maui-datagrid-table.png?sfvrsn=ae2254d8_2" alt="Converted DataGrid showing tabular data with columns" /></p><p>Another thing we can do is use the Telerik <a target="_blank" href="https://www.telerik.com/maui-ui/documentation/ai/prompt-library">Prompt Library</a>, which contains a list of prompts for different use cases.</p><p>For example, suppose you&rsquo;d like to add paging to the component. To accomplish this, you can take the prompt <strong>DataGrid with Paging</strong> and adapt it to your use case, as follows:</p><pre class=" language-text"><code class="prism  language-text">#telerik-maui-assistant Modify the DataGrid to include pagination of 20 records per page.
</code></pre><p>Again, after a few calls to the MCP tool, the change is implemented in just a few minutes:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-05/pagination-added-with-mcp.png?sfvrsn=d786983d_2" alt="Pagination feature added quickly using the MCP server" /></p><p>With the previous exercises, you have been able to verify the power of using the Telerik MCP server for .NET MAUI to create robust graphical interfaces in much less time.</p><h2 id="conclusion">Conclusion</h2><p>In this article you learned about the Telerik UI for .NET MAUI AI Coding Assistant, a powerful MCP server specialized in using Telerik controls to guide you and implement complex graphical interfaces using artificial intelligence.</p><p>Undoubtedly, having this assistant provides a competitive advantage by helping you reduce the time required to create graphical interfaces, while also allowing you to explore design alternatives.</p><hr /><p><strong>Remember:</strong> Telerik UI for .NET MAUI comes with a free 30-day trial. </p><p><a href="https://www.telerik.com/try/ui-for-maui" target="_blank" class="Btn">Try Now</a></p>]]></content>
  </entry>
  <entry>
    <id>urn:uuid:6226fc64-e8ab-4f7f-9a05-3dfe380b4d93</id>
    <title type="text">How to Verify Network Connectivity in .NET MAUI</title>
    <summary type="text">Learn the key steps to checking network connectivity in the various platforms available to your .NET MAUI app.</summary>
    <published>2026-05-11T13:22:15Z</published>
    <updated>2026-07-12T05:29:41Z</updated>
    <author>
      <name>Leomaris Reyes </name>
    </author>
    <link rel="alternate" href="https://www.telerik.com/blogs/how-to-verify-network-connectivity-net-maui?utm_medium=feed&amp;utm_source=feedpress.me&amp;utm_campaign=Feed%3A+telerik-blogs-desktop"/>
    <content type="text"><![CDATA[<p><span class="featured">Learn the key steps to checking network connectivity in the various platforms available to your .NET MAUI app.</span></p><p>Identifying the connectivity of the devices running our mobile applications allows us to have much more precise control over the decisions we need to make within the app. From knowing whether the device has internet access, if the connection is limited, and if <strong>connection types such as Bluetooth, WiFi or Ethernet</strong> are active, all this information helps us provide a better user experience.</p><p>For example, we can decide whether to show an empty state when there is no internet connection, prevent certain actions or clearly inform the user about what is happening. This is especially important because, in many cases, the user loses connectivity and assumes the problem is with the application, when in reality it is a network issue.</p><p>Additionally, we can display different scenarios or behaviors depending on the type of connection available, such as when the device only has Bluetooth active or does not have internet access. That&rsquo;s why it&rsquo;s essential to know how to detect these connectivity states. The good news is that in .NET MAUI, we have the ability to do this in a very simple way. Let&rsquo;s take a look! </p><h2 id="first-platform-configuration">First, Platform Configuration</h2><p>Before starting with any implementation, it&rsquo;s important to verify whether you need to apply any platform-specific configuration. Some platforms may require additional setup, while others work out of the box.</p><p>For this, <strong>iOS/Mac Catalyst</strong> and <strong>Windows</strong> require no additional configuration.</p><p>For <strong>Android</strong>, to access connectivity information, you must add the <code>ACCESS_NETWORK_STATE</code> permission. There are three different ways to add this permission on Android:</p><h3 id="android-option-1-add-the-permission-directly-in-the-androidmanifest.xml">Android Option 1: Add the Permission Directly in the AndroidManifest.xml</h3><p>Go to Platforms &rarr; Android, open the AndroidManifest.xml file, and add the following node:</p><pre class=" language-xml"><code class="prism  language-xml">&lt;uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /&gt;
</code></pre><h3 id="android-option-2-use-the-android-manifest-graphical-editor">Android Option 2: Use the Android Manifest Graphical Editor</h3><p>Go to Platforms &rarr; Android, double-click the AndroidManifest.xml file, and locate the Required permissions section. Find the permission labeled <strong>ACCESS_NETWORK_STATE</strong> and simply check the option, as shown below.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-05/02_permissions.png?sfvrsn=70ef6bff_2" title="Required permissions" alt="" /></p><h3 id="android-option-3-add-the-assembly-based-permission">Android Option 3: Add the Assembly-based Permission</h3><p>Go to Platforms &rarr; Android &rarr; MainApplication.cs and add the permission as follows:</p><pre class=" language-csharp"><code class="prism  language-csharp">[assembly: UsesPermission(Android.Manifest.Permission.AccessNetworkState)]
</code></pre><h2 id="network-accessibility-in-.net-maui">Network Accessibility in .NET MAUI</h2><p>To inspect the network accessibility on a device, .NET MAUI provides the IConnectivity interface. This is part of the Microsoft.Maui.Networking namespace and is available through the <code>Connectivity.Current</code> property.</p><p>One thing I really like about this API is that it doesn&rsquo;t simply return a boolean value indicating whether there is internet access or not. Instead, it provides much more detailed information, such as the scope of the current network (for example, Internet, ConstrainedInternet and others), as well as details about active connection profiles like Bluetooth, Cellular, WiFi and others. It also exposes an event that allows you to monitor changes in the device&rsquo;s connectivity state in real time.</p><p>Next, we&rsquo;ll take a closer look at each of these values to better understand what they mean and how you can use them in your applications.</p><h2 id="how-to-inspect-the-current-network-scope-">How to Inspect the Current Network Scope? </h2><p>Thanks to the .NET MAUI team, we can determine the scope of the current network in a much more precise way through the <code>NetworkAccess</code> property. This property provides different values that we can evaluate to obtain more detailed information about the device&rsquo;s connectivity state. These values are the following:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-05/01_internet_connection.png?sfvrsn=f3b0f0be_2" title="Internet connection" alt="" /></p><p>➖ <strong>Internet:</strong> Indicates that the device has access to both the local network and the internet. This is the ideal state for making API calls or performing any action that requires a full internet connection.</p><p>➖ <strong>Local:</strong> The device has access only to the local network.</p><p>➖ <strong>None:</strong> No type of connectivity is available. In this state, it&rsquo;s ideal to inform the user that all or some actions within the app will not work correctly due to the lack of connectivity. This can be done through an empty state, an alert or any other approach that best fits the scenario you&rsquo;re working on.</p><p>➖ <strong>Unknown:</strong> It&rsquo;s not possible to determine the connectivity state. If this happens, while the correct information is being retrieved, it&rsquo;s recommended to inform the user in the same way as in the None state.</p><p>➖ <strong>ConstrainedInternet:</strong> Indicates that the device has limited internet access. This state usually appears when the device is connected to a network with a captive portal, meaning networks that require accepting terms or entering information before granting full internet access. This is common in places like airports, universities or hotels.</p><p>Thanks to all these states, as developers we can be much more specific in how we communicate connectivity issues to our users and better adapt the behavior of our applications.</p><p>For the code implementation, you can do something like what I show below:</p><pre class=" language-csharp"><code class="prism  language-csharp">NetworkAccess accessType = Connectivity.Current.NetworkAccess; 

if (accessType == NetworkAccess.Internet) 
{ 
    // Add the code that you need here 
}
</code></pre><h2 id="checking-active-connection-profiles">Checking Active Connection Profiles</h2><p>While NetworkAccess tells us how accessible the network is (internet, local, none, etc.), ConnectionProfiles allows us to know which type of connection the device is actively using at a given moment.</p><p>The types of connections we can detect are the following:</p><ul><li><strong>WiFi</strong></li><li><strong>Cellular</strong> (mobile data)</li><li><strong>Bluetooth</strong></li><li><strong>Ethernet</strong></li></ul><p>This information is extremely useful for making decisions within your application. For example:</p><ul><li>You can limit your app to download files <strong>only when the device is connected to a WiFi network</strong>.</li><li>Enable local features <strong>when only a Bluetooth connection is available</strong>.</li></ul><p>It&rsquo;s important to keep in mind that <strong>Connectivity.Current.ConnectionProfiles</strong> returns a collection (<code>IEnumerable&lt;ConnectionProfile&gt;</code>), because a device can have multiple connection types active at the same time. For instance, the device may be connected to WiFi while Bluetooth is enabled simultaneously.</p><p>In code, the implementation would look like the following:</p><pre class=" language-csharp"><code class="prism  language-csharp">IEnumerable&lt;ConnectionProfile&gt; profiles = Connectivity.Current.ConnectionProfiles;

if (profiles.Contains(ConnectionProfile.WiFi)) 
{ 
    // Add the code that you need here. 
}
</code></pre><h2 id="reacting-to-connectivity-changes">Reacting to Connectivity Changes</h2><p>We know that network conditions can change at any moment. For this reason, .NET MAUI provides the <code>ConnectivityChanged</code> event, which allows us to detect when network access or active connection profiles change. This makes it possible for our applications to react immediately to these changes, without breaking the app experience.</p><p>Let&rsquo;s take a look at an example based on the official documentation:</p><pre class=" language-csharp"><code class="prism  language-csharp">public class ConnectivityListener 
{ 
    public ConnectivityListener() 
    { 
    Connectivity.ConnectivityChanged += OnConnectivityChanged; 
    }
     
    void OnConnectivityChanged(object sender, ConnectivityChangedEventArgs e) 
    { 
    if (e.NetworkAccess != NetworkAccess.Internet) 
    { 
    Console.WriteLine("No internet connection available."); 
    return; 
    }
     
    if (e.ConnectionProfiles.Contains(ConnectionProfile.WiFi)) 
    { 
    Console.WriteLine("Connected via Wi-Fi."); 
    } 
    else if (e.ConnectionProfiles.Contains(ConnectionProfile.Cellular)) 
    { 
    Console.WriteLine("Using mobile data."); 
    } 
    } 
}
</code></pre><h2 id="⚠️-important-considerations">⚠️ Important Considerations</h2><p><strong>NetworkAccess.Internet:</strong> Due to how connectivity detection works on each platform, .NET MAUI can only detect that a network connection is available. It does not guarantee that the connection has real internet access. For example, a device may be connected to a WiFi network, but the router itself may not have an internet connection.</p><h2 id="conclusion">Conclusion</h2><p>And that&rsquo;s it!  In this article, you explored how to work with network connectivity in .NET MAUI using Connectivity. You learned how to determine the scope of the current network, detect active connection profiles such as WiFi, Cellular, Bluetooth and Ethernet, and react to connectivity changes in real time using the <code>ConnectivityChanged</code> event.</p><p>With this knowledge, you can now make better decisions in your apps, provide clearer feedback to users and build more resilient experiences that adapt to changing network conditions.</p><p>See you in the next article! &zwj;♀️✨</p><h3 id="references">References</h3><p>Code samples and explanations were based on the official documentation:</p><ul><li><a target="_blank" href="https://learn.microsoft.com/en-us/dotnet/maui/platform-integration/communication/networking?view=net-maui-10.0&amp;tabs=android">https://learn.microsoft.com/en-us/dotnet/maui/platform-integration/communication/networking?view=net-maui-10.0&amp;tabs=android</a></li></ul><aside><hr data-sf-ec-immutable="" /><div class="row"><div class="col-4 u-normal-full u-small-mb0"><h4 class="u-fs20 u-fw5 u-lh125 u-mb0">Get Your .NET MAUI App Up More Quickly</h4></div><div class="col-8"><p class="u-fs16 u-mb0">Deliver native apps for every platform in half the time with 70+ customizable UI components, an AI Coding Assistant and unmatched productivity tools. <a href="https://www.telerik.com/maui-ui" target="_blank">Check out Progress Telerik UI for .NET MAUI</a>.</p></div></div></aside>]]></content>
  </entry>
  <entry>
    <id>urn:uuid:3ff0a7d1-e5ec-4f1e-8409-1e23c12969cd</id>
    <title type="text">Integrating Haptic Feedback in .NET MAUI</title>
    <summary type="text">Learn how to give your users interactive feedback with long or short haptic vibration in your .NET MAUI application.</summary>
    <published>2026-05-04T17:04:07Z</published>
    <updated>2026-07-12T05:29:41Z</updated>
    <author>
      <name>Leomaris Reyes </name>
    </author>
    <link rel="alternate" href="https://www.telerik.com/blogs/integrating-haptic-feedback-net-maui?utm_medium=feed&amp;utm_source=feedpress.me&amp;utm_campaign=Feed%3A+telerik-blogs-desktop"/>
    <content type="text"><![CDATA[<p><span class="featured">Learn how to give your users interactive feedback with long or short haptic vibration in your .NET MAUI application.</span></p><p>From my experience, keeping users continuously informed about in-app activity is one of the most important retention strategies.</p><p>This feedback can take different forms. For example:</p><ul><li>A message indicating that a record could not be created because the email format isn&rsquo;t valid</li><li>An empty state that informs the user that the app is not working due to a loss of internet connection</li><li>Sound feedback that confirms an action such as a successful transaction</li></ul><p>However, there is another type of feedback that goes beyond visuals or sound: <strong>feedback that can be felt.</strong> This is where haptic feedback comes into play. This type of feedback is usually expressed through a device vibration to notify the user that an action has occurred.</p><p>Common examples include banking applications that vibrate when a transaction is completed successfully, or gaming apps that use vibrations to indicate a collision or an important in-game event. This type of interaction can help create a closer and more natural communication between the user and the application.</p><p>The good news is that today you will learn how to integrate <strong>haptic feedback</strong> into your .NET MAUI applications in a simple and very fast way! </p><h2 id="what-exactly-is-ihapticfeedback-">What Exactly Is IHapticFeedback? </h2><p>IHapticFeedback is an interface in the Microsoft.Maui.Devices namespace that allows you to trigger device vibrations and can be accessed through the HapticFeedback.Default property.</p><p>Haptic feedback provides two different sensation modes that we can trigger in our application:</p><h3 id="click">Click</h3><p>This refers to a short and subtle vibration. It&rsquo;s a great option when we want to provide feedback for simple interactions, such as tapping a button, selecting an item from a list or performing quick actions.</p><h3 id="longpress">LongPress</h3><p>This produces a longer vibration compared to Click. It&rsquo;s mainly used for actions that require more attention or have greater importance, such as confirming a transaction or notifying the user about a relevant event.</p><p>Through HapticFeedback, we can specify which type of sensation we want to trigger. Let&rsquo;s see how to get it implemented.</p><h2 id="initial-setup">Initial Setup</h2><p>For <strong>Android</strong>, we need authorization in our application in order to vibrate the device. This permission can be added in three different ways, which we&rsquo;ll look at below.</p><p>For <strong>iOS / Mac Catalyst</strong> and <strong>Windows</strong>, no initial setup is required.</p><h3 id="android-option-1-add-it-directly-to-the-android-manifest">Android Option 1: Add It Directly to the Android Manifest</h3><p>You can find this file at Platforms ➖ Android ➖ AndroidManifest.xml. Open it and add the following line:</p><pre class=" language-xml"><code class="prism  language-xml">&lt;uses-permission android:name="android.permission.VIBRATE" /&gt;
</code></pre><h3 id="android-option-2-using-the-android-manifest-editor">Android Option 2: Using the Android Manifest Editor</h3><p>Go to <strong>Platforms ➖ Android</strong>, double-click the <strong>AndroidManifest.xml</strong> file and locate the <strong>Required permissions</strong> section. Find the permission labeled <strong>VIBRATE</strong> and simply check the option, as shown below.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-04/01_permissions.png?sfvrsn=1942c2a0_2" title="Required permissions" alt="" /></p><p>This automatically adds the same line we saw in the first option, but through a graphical interface.</p><h3 id="android-option-3-adding-the-assembly-based-permission">Android Option 3: Adding the Assembly-based Permission</h3><p>Go to the file Platforms ➖Android ➖ MainApplication.cs and add the permission as follows:</p><pre class=" language-csharp"><code class="prism  language-csharp">[assembly: UsesPermission(Android.Manifest.Permission.Vibrate)]
</code></pre><h2 id="how-to-implement-haptic-feedback">How to Implement Haptic Feedback?</h2><p>Once we understand what haptic feedback is and have the correct platform configuration in place, adding it to our project is very easy.</p><h3 id="click-short-haptic">Click (Short Haptic)</h3><pre class=" language-csharp"><code class="prism  language-csharp">private void HapticShortButton_Clicked(object sender, EventArgs e) =&gt;

HapticFeedback.Default.Perform(HapticFeedbackType.Click);
</code></pre><p>Taking a closer look, this code represents an event handler that contains the following:</p><ul><li><p><strong>HapticFeedback.Default:</strong> retrieves the default system implementation for the current device.</p></li><li><p><strong>.Perform(HapticFeedbackType.Click):</strong> tells the system to execute a Click haptic feedback immediately.</p></li></ul><h3 id="longpress-longer-haptic">LongPress (Longer Haptic)</h3><pre class=" language-csharp"><code class="prism  language-csharp">private void HapticLongButton_Clicked(object sender, EventArgs e) =&gt;

HapticFeedback.Default.Perform(HapticFeedbackType.LongPress);
</code></pre><p>This works exactly the same way as the previous example, but changes the feedback type to <strong>LongPress</strong>, resulting in a stronger and longer tactile response.</p><h3 id="connecting-haptic-feedback-to-a-button">Connecting Haptic Feedback to a Button</h3><p>Let&rsquo;s look at a simple example using buttons in XAML:</p><pre class=" language-xml"><code class="prism  language-xml">&lt;Button Text="Short Haptic" Clicked="HapticShortButton_Clicked"/&gt;

&lt;Button Text="Long Haptic" Clicked="HapticLongButton_Clicked"/&gt;
</code></pre><p>With this setup, each button triggers a different type of haptic feedback when clicked, allowing the user to feel the interaction directly through the device.</p><h3 id="-platform-considerations"> Platform Considerations</h3><ul><li>On Apple, haptic feedback must be triggered from the UI thread.</li></ul><h2 id="conclusion">Conclusion</h2><p>And that&rsquo;s it!  In this article, you learned what <strong>haptic feedback</strong> is and how it can significantly improve user experience by providing tactile confirmation for user interactions in your .NET MAUI applications.</p><p>You also explored the different types of haptic feedback available&mdash;<strong>Click</strong> and <strong>LongPress</strong>&mdash;and when to use each one, as well as the platform-specific setup required, especially on Android, to enable the feature to work correctly across devices.</p><p>With these concepts in mind, you now have a clear understanding of how to integrate haptic feedback in a simple and effective way, enhancing interaction, usability, and overall app retention without adding unnecessary complexity to your code.</p><p>If you have any questions or would like me to cover more .NET MAUI topics, feel free to leave a comment&mdash;I&rsquo;d be happy to help! </p><p>See you in the next article! &zwj;♀️✨</p><h3 id="references">References</h3><p>The explanation was based on the official documentation:</p><ul><li><a target="_blank" href="https://learn.microsoft.com/en-us/dotnet/maui/platform-integration/device/haptic-feedback?view=net-maui-10.0&amp;tabs=android">https://learn.microsoft.com/en-us/dotnet/maui/platform-integration/device/haptic-feedback?view=net-maui-10.0&amp;tabs=android</a></li></ul><aside><hr data-sf-ec-immutable="" /><div class="row"><div class="col-4 u-normal-full u-small-mb0"><h4 class="u-fs20 u-fw5 u-lh125 u-mb0">Building Chat Applications with the .NET MAUI Chat (Conversational UI) Control</h4></div><div class="col-8"><p class="u-fs16 u-mb0">The <a target="_blank" href="https://www.telerik.com/blogs/building-chat-applications-net-maui-chat-conversational-ui-control">.NET MAUI Conversational UI (Chat) component allows integrating chat experiences</a> into your mobile and desktop applications. Learn how to work with this chat component, use cases and how to integrate LLM models.</p></div></div></aside>]]></content>
  </entry>
  <entry>
    <id>urn:uuid:3f5e3e2c-0528-4522-a2c8-b3c294e5861d</id>
    <title type="text">Building Chat Applications with the .NET MAUI Chat (Conversational UI) Control</title>
    <summary type="text">The .NET MAUI Conversational UI (Chat) component allows integrating chat experiences into your mobile and desktop applications. Learn how to work with this chat component, use cases and how to integrate LLM models.</summary>
    <published>2026-04-27T19:45:10Z</published>
    <updated>2026-07-12T05:29:41Z</updated>
    <author>
      <name>Héctor Pérez </name>
    </author>
    <link rel="alternate" href="https://www.telerik.com/blogs/building-chat-applications-net-maui-chat-conversational-ui-control?utm_medium=feed&amp;utm_source=feedpress.me&amp;utm_campaign=Feed%3A+telerik-blogs-desktop"/>
    <content type="text"><![CDATA[<p><span class="featured">The .NET MAUI Conversational UI (Chat) component allows integrating chat experiences into your mobile and desktop applications. Learn how to work with this chat component, use cases and how to integrate LLM models.</span></p><p>One of the best ways to connect with a customer is through conversations, whether with a real person or through an AI agent that provides information about the company or solves problems using a knowledge base.</p><p>If you are creating .NET MAUI applications, you should know that in the Progress Telerik suite you can find the <a target="_blank" href="https://www.telerik.com/maui-ui">.NET MAUI Conversational UI (Chat)</a> component, featuring several characteristics that will allow you to create chat-based applications quickly.</p><p>Throughout this post, we will create an app that uses AI models to provide tips on healthy eating. Let&rsquo;s see how to do it!</p><h2 id="understanding-the-radchat-control-from-telerik-for-.net-maui">Understanding the RadChat Control from Telerik for .NET MAUI</h2><p>The <code>RadChat</code> control from Telerik for .NET MAUI is a component that allows users to interact through a conversational interface, production-ready, capable of handling text messages, attachments, voice-to-text integration and full customization so you can adapt it to your own style, among many other features.</p><p>The control is composed of different graphical elements that we can control and modify through code, as shown in the following image:</p><p><img src="https://www.telerik.com/maui-ui/documentation/assets/898f7480b0af1c2627c39907f618d733/chat-visualstructure.png" alt="RadChat Component Visual Structure" /></p><p>Some typical use cases for the control include:</p><ul><li>AI chatbots</li><li>Real-time customer support</li><li>Messaging applications</li><li>Virtual assistants</li><li>Image analysis with vision AI models</li><li>Among many others</li></ul><p>Let&rsquo;s see how to implement the control in a real application.</p><h2 id="setting-up-a-.net-maui-project-to-integrate-chat-conversations">Setting Up a .NET MAUI Project to Integrate Chat Conversations</h2><p>The first and most important thing when using the chat component in our applications is to follow the <a target="_blank" href="https://www.telerik.com/maui-ui/documentation/get-started/first-steps-vs">official installation guide</a>, which shows different ways to set up your environment.</p><p>Additionally, if you want to use any AI model, you need to set up the project by installing the corresponding NuGet packages. As a personal preference, I always like to use <code>Microsoft.Extensions.AI</code>, as it greatly simplifies handling requests to both <strong>OpenAI</strong> and <strong>Azure OpenAI</strong>. For this, install the following packages:</p><ul><li><code>Azure.AI.OpenAI</code></li><li><code>Microsoft.Extensions.AI</code></li><li><code>Microsoft.Extensions.AI.OpenAI</code></li></ul><p>Finally, to facilitate handling with the MVVM pattern, I recommend installing the community toolkit through the following package:</p><ul><li><code>CommunityToolkit.Mvvm</code></li></ul><p>With the packages installed, let&rsquo;s implement the control.</p><h2 id="integrating-chat-functionality-into-a-.net-maui-project">Integrating Chat Functionality into a .NET MAUI Project</h2><p>To use the <code>RadChat</code> control in a .NET MAUI application, you need to do this using the <code>RadChat</code> tag as shown in the following example:</p><pre class=" language-xml"><code class="prism  language-xml"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>ContentPage</span> <span class="token attr-name">...</span>
    <span class="token attr-name"><span class="token namespace">xmlns:</span>telerik</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>http://schemas.telerik.com/2022/xaml/maui<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>

    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span><span class="token namespace">telerik:</span>RadChat</span> <span class="token attr-name"><span class="token namespace">x:</span>Name</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>chat<span class="token punctuation">"</span></span> <span class="token punctuation">/&gt;</span></span>

<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>ContentPage</span><span class="token punctuation">&gt;</span></span>
</code></pre><p>By including the above code, we will immediately see the chat control in the emulator:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-04/basic-radchat-interface.png?sfvrsn=e2cb5709_2" alt="Basic RadChat Interface" /></p><h2 id="interacting-with-chat-messages-in-a-.net-maui-app">Interacting with Chat Messages in a .NET MAUI App</h2><p>To work with chat messages, you should know that the class <code>ChatMessage</code> is the basic class for handling messages, which contains the property <code>Author</code>, used to define the information of a participant that will appear in the UI. <code>Author</code> contains data such as <code>Name</code>, <code>Avatar</code> and <code>Data</code>.</p><p>It is possible to extend this class as the control itself does through <code>TextMessage</code>, which inherits from <code>ChatMessage</code> by adding the property <code>Text</code>.</p><p>Knowing this, we will create a list of <code>TextMessage</code> to maintain the conversation history, as well as define the different roles of type <code>Author</code> that will be used in the conversation. For the example, I have created the class <code>ChatViewModel</code>, which looks as follows:</p><pre class=" language-csharp"><code class="prism  language-csharp"><span class="token keyword">public</span> <span class="token keyword">partial</span> <span class="token keyword">class</span> <span class="token class-name">ChatViewModel</span> <span class="token punctuation">:</span> ObservableObject
<span class="token punctuation">{</span>
    <span class="token punctuation">[</span>ObservableProperty<span class="token punctuation">]</span>
    <span class="token keyword">private</span> ObservableCollection<span class="token operator">&lt;</span>TextMessage<span class="token operator">&gt;</span> items <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span>

    <span class="token keyword">public</span> Author Me <span class="token punctuation">{</span> <span class="token keyword">get</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
    <span class="token keyword">public</span> Author Bot <span class="token punctuation">{</span> <span class="token keyword">get</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>

    <span class="token keyword">public</span> <span class="token function">ChatViewModel</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
    <span class="token punctuation">{</span>
        Me <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Author</span> <span class="token punctuation">{</span> Name <span class="token operator">=</span> <span class="token string">"You"</span> <span class="token punctuation">}</span><span class="token punctuation">;</span>
        Bot <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Author</span> <span class="token punctuation">{</span> Name <span class="token operator">=</span> <span class="token string">"NutriBot"</span> <span class="token punctuation">}</span><span class="token punctuation">;</span>

        Items<span class="token punctuation">.</span><span class="token function">Add</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">TextMessage</span>
        <span class="token punctuation">{</span>
            Author <span class="token operator">=</span> Bot<span class="token punctuation">,</span>
            Text <span class="token operator">=</span> <span class="token string">"Hello!  I'm NutriBot, your AI-powered nutrition assistant.\n\n"</span> <span class="token operator">+</span>
                    <span class="token string">"I can help you with:\n"</span> <span class="token operator">+</span>
                    <span class="token string">"Analyzing how healthy a food is\n"</span> <span class="token operator">+</span>
                    <span class="token string">"Analyzing photos of food or nutrition labels\n"</span> <span class="token operator">+</span>
                    <span class="token string">"Providing recommendations for a healthy diet\n"</span> <span class="token operator">+</span>
                    <span class="token string">"Evaluating recipes\n\n"</span> <span class="token operator">+</span>
                    <span class="token string">"Send me a message or a photo to get started!"</span>
        <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>            
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><p>On the other hand, the RadChat control has the properties <code>Author</code>, which allows specifying who is interacting, in addition to <code>Items</code>, responsible for managing the message history:</p><pre class=" language-xml"><code class="prism  language-xml"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span><span class="token namespace">telerik:</span>RadChat</span>
    <span class="token attr-name"><span class="token namespace">x:</span>Name</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>chat<span class="token punctuation">"</span></span>
    <span class="token attr-name">Author</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>{Binding Me}<span class="token punctuation">"</span></span>
    <span class="token attr-name">ItemsSource</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>{Binding Items}<span class="token punctuation">"</span></span> <span class="token punctuation">/&gt;</span></span>
</code></pre><p>For the previous viewmodel to work correctly, remember to configure both the code-behind of your page and the dependency injection as follows:</p><p><strong>MauiProgram.cs</strong></p><pre class=" language-csharp"><code class="prism  language-csharp"><span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">class</span> <span class="token class-name">MauiProgram</span>
<span class="token punctuation">{</span>
    <span class="token keyword">public</span> <span class="token keyword">static</span> MauiApp <span class="token function">CreateMauiApp</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
    <span class="token punctuation">{</span>
        <span class="token keyword">var</span> builder <span class="token operator">=</span> MauiApp<span class="token punctuation">.</span><span class="token function">CreateBuilder</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>
        builder<span class="token punctuation">.</span>Services<span class="token punctuation">.</span><span class="token generic-method function">AddTransient<span class="token punctuation">&lt;</span>ChatViewModel<span class="token punctuation">&gt;</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>            
        <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>
        <span class="token keyword">return</span> builder<span class="token punctuation">.</span><span class="token function">Build</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><p><strong>MainPage.xaml.cs</strong></p><pre class=" language-csharp"><code class="prism  language-csharp"><span class="token keyword">public</span> <span class="token function">MainPage</span><span class="token punctuation">(</span>ChatViewModel viewModel<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
    <span class="token function">InitializeComponent</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    BindingContext <span class="token operator">=</span> viewModel<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><p>Executing the previous code allows you to see the welcome message in the chat history:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-04/displaying-chat-app-welcome-message.png?sfvrsn=88610ef7_2" alt="Displaying chat app welcome message" /></p><h2 id="receiving-and-returning-chat-messages">Receiving and Returning Chat Messages</h2><p>So far, we have a list of messages in the application; however, there is no real interaction, meaning that messages are not sent or received back. The control has some commands by default that can help us with this task:</p><ul><li><code>SendMessageCommand</code>: executes when a message is sent</li><li><code>PickFileCommand</code>: executes when attempting to attach a file</li><li><code>PickPhotoCommand</code>: executes when wanting to attach a photo</li><li><code>TakePhotoCommand</code>: executes when the camera opens to take a photo</li></ul><p>There are other <a target="_blank" href="https://www.telerik.com/maui-ui/documentation/controls/chat/commands#commands-related-to-attachments">commands for working with attachments</a>, but the main ones are the above.</p><p>Let&rsquo;s implement the functionality to send and receive messages in the viewmodel, creating a property <code>Message</code> that allows binding the user&rsquo;s message, in addition to a method <code>SendMessage</code>, which will be linked to <code>SendMessageCommand</code> as follows:</p><pre class=" language-csharp"><code class="prism  language-csharp"><span class="token keyword">public</span> <span class="token keyword">partial</span> <span class="token keyword">class</span> <span class="token class-name">ChatViewModel</span> <span class="token punctuation">:</span> ObservableObject
<span class="token punctuation">{</span>
    <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>
    <span class="token punctuation">[</span>ObservableProperty<span class="token punctuation">]</span>
    <span class="token keyword">private</span> <span class="token keyword">string</span> message <span class="token operator">=</span> <span class="token keyword">string</span><span class="token punctuation">.</span>Empty<span class="token punctuation">;</span>
    <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>
    
    <span class="token punctuation">[</span>RelayCommand<span class="token punctuation">]</span>
    <span class="token keyword">private</span> <span class="token keyword">async</span> Task <span class="token function">SendMessage</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
    <span class="token punctuation">{</span>
        <span class="token keyword">var</span> messageText <span class="token operator">=</span> Message<span class="token punctuation">;</span>
        Message <span class="token operator">=</span> <span class="token keyword">string</span><span class="token punctuation">.</span>Empty<span class="token punctuation">;</span>

        Items<span class="token punctuation">.</span><span class="token function">Add</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">TextMessage</span> <span class="token punctuation">{</span> Author <span class="token operator">=</span> Me<span class="token punctuation">,</span> Text <span class="token operator">=</span> messageText <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>            

        Items<span class="token punctuation">.</span><span class="token function">Add</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">TextMessage</span> <span class="token punctuation">{</span> Author <span class="token operator">=</span> Bot<span class="token punctuation">,</span> Text <span class="token operator">=</span> <span class="token string">"Message received!"</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><p>In the UI page, you need to bind this pair of elements using <code>Message</code> and <code>SendMessageCommand</code>:</p><pre class=" language-xml"><code class="prism  language-xml"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span><span class="token namespace">telerik:</span>RadChat</span> <span class="token attr-name">...</span>
    <span class="token attr-name">Message</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>{Binding Message}<span class="token punctuation">"</span></span>
    <span class="token attr-name">SendMessageCommand</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>{Binding SendMessageCommand}<span class="token punctuation">"</span></span> <span class="token punctuation">/&gt;</span></span>
</code></pre><p>With these new changes, we can see that there is a response in the chat window after an interaction:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-04/sending-and-receiving-messages.png?sfvrsn=f503a7ef_2" alt="Sending and receiving messages using predefined commands" /></p><p>Now let&rsquo;s see how to connect an AI model so that we can have more realistic conversations.</p><h2 id="connecting-an-llm-model-to-a-chat-app-in-.net-maui">Connecting an LLM Model to a Chat App in .NET MAUI</h2><p>To use AI in our application, I have created a service-like class that manages the prompt, model information and methods related to obtaining results from the LLM.</p><p>It is worth noting that I have created some variables to store the connection data with the model, solely for demonstration purposes. Ideally, these data should be stored securely on the device, create an external service to handle it, etc.</p><p>The class looks like this:</p><pre class=" language-csharp"><code class="prism  language-csharp"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">ChatService</span>
<span class="token punctuation">{</span>
    <span class="token keyword">private</span> <span class="token keyword">const</span> <span class="token keyword">string</span> Endpoint <span class="token operator">=</span> <span class="token string">"your-endpoint"</span><span class="token punctuation">;</span>
    <span class="token keyword">private</span> <span class="token keyword">const</span> <span class="token keyword">string</span> DeploymentName <span class="token operator">=</span> <span class="token string">"your-deployment-name"</span><span class="token punctuation">;</span>
    <span class="token keyword">private</span> <span class="token keyword">const</span> <span class="token keyword">string</span> ApiKey <span class="token operator">=</span> <span class="token string">"your-api-key"</span><span class="token punctuation">;</span>

    <span class="token keyword">private</span> <span class="token keyword">readonly</span> IChatClient _chatClient<span class="token punctuation">;</span>
    <span class="token keyword">private</span> <span class="token keyword">readonly</span> List<span class="token operator">&lt;</span>ChatMessage<span class="token operator">&gt;</span> _history<span class="token punctuation">;</span>

    <span class="token keyword">private</span> <span class="token keyword">const</span> <span class="token keyword">string</span> SystemPrompt <span class="token operator">=</span> <span class="token string">""</span>"
        You are an expert and friendly nutritionist<span class="token punctuation">.</span> Your role <span class="token keyword">is</span> to<span class="token punctuation">:</span>
        <span class="token operator">-</span> Analyze food photographs and nutrition <span class="token function">labels</span> <span class="token punctuation">(</span>nutrition facts<span class="token punctuation">)</span>
        <span class="token operator">-</span> Evaluate how healthy a food <span class="token keyword">is</span> <span class="token keyword">for</span> a balanced diet
        <span class="token operator">-</span> Provide healthy eating recommendations
        <span class="token operator">-</span> Suggest healthier alternatives when necessary
        <span class="token operator">-</span> Analyze recipes and give your professional opinion
        <span class="token operator">-</span> Answer questions about nutrition<span class="token punctuation">,</span> diets<span class="token punctuation">,</span> and food wellness
        
        When analyzing an image<span class="token punctuation">:</span>
        <span class="token number">1</span><span class="token punctuation">.</span> Identify the food or nutrition label
        <span class="token number">2</span><span class="token punctuation">.</span> Give a rating <span class="token keyword">from</span> <span class="token number">1</span><span class="token operator">-</span><span class="token number">10</span> on how healthy it <span class="token keyword">is</span>
        <span class="token number">3</span><span class="token punctuation">.</span> Explain the nutritional pros and cons
        <span class="token number">4</span><span class="token punctuation">.</span> Suggest improvements or alternatives
        
        Always respond <span class="token keyword">in</span> a concise but informative manner<span class="token punctuation">.</span>
        Don't use emojis<span class="token punctuation">.</span>
        <span class="token string">""</span>"<span class="token punctuation">;</span>

    <span class="token keyword">public</span> <span class="token function">ChatService</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
    <span class="token punctuation">{</span>
        _chatClient <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">AzureOpenAIClient</span><span class="token punctuation">(</span>
                <span class="token keyword">new</span> <span class="token class-name">Uri</span><span class="token punctuation">(</span>Endpoint<span class="token punctuation">)</span><span class="token punctuation">,</span>
                <span class="token keyword">new</span> <span class="token class-name">ApiKeyCredential</span><span class="token punctuation">(</span>ApiKey<span class="token punctuation">)</span><span class="token punctuation">)</span>
            <span class="token punctuation">.</span><span class="token function">GetChatClient</span><span class="token punctuation">(</span>DeploymentName<span class="token punctuation">)</span>
            <span class="token punctuation">.</span><span class="token function">AsIChatClient</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

        _history <span class="token operator">=</span>
        <span class="token punctuation">[</span>
            <span class="token keyword">new</span><span class="token punctuation">(</span>ChatRole<span class="token punctuation">.</span>System<span class="token punctuation">,</span> SystemPrompt<span class="token punctuation">)</span>
        <span class="token punctuation">]</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token comment">/// &lt;summary&gt;</span>
    <span class="token comment">/// Sends a text-only message and returns the AI response.</span>
    <span class="token comment">/// &lt;/summary&gt;</span>
    <span class="token keyword">public</span> <span class="token keyword">async</span> Task<span class="token operator">&lt;</span><span class="token keyword">string</span><span class="token operator">&gt;</span> <span class="token function">SendMessageAsync</span><span class="token punctuation">(</span><span class="token keyword">string</span> userMessage<span class="token punctuation">)</span>
    <span class="token punctuation">{</span>
        _history<span class="token punctuation">.</span><span class="token function">Add</span><span class="token punctuation">(</span><span class="token keyword">new</span><span class="token punctuation">(</span>ChatRole<span class="token punctuation">.</span>User<span class="token punctuation">,</span> userMessage<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token keyword">var</span> response <span class="token operator">=</span> <span class="token keyword">await</span> _chatClient<span class="token punctuation">.</span><span class="token function">GetResponseAsync</span><span class="token punctuation">(</span>_history<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">var</span> assistantMessage <span class="token operator">=</span> response<span class="token punctuation">.</span>Text <span class="token operator">?</span><span class="token operator">?</span> <span class="token keyword">string</span><span class="token punctuation">.</span>Empty<span class="token punctuation">;</span>

        _history<span class="token punctuation">.</span><span class="token function">AddMessages</span><span class="token punctuation">(</span>response<span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token keyword">return</span> assistantMessage<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token comment">/// &lt;summary&gt;</span>
    <span class="token comment">/// Sends a message with an image for vision analysis and returns the AI response.</span>
    <span class="token comment">/// &lt;/summary&gt;</span>
    <span class="token keyword">public</span> <span class="token keyword">async</span> Task<span class="token operator">&lt;</span><span class="token keyword">string</span><span class="token operator">&gt;</span> <span class="token function">SendMessageWithImageAsync</span><span class="token punctuation">(</span><span class="token keyword">string</span> userMessage<span class="token punctuation">,</span> <span class="token keyword">byte</span><span class="token punctuation">[</span><span class="token punctuation">]</span> imageBytes<span class="token punctuation">,</span> <span class="token keyword">string</span> mimeType<span class="token punctuation">)</span>
    <span class="token punctuation">{</span>        
        <span class="token keyword">var</span> contents <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">List</span><span class="token operator">&lt;</span>AIContent<span class="token operator">&gt;</span>
        <span class="token punctuation">{</span>
            <span class="token keyword">new</span> <span class="token class-name">TextContent</span><span class="token punctuation">(</span><span class="token keyword">string</span><span class="token punctuation">.</span><span class="token function">IsNullOrWhiteSpace</span><span class="token punctuation">(</span>userMessage<span class="token punctuation">)</span>
                <span class="token operator">?</span> <span class="token string">"Analyze this image from a nutritional perspective. How healthy is it?"</span>
                <span class="token punctuation">:</span> userMessage<span class="token punctuation">)</span><span class="token punctuation">,</span>
            <span class="token keyword">new</span> <span class="token class-name">DataContent</span><span class="token punctuation">(</span>imageBytes<span class="token punctuation">,</span> mimeType<span class="token punctuation">)</span>
        <span class="token punctuation">}</span><span class="token punctuation">;</span>

        <span class="token keyword">var</span> message <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ChatMessage</span><span class="token punctuation">(</span>ChatRole<span class="token punctuation">.</span>User<span class="token punctuation">,</span> contents<span class="token punctuation">)</span><span class="token punctuation">;</span>
        _history<span class="token punctuation">.</span><span class="token function">Add</span><span class="token punctuation">(</span>message<span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token keyword">var</span> response <span class="token operator">=</span> <span class="token keyword">await</span> _chatClient<span class="token punctuation">.</span><span class="token function">GetResponseAsync</span><span class="token punctuation">(</span>_history<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">var</span> assistantMessage <span class="token operator">=</span> response<span class="token punctuation">.</span>Text <span class="token operator">?</span><span class="token operator">?</span> <span class="token keyword">string</span><span class="token punctuation">.</span>Empty<span class="token punctuation">;</span>

        _history<span class="token punctuation">.</span><span class="token function">AddMessages</span><span class="token punctuation">(</span>response<span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token keyword">return</span> assistantMessage<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><p>In the code above, you can see that the methods <code>SendMessageAsync</code> are defined to send only text messages, and <code>SendMessageWithImageAsync</code> to send text along with images, which prepares us for the following sections.</p><p>To use it, we must update the viewmodel code to receive the instance of the new service:</p><pre class=" language-csharp"><code class="prism  language-csharp"><span class="token keyword">public</span> <span class="token keyword">partial</span> <span class="token keyword">class</span> <span class="token class-name">ChatViewModel</span> <span class="token punctuation">:</span> ObservableObject
<span class="token punctuation">{</span>
    <span class="token keyword">private</span> <span class="token keyword">readonly</span> ChatService _chatService<span class="token punctuation">;</span>
    <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>
    <span class="token keyword">public</span> <span class="token function">ChatViewModel</span><span class="token punctuation">(</span>ChatService chatService<span class="token punctuation">)</span>
    <span class="token punctuation">{</span>
        _chatService <span class="token operator">=</span> chatService<span class="token punctuation">;</span>
        <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>
    <span class="token punctuation">}</span>
    <span class="token punctuation">[</span>RelayCommand<span class="token punctuation">]</span>

    <span class="token keyword">private</span> <span class="token keyword">async</span> Task <span class="token function">SendMessage</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
    <span class="token punctuation">{</span>
        <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>
        <span class="token keyword">try</span>
        <span class="token punctuation">{</span>
            Items<span class="token punctuation">.</span><span class="token function">Add</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">TextMessage</span> <span class="token punctuation">{</span> Author <span class="token operator">=</span> Me<span class="token punctuation">,</span> Text <span class="token operator">=</span> messageText <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

            <span class="token keyword">var</span> response <span class="token operator">=</span> <span class="token keyword">await</span> _chatService<span class="token punctuation">.</span><span class="token function">SendMessageAsync</span><span class="token punctuation">(</span>messageText<span class="token punctuation">)</span><span class="token punctuation">;</span>

            Items<span class="token punctuation">.</span><span class="token function">Add</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">TextMessage</span> <span class="token punctuation">{</span> Author <span class="token operator">=</span> Bot<span class="token punctuation">,</span> Text <span class="token operator">=</span> response <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
        <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">Exception</span> ex<span class="token punctuation">)</span>
        <span class="token punctuation">{</span>
            Items<span class="token punctuation">.</span><span class="token function">Add</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">TextMessage</span>
            <span class="token punctuation">{</span>
                Author <span class="token operator">=</span> Bot<span class="token punctuation">,</span>
                Text <span class="token operator">=</span> $<span class="token string">"⚠️ Error processing your message: {ex.Message}"</span>
            <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><p>In the previous update, you can also see that I have changed the method <code>SendMessage</code>, adding an <code>try-catch</code> for any error that might occur, in addition to using the service to obtain a response from the LLM model. You should also add the new service to the dependency container in <code>MauiProgram.cs</code>:</p><pre class=" language-csharp"><code class="prism  language-csharp">builder<span class="token punctuation">.</span>Services<span class="token punctuation">.</span><span class="token generic-method function">AddSingleton<span class="token punctuation">&lt;</span>ChatService<span class="token punctuation">&gt;</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>With the previous changes, we will see a more realistic response created thanks to an LLM model:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-04/interacting-with-an-llm-model.png?sfvrsn=83fa7495_2" alt="Interacting with an llm model" /></p><h2 id="attaching-elements-to-the-conversation">Attaching Elements to the Conversation</h2><p>Next, we will see how we can attach images to the conversation, with the purpose of querying the AI model for information about them. The first thing we will do is create a model that represents the attachments:</p><pre class=" language-csharp"><code class="prism  language-csharp"><span class="token keyword">public</span> <span class="token keyword">partial</span> <span class="token keyword">class</span> <span class="token class-name">AttachedFileData</span> <span class="token punctuation">:</span> ObservableObject
<span class="token punctuation">{</span>
    <span class="token punctuation">[</span>ObservableProperty<span class="token punctuation">]</span>
    <span class="token keyword">private</span> <span class="token keyword">string</span> name <span class="token operator">=</span> <span class="token keyword">string</span><span class="token punctuation">.</span>Empty<span class="token punctuation">;</span>

    <span class="token punctuation">[</span>ObservableProperty<span class="token punctuation">]</span>
    <span class="token keyword">private</span> <span class="token keyword">long</span> size<span class="token punctuation">;</span>

    <span class="token punctuation">[</span>ObservableProperty<span class="token punctuation">]</span>
    <span class="token keyword">private</span> Func<span class="token operator">&lt;</span>Task<span class="token operator">&lt;</span>Stream<span class="token operator">&gt;</span><span class="token operator">&gt;</span> getStream <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=</span><span class="token operator">&gt;</span> Task<span class="token punctuation">.</span><span class="token generic-method function">FromResult<span class="token punctuation">&lt;</span>Stream<span class="token punctuation">&gt;</span></span><span class="token punctuation">(</span>Stream<span class="token punctuation">.</span>Null<span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token punctuation">[</span>ObservableProperty<span class="token punctuation">]</span>
    <span class="token keyword">private</span> <span class="token keyword">byte</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token operator">?</span> imageBytes<span class="token punctuation">;</span>

    <span class="token punctuation">[</span>ObservableProperty<span class="token punctuation">]</span>
    <span class="token keyword">private</span> <span class="token keyword">string</span><span class="token operator">?</span> mimeType<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><p>With the class that defines an attachment ready, we can create a list with a generic <code>AttachedFileData</code>, which will allow us to display them in a special section in the chat window.</p><pre class=" language-csharp"><code class="prism  language-csharp"><span class="token keyword">public</span> <span class="token keyword">partial</span> <span class="token keyword">class</span> <span class="token class-name">ChatViewModel</span> <span class="token punctuation">:</span> ObservableObject
<span class="token punctuation">{</span>
    <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>
    <span class="token punctuation">[</span>ObservableProperty<span class="token punctuation">]</span>
    <span class="token keyword">private</span> ObservableCollection<span class="token operator">&lt;</span>AttachedFileData<span class="token operator">&gt;</span> attachedFiles <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
    <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>
    <span class="token punctuation">[</span>RelayCommand<span class="token punctuation">]</span>
    <span class="token keyword">private</span> <span class="token keyword">async</span> Task <span class="token function">AttachFile</span><span class="token punctuation">(</span>IList<span class="token operator">&lt;</span>AttachedFileData<span class="token operator">&gt;</span><span class="token operator">?</span> filesToAttach<span class="token punctuation">)</span>
    <span class="token punctuation">{</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>filesToAttach <span class="token keyword">is</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token keyword">return</span><span class="token punctuation">;</span>
        
        <span class="token keyword">foreach</span> <span class="token punctuation">(</span><span class="token keyword">var</span> file <span class="token keyword">in</span> filesToAttach<span class="token punctuation">)</span>
        <span class="token punctuation">{</span>
            AttachedFiles<span class="token punctuation">.</span><span class="token function">Add</span><span class="token punctuation">(</span>file<span class="token punctuation">)</span><span class="token punctuation">;</span>                
        <span class="token punctuation">}</span>
        
        filesToAttach<span class="token punctuation">.</span><span class="token function">Clear</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
</code></pre><p>In the code above, we have also defined a method called <code>AttachFile</code>, which will allow us to attach the attachments to the list. In the graphic control, we need to perform two operations.</p><ol><li>Activate the button to attach files via <code>IsMoreButtonVisible</code></li><li>Bind <code>AttachFilesCommand</code> to the viewmodel method</li><li>Bind <code>AttachedFilesSource</code> to <code>AttachedFiles</code></li></ol><p>We can see this below:</p><pre class=" language-xml"><code class="prism  language-xml"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span><span class="token namespace">telerik:</span>RadChat</span> <span class="token attr-name">...</span>
    <span class="token attr-name">AttachFilesCommand</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>{Binding AttachFilesCommand}<span class="token punctuation">"</span></span>
    <span class="token attr-name">AttachedFilesSource</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>{Binding AttachedFiles}<span class="token punctuation">"</span></span>
    <span class="token attr-name">IsMoreButtonVisible</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>True<span class="token punctuation">"</span></span> <span class="token punctuation">/&gt;</span></span>
</code></pre><p>With the previous modifications, we will see a new button to attach attachments. Although we might think that the above is enough for the LLM to respond correctly to messages with images, if we try to query something with an attached image, we will get a response regarding the LLM model&rsquo;s unawareness of the attached file:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-04/attaching-files-without-favorable-llm-responses.png?sfvrsn=cabb71e0_2" alt="Attaching files without successful llm response" /></p><p>This happens because we have not added the attached file to the message list. To achieve this, several steps need to be followed:</p><ol><li>Detect when the collection of files changes:</li></ol><pre class=" language-csharp"><code class="prism  language-csharp"><span class="token keyword">public</span> <span class="token function">ChatViewModel</span><span class="token punctuation">(</span>ChatService chatService<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
   <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>    
    AttachedFiles<span class="token punctuation">.</span>CollectionChanged <span class="token operator">+</span><span class="token operator">=</span> OnAttachedFilesChanged<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><ol start="2"><li>Create the event handler for when the collection changes. This will allow adding the corresponding information according to the type of file:</li></ol><pre class=" language-csharp"><code class="prism  language-csharp"><span class="token keyword">private</span> <span class="token keyword">async</span> <span class="token keyword">void</span> <span class="token function">OnAttachedFilesChanged</span><span class="token punctuation">(</span><span class="token keyword">object</span><span class="token operator">?</span> sender<span class="token punctuation">,</span> NotifyCollectionChangedEventArgs e<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>e<span class="token punctuation">.</span>Action <span class="token operator">==</span> NotifyCollectionChangedAction<span class="token punctuation">.</span>Add <span class="token operator">&amp;&amp;</span> e<span class="token punctuation">.</span>NewItems <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span>
    <span class="token punctuation">{</span>
        <span class="token keyword">foreach</span> <span class="token punctuation">(</span>AttachedFileData file <span class="token keyword">in</span> e<span class="token punctuation">.</span>NewItems<span class="token punctuation">)</span>
        <span class="token punctuation">{</span>
            <span class="token keyword">await</span> <span class="token function">LoadFileData</span><span class="token punctuation">(</span>file<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>

<span class="token keyword">private</span> <span class="token keyword">async</span> Task <span class="token function">LoadFileData</span><span class="token punctuation">(</span>AttachedFileData file<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
    <span class="token keyword">try</span>
    <span class="token punctuation">{</span>
        <span class="token comment">// Load the image bytes from the stream</span>
        <span class="token keyword">using</span> <span class="token keyword">var</span> stream <span class="token operator">=</span> <span class="token keyword">await</span> file<span class="token punctuation">.</span><span class="token function">GetStream</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">using</span> <span class="token keyword">var</span> ms <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">MemoryStream</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">await</span> stream<span class="token punctuation">.</span><span class="token function">CopyToAsync</span><span class="token punctuation">(</span>ms<span class="token punctuation">)</span><span class="token punctuation">;</span>
        file<span class="token punctuation">.</span>ImageBytes <span class="token operator">=</span> ms<span class="token punctuation">.</span><span class="token function">ToArray</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token comment">// Try to determine MIME type from file extension</span>
        <span class="token keyword">var</span> extension <span class="token operator">=</span> Path<span class="token punctuation">.</span><span class="token function">GetExtension</span><span class="token punctuation">(</span>file<span class="token punctuation">.</span>Name<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">ToLowerInvariant</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        file<span class="token punctuation">.</span>MimeType <span class="token operator">=</span> extension <span class="token keyword">switch</span>
        <span class="token punctuation">{</span>
            <span class="token string">".jpg"</span> or <span class="token string">".jpeg"</span> <span class="token operator">=</span><span class="token operator">&gt;</span> <span class="token string">"image/jpeg"</span><span class="token punctuation">,</span>
            <span class="token string">".png"</span> <span class="token operator">=</span><span class="token operator">&gt;</span> <span class="token string">"image/png"</span><span class="token punctuation">,</span>
            <span class="token string">".gif"</span> <span class="token operator">=</span><span class="token operator">&gt;</span> <span class="token string">"image/gif"</span><span class="token punctuation">,</span>
            <span class="token string">".webp"</span> <span class="token operator">=</span><span class="token operator">&gt;</span> <span class="token string">"image/webp"</span><span class="token punctuation">,</span>
            _ <span class="token operator">=</span><span class="token operator">&gt;</span> <span class="token string">"image/jpeg"</span>
        <span class="token punctuation">}</span><span class="token punctuation">;</span>
                        
    <span class="token punctuation">}</span>
    <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">Exception</span> ex<span class="token punctuation">)</span>
    <span class="token punctuation">{</span>
        Items<span class="token punctuation">.</span><span class="token function">Add</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">TextMessage</span>
        <span class="token punctuation">{</span>
            Author <span class="token operator">=</span> Bot<span class="token punctuation">,</span>
            Text <span class="token operator">=</span> $<span class="token string">"⚠️ Error loading file {file.Name}: {ex.Message}"</span>
        <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><ol start="3"><li>In addition to the above, we need to modify the method for sending messages. Before doing that, to display the new messages in the history, we need to create a new class to handle the image information. In our case, it is as follows:</li></ol><pre class=" language-csharp"><code class="prism  language-csharp"><span class="token keyword">public</span> <span class="token keyword">partial</span> <span class="token keyword">class</span> <span class="token class-name">ChatMessageItem</span> <span class="token punctuation">:</span> ObservableObject
<span class="token punctuation">{</span>
    <span class="token punctuation">[</span>ObservableProperty<span class="token punctuation">]</span>
    <span class="token keyword">private</span> <span class="token keyword">object</span><span class="token operator">?</span> author<span class="token punctuation">;</span>

    <span class="token punctuation">[</span>ObservableProperty<span class="token punctuation">]</span>
    <span class="token keyword">private</span> <span class="token keyword">string</span> text <span class="token operator">=</span> <span class="token keyword">string</span><span class="token punctuation">.</span>Empty<span class="token punctuation">;</span>

    <span class="token punctuation">[</span>ObservableProperty<span class="token punctuation">]</span>
    <span class="token keyword">private</span> <span class="token keyword">byte</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token operator">?</span> imageData<span class="token punctuation">;</span>

    <span class="token punctuation">[</span>ObservableProperty<span class="token punctuation">]</span>
    <span class="token keyword">private</span> <span class="token keyword">string</span><span class="token operator">?</span> imageMimeType<span class="token punctuation">;</span>

    <span class="token punctuation">[</span>ObservableProperty<span class="token punctuation">]</span>
    <span class="token keyword">private</span> <span class="token keyword">string</span><span class="token operator">?</span> imageFileName<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><p>With this change, we can now update the method that sends the messages, adding the necessary code for a message to contain information about the image. Make sure to change all references from <code>TextMessage</code> to <code>ChatMessageItem</code>:</p><pre class=" language-csharp"><code class="prism  language-csharp"><span class="token punctuation">[</span>RelayCommand<span class="token punctuation">]</span>
<span class="token keyword">private</span> <span class="token keyword">async</span> Task <span class="token function">SendMessage</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
    <span class="token keyword">var</span> messageText <span class="token operator">=</span> Message<span class="token punctuation">;</span>
    <span class="token keyword">var</span> filesToSend <span class="token operator">=</span> AttachedFiles<span class="token punctuation">.</span><span class="token function">ToList</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    Message <span class="token operator">=</span> <span class="token keyword">string</span><span class="token punctuation">.</span>Empty<span class="token punctuation">;</span>

    <span class="token keyword">try</span>
    <span class="token punctuation">{</span>        
        <span class="token keyword">if</span> <span class="token punctuation">(</span>filesToSend<span class="token punctuation">.</span>Count <span class="token operator">&gt;</span> <span class="token number">0</span><span class="token punctuation">)</span>
        <span class="token punctuation">{</span>
            <span class="token keyword">var</span> file <span class="token operator">=</span> filesToSend<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
            
            Items<span class="token punctuation">.</span><span class="token function">Add</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">ChatMessageItem</span>
            <span class="token punctuation">{</span>
                Author <span class="token operator">=</span> Me<span class="token punctuation">,</span>
                Text <span class="token operator">=</span> <span class="token keyword">string</span><span class="token punctuation">.</span><span class="token function">IsNullOrWhiteSpace</span><span class="token punctuation">(</span>messageText<span class="token punctuation">)</span>
                    <span class="token operator">?</span> <span class="token string">" Analyzing this image..."</span>
                    <span class="token punctuation">:</span> messageText<span class="token punctuation">,</span>
                ImageData <span class="token operator">=</span> file<span class="token punctuation">.</span>ImageBytes<span class="token punctuation">,</span>
                ImageMimeType <span class="token operator">=</span> file<span class="token punctuation">.</span>MimeType<span class="token punctuation">,</span>
                ImageFileName <span class="token operator">=</span> file<span class="token punctuation">.</span>Name
            <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            
            <span class="token keyword">var</span> response <span class="token operator">=</span> <span class="token keyword">await</span> _chatService<span class="token punctuation">.</span><span class="token function">SendMessageWithImageAsync</span><span class="token punctuation">(</span>
                <span class="token keyword">string</span><span class="token punctuation">.</span><span class="token function">IsNullOrWhiteSpace</span><span class="token punctuation">(</span>messageText<span class="token punctuation">)</span>
                    <span class="token operator">?</span> <span class="token string">"Analyze this image from a nutritional perspective."</span>
                    <span class="token punctuation">:</span> messageText<span class="token punctuation">,</span>
                file<span class="token punctuation">.</span>ImageBytes<span class="token operator">!</span><span class="token punctuation">,</span>
                file<span class="token punctuation">.</span>MimeType <span class="token operator">?</span><span class="token operator">?</span> <span class="token string">"image/jpeg"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

            Items<span class="token punctuation">.</span><span class="token function">Add</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">ChatMessageItem</span> <span class="token punctuation">{</span> Author <span class="token operator">=</span> Bot<span class="token punctuation">,</span> Text <span class="token operator">=</span> response <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
        <span class="token keyword">else</span>
        <span class="token punctuation">{</span>
           <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
    <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>
<span class="token punctuation">}</span>
</code></pre><p>If you try to run the application at this moment, you will encounter an exception like the following:</p><pre class=" language-text"><code class="prism  language-text">`Unable to convert item of type MauiRadChatTests.ChatMessageItem to Telerik.Maui.Controls.Chat.ChatItem. You need to set the ItemConverter of the RadChat`.
</code></pre><p>The message is very descriptive about what we need to do: assign a value to <code>ItemConverter</code>. Let&rsquo;s do that next.</p><h2 id="displaying-attachments-in-the-conversation-history">Displaying Attachments in the Conversation History</h2><p>To understand this section, you should know that the control <code>RadChat</code> works internally with its own types, such as <code>ChatItem</code>, <code>ChatAttachedFile</code>, etc. However, in an MVVM architecture, the viewmodel should not know or depend on specific types in the UI. This is why the control mandates the use of some converters to perform a conversion between business objects and graphical control elements.</p><p><code>ItemConverter</code> is a property we need to assign through a class that inherits from <code>IChatItemConverter</code>. Its purpose is to convert a data model <code>ChatMessageItem</code> (or the type you have defined) into a Telerik UI type <code>ChatItem</code>, so that binding to the property <code>ItemsSource</code> can be done correctly.</p><p>The method <code>ConvertToChatItem</code> is used every time <code>RadChat</code> needs to render an element of the collection <code>ItemSource</code>, while <code>ConvertToDataItem</code> is used when RadChat wants to create a new item automatically, such as when the user presses Send. We will use null because we will handle everything from the viewmodel.</p><p>In the following example, you can see how we compare whether it is a text message or an image, and based on that we return either <code>ChatAttachmentsMessage</code> or <code>TextMessage</code>:</p><pre class=" language-csharp"><code class="prism  language-csharp"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">ChatItemConverter</span> <span class="token punctuation">:</span> IChatItemConverter
<span class="token punctuation">{</span>
    <span class="token keyword">public</span> ChatItem <span class="token function">ConvertToChatItem</span><span class="token punctuation">(</span><span class="token keyword">object</span> dataItem<span class="token punctuation">,</span> ChatItemConverterContext context<span class="token punctuation">)</span>
    <span class="token punctuation">{</span>
        <span class="token keyword">var</span> item <span class="token operator">=</span> <span class="token punctuation">(</span>ChatMessageItem<span class="token punctuation">)</span>dataItem<span class="token punctuation">;</span>

        <span class="token keyword">var</span> vm <span class="token operator">=</span> <span class="token punctuation">(</span>ChatViewModel<span class="token punctuation">)</span>context<span class="token punctuation">.</span>Chat<span class="token punctuation">.</span>BindingContext<span class="token punctuation">;</span>
        <span class="token keyword">var</span> author <span class="token operator">=</span> item<span class="token punctuation">.</span>Author <span class="token operator">==</span> vm<span class="token punctuation">.</span>Bot <span class="token operator">?</span> vm<span class="token punctuation">.</span>Bot <span class="token punctuation">:</span> context<span class="token punctuation">.</span>Chat<span class="token punctuation">.</span>Author<span class="token punctuation">;</span>
        
        <span class="token keyword">if</span> <span class="token punctuation">(</span>item<span class="token punctuation">.</span>ImageData <span class="token operator">!=</span> <span class="token keyword">null</span> <span class="token operator">&amp;&amp;</span> item<span class="token punctuation">.</span>ImageData<span class="token punctuation">.</span>Length <span class="token operator">&gt;</span> <span class="token number">0</span><span class="token punctuation">)</span>
        <span class="token punctuation">{</span>            
            <span class="token keyword">var</span> imageSource <span class="token operator">=</span> ImageSource<span class="token punctuation">.</span><span class="token function">FromStream</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=</span><span class="token operator">&gt;</span> <span class="token keyword">new</span> <span class="token class-name">MemoryStream</span><span class="token punctuation">(</span>item<span class="token punctuation">.</span>ImageData<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            
            <span class="token keyword">var</span> attachment <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ChatAttachment</span>
            <span class="token punctuation">{</span>
                FileName <span class="token operator">=</span> item<span class="token punctuation">.</span>ImageFileName <span class="token operator">?</span><span class="token operator">?</span> <span class="token string">"image.jpg"</span><span class="token punctuation">,</span>
                FileSize <span class="token operator">=</span> item<span class="token punctuation">.</span>ImageData<span class="token punctuation">.</span>Length<span class="token punctuation">,</span>
                Data <span class="token operator">=</span> imageSource<span class="token punctuation">,</span>
                GetFileStream <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=</span><span class="token operator">&gt;</span> Task<span class="token punctuation">.</span><span class="token generic-method function">FromResult<span class="token punctuation">&lt;</span>Stream<span class="token punctuation">&gt;</span></span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">MemoryStream</span><span class="token punctuation">(</span>item<span class="token punctuation">.</span>ImageData<span class="token punctuation">)</span><span class="token punctuation">)</span>
            <span class="token punctuation">}</span><span class="token punctuation">;</span>

            <span class="token keyword">var</span> attachmentMessage <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ChatAttachmentsMessage</span>
            <span class="token punctuation">{</span>
                Data <span class="token operator">=</span> dataItem<span class="token punctuation">,</span>
                Author <span class="token operator">=</span> author<span class="token punctuation">,</span>
                Text <span class="token operator">=</span> item<span class="token punctuation">.</span>Text<span class="token punctuation">,</span>
                Attachments <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">List</span><span class="token operator">&lt;</span>ChatAttachment<span class="token operator">&gt;</span> <span class="token punctuation">{</span> attachment <span class="token punctuation">}</span>
            <span class="token punctuation">}</span><span class="token punctuation">;</span>

            <span class="token keyword">return</span> attachmentMessage<span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
        
        <span class="token keyword">var</span> textMessage <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">TextMessage</span>
        <span class="token punctuation">{</span>
            Data <span class="token operator">=</span> dataItem<span class="token punctuation">,</span>
            Author <span class="token operator">=</span> author<span class="token punctuation">,</span>
            Text <span class="token operator">=</span> item<span class="token punctuation">.</span>Text
        <span class="token punctuation">}</span><span class="token punctuation">;</span>

        <span class="token keyword">return</span> textMessage<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token keyword">public</span> <span class="token keyword">object</span><span class="token operator">?</span> <span class="token function">ConvertToDataItem</span><span class="token punctuation">(</span><span class="token keyword">object</span> message<span class="token punctuation">,</span> ChatItemConverterContext context<span class="token punctuation">)</span>
    <span class="token punctuation">{</span>        
        <span class="token keyword">return</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><p>In the above code, you can see that we are very specific in loading the image through the use of <code>ImageSource.FromStream</code>, necessary to bind a <code>Image</code> control to an image. This converter needs to be bound to the property <code>ItemConverter</code> as we saw in the exception description:</p><pre class=" language-xml"><code class="prism  language-xml"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>ContentPage</span>
    <span class="token attr-name">...</span>
    <span class="token attr-name"><span class="token namespace">xmlns:</span>converters</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>clr-namespace:MauiRadChatTests<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>


    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>ContentPage.Resources</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span><span class="token namespace">converters:</span>ChatItemConverter</span> <span class="token attr-name"><span class="token namespace">x:</span>Key</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>ChatItemConverter<span class="token punctuation">"</span></span> <span class="token punctuation">/&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>ContentPage.Resources</span><span class="token punctuation">&gt;</span></span>

    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span><span class="token namespace">telerik:</span>RadChat</span> <span class="token attr-name">...</span>       
        <span class="token attr-name">ItemConverter</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>{StaticResource ChatItemConverter}<span class="token punctuation">"</span></span> <span class="token punctuation">/&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>ContentPage</span><span class="token punctuation">&gt;</span></span>

</code></pre><p>Now, if we tried to run the application again, we would receive the following error:</p><pre class=" language-text"><code class="prism  language-text">The AttachedFileConverter is null. This converter must be set, so that the RadChat can automatically convert IFileInfo instances to a business object that represents an attached file, and add them to the AttachedFilesSource collection. Alternatively, you can add attachments objects in your view model via the AttachFilesCommand or AttachFiles event.
</code></pre><p>The previous error tells us that we need to implement a second converter, necessary to convert a business object and add it to the collection of attachments. This means we need to implement a class that implements the <code>IChatAttachedFileConverter</code> interface, which will be responsible for translating our file model <code>AttachedFileData</code> to a <code>ChatAttachedFile</code> from Telerik.</p><p>In our case, the converter looks like this:</p><pre class=" language-csharp"><code class="prism  language-csharp"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">AttachedFileConverter</span> <span class="token punctuation">:</span> IChatAttachedFileConverter
<span class="token punctuation">{</span>
    <span class="token keyword">private</span> <span class="token keyword">static</span> AttachedFileConverter<span class="token operator">?</span> _instance<span class="token punctuation">;</span>
    <span class="token keyword">public</span> <span class="token keyword">static</span> AttachedFileConverter Instance <span class="token operator">=</span><span class="token operator">&gt;</span> _instance <span class="token operator">?</span><span class="token operator">?</span><span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">AttachedFileConverter</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token keyword">public</span> ChatAttachedFile <span class="token function">ConvertToChatAttachedFile</span><span class="token punctuation">(</span><span class="token keyword">object</span> dataItem<span class="token punctuation">,</span> ChatAttachedFileConverterContext context<span class="token punctuation">)</span>
    <span class="token punctuation">{</span>
        <span class="token keyword">var</span> data <span class="token operator">=</span> <span class="token punctuation">(</span>AttachedFileData<span class="token punctuation">)</span>dataItem<span class="token punctuation">;</span>
        <span class="token keyword">var</span> chatAttachedFile <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ChatAttachedFile</span>
        <span class="token punctuation">{</span>
            Data <span class="token operator">=</span> data<span class="token punctuation">,</span>
            FileName <span class="token operator">=</span> data<span class="token punctuation">.</span>Name<span class="token punctuation">,</span>
            FileSize <span class="token operator">=</span> data<span class="token punctuation">.</span>Size
        <span class="token punctuation">}</span><span class="token punctuation">;</span>
        <span class="token keyword">return</span> chatAttachedFile<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token keyword">public</span> <span class="token keyword">object</span> <span class="token function">ConvertToDataItem</span><span class="token punctuation">(</span>Telerik<span class="token punctuation">.</span>Maui<span class="token punctuation">.</span>Controls<span class="token punctuation">.</span>IFileInfo fileToAttach<span class="token punctuation">,</span> ChatAttachedFileConverterContext context<span class="token punctuation">)</span>
    <span class="token punctuation">{</span>
        <span class="token keyword">return</span> <span class="token function">CreateAttachedFileData</span><span class="token punctuation">(</span>fileToAttach<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token keyword">internal</span> <span class="token keyword">static</span> AttachedFileData <span class="token function">CreateAttachedFileData</span><span class="token punctuation">(</span>Telerik<span class="token punctuation">.</span>Maui<span class="token punctuation">.</span>Controls<span class="token punctuation">.</span>IFileInfo file<span class="token punctuation">)</span>
    <span class="token punctuation">{</span>
        <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">AttachedFileData</span>
        <span class="token punctuation">{</span>
            Name <span class="token operator">=</span> file<span class="token punctuation">.</span>FileName<span class="token punctuation">,</span>
            Size <span class="token operator">=</span> file<span class="token punctuation">.</span>FileSize<span class="token punctuation">,</span>
            GetStream <span class="token operator">=</span> file<span class="token punctuation">.</span>OpenReadAsync<span class="token punctuation">,</span>
        <span class="token punctuation">}</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><p>In the control, we must assign the instance of the class to <code>AttachedFileConverter</code>, preferably allowing a single instance through the use of <code>x:Static</code>:</p><pre class=" language-xml"><code class="prism  language-xml"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span><span class="token namespace">telerik:</span>RadChat</span> <span class="token attr-name">...</span>
    <span class="token attr-name">AttachedFileConverter</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>{x:Static converters:AttachedFileConverter.Instance}<span class="token punctuation">"</span></span><span class="token punctuation">/&gt;</span></span>
</code></pre><p>With the implementation of the previous changes, it is now possible to run the application, which returns information on a query of type image + text:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-04/radchat-control-in-action-receiving-text-and-images.gif?sfvrsn=7c266654_2" alt="RadChat control in action receiving text and images" /></p><p>With this, we have created a useful and real application based on a chat component, which we developed quickly and easily thanks to the controls from the Telerik suite for .NET MAUI.</p><h2 id="conclusion">Conclusion</h2><p>Throughout this post, we have explored the .NET MAUI Conversational UI (Chat) component, which allows integrating chat experiences into your applications. We have seen how to configure it, the parts that make it up, use cases, how to integrate LLM models for its usage, among other topics.</p><p>This is just the beginning, as in the official documentation you can find other relevant topics about customizing the control. See you in the next post.</p><h3 id="want-to-try-it-yourself">Want to Try It Yourself?</h3><p>The Telerik UI for .NET MAUI component library comes with a free 30-day trial. So go ahead!</p><p><a target="_blank" href="https://www.telerik.com/try/ui-for-maui" class="Btn">Try Now</a></p>]]></content>
  </entry>
  <entry>
    <id>urn:uuid:89e0e3fc-f615-4718-b937-f4de1ceba07a</id>
    <title type="text">Introducing the Progress Agentic RAG .NET SDK</title>
    <summary type="text">The .NET SDK for Progress Agentic RAG provides Retrieval-Augmented Generation (RAG) capabilities to .NET development with knowledge base management, AI-powered search and resource operations.</summary>
    <published>2026-04-23T15:33:21Z</published>
    <updated>2026-07-12T05:29:41Z</updated>
    <author>
      <name>Ed Charbeneau </name>
    </author>
    <link rel="alternate" href="https://www.telerik.com/blogs/introducing-progress-agentic-rag-net-sdk?utm_medium=feed&amp;utm_source=feedpress.me&amp;utm_campaign=Feed%3A+telerik-blogs-desktop"/>
    <content type="text"><![CDATA[<p><span class="featured">The .NET SDK for Progress Agentic RAG provides Retrieval-Augmented Generation (RAG) capabilities to .NET development with knowledge base management, AI-powered search and resource operations.</span></p><h2>What Is Progress Agentic RAG?</h2><p>Progress Agentic RAG is a RAG-as-a-Service that makes it dramatically easier to build AI systems grounded in real, trusted content. Rather than wiring together vector databases, embedding pipelines and retrieval logic yourself, Progress Agentic RAG provides an end-to-end platform for indexing, understanding and retrieving multimodal data.</p><p>It enables intelligent, agent-driven workflows that combine structured knowledge, contextual search and LLM orchestration into a unified experience.</p><p>With the introduction of the .NET SDK for Progress Agentic RAG, .NET developers can integrate this capability directly into their applications with just a few lines of code, leveraging modern .NET architecture patterns such as dependency injection, async workflows and strongly typed APIs.</p><h3>From Retrieval to Agentic Intelligence</h3><p>Progress Agentic RAG offers a fully capable AI Search Dashboard solution that allows you to get started in a matter of minutes. Simply connect or upload your data to a Knowledge Box, wait for NucliaDB&rsquo;s blazing-fast indexing engine to process it, and you&rsquo;re ready to explore grounded, contextual AI responses.</p><p>That immediate productivity is powerful. But modern enterprise development requires more than a dashboard.</p><p>Enterprise environments demand typed APIs, strong tooling and predictable behavior. Many RAG solutions are Python-first, leaving .NET teams stitching together REST calls manually and building custom abstractions just to regain the ergonomics they expect from their platform.</p><p>The new .NET SDK changes that.</p><p>It provides:</p><ul style="margin-top:0in;" type="disc"><li>Strongly typed APIs</li><li>Async-first patterns</li><li>Native .NET integration</li><li>Simplified knowledge base interaction</li></ul><p>With these capabilities, you can move beyond simple retrieval and begin composing intelligent, agent-driven experiences directly inside your application architecture. As powerful as it is convenient, the .NET SDK makes a great choice for new AI-enabled .NET applications.</p><h2>Getting Started</h2><p>Once a Knowledge Box has been established, you can begin interacting with Progress Agentic RAG through the .NET SDK.</p><p>The SDK is distributed as a <a target="_blank" href="https://www.nuget.org/packages/Progress.Nuclia">NuGet package</a> and covers the complete NucliaDB REST API. That includes strongly typed models, structured output helpers, dependency injection extensions and more than 200 APIs that expose the full surface area of the platform. See the <a target="_blank" href="https://docs.rag.progress.cloud/docs/develop/dotnet-sdk/">SDK documentation page </a>for a comprehensive list of service providers available.</p><h3>Install the NuGet Package</h3><pre><code class="language-csharp">dotnet add package Progress.Nuclia</code></pre><p>With the package installed, you can register the INucliaDb interface using modern dependency injection patterns. The SDK supports everything from basic configuration to advanced multi-tenant scenarios using keyed services.</p><h3>Register the Client</h3><pre><code class="language-csharp">using Progress.Nuclia.Extensions;

// Create configuration
var config = new NucliaDbConfig(
    ZoneId: "aws-us-east-2-1",
    KnowledgeBoxId: "your-knowledge-box-id",
    ApiKey: "your-api-key"
);

// Register with logging
builder.Services.AddNucliaDb(config).UseLogging();</code></pre><p>This approach aligns naturally with ASP.NET Core&rsquo;s architecture. You configure once, inject where needed, and keep your AI integration cleanly separated from business logic.</p><h2>Ask Questions with Agentic RAG</h2><p>With configuration complete, you can begin querying your Knowledge Box using AskAsync or AskStreamingAsync.</p><pre><code class="language-csharp">// Make request
AskRequest askRequest = new("What issues are driving the most customer escalations this quarter?");
var response = await client.Search.AskAsync(askRequest);

// Display answer
Console.WriteLine(response.Data.Answer);</code></pre><p>In just a few lines of code, you&rsquo;re executing a grounded, agent-driven query against indexed enterprise data.</p><p>The Ask functionality is only the beginning. With more than 200 APIs available in the SDK, you can ingest and manage resources, create conversational interactions and perform search, all using strongly typed, async-first C# patterns.</p><p>With structured configuration and native .NET integration in place, you can move from experimentation to production-ready AI systems with confidence.</p><h2>Explore the Examples: Blazor and .NET MAUI</h2><p>The fastest way to understand what Progress Agentic RAG can do in a real application is to see it running inside the frameworks you already use.</p><p>We&rsquo;ve published hands-on examples built with:</p><ul style="margin-top:0in;" type="disc"><li><a target="_blank" href="https://github.com/telerik/telerik-blazor-progress-rag-demo">Blazor &mdash; showcasing grounded AI experiences in modern web applications</a></li><li><a target="_blank" href="https://github.com/telerik/telerik-maui-progress-rag-demo">NET MAUI &mdash; demonstrating cross-platform, AI-powered mobile and desktop apps</a></li></ul><p>These samples go beyond simple API calls. They show how to:</p><ul style="margin-top:0in;" type="disc"><li>Register the SDK using dependency injection</li><li>Execute agentic queries with structured output</li><li>Stream responses into interactive UI components</li><li>Keep AI concerns cleanly separated from presentation logic</li></ul><p>If you&rsquo;re building internal tools, customer-facing dashboards or cross-platform AI assistants, these examples provide a production-oriented starting point.</p><p>Clone the samples, wire up your Knowledge Box and see how quickly you can integrate grounded, agent-driven intelligence into your existing .NET architecture.</p><h2>Additional Media</h2><p>Learn more about Progress Agentic RAG and the .NET SDK from video tutorials and podcasts:</p><ul><li>The Progress Agentic RAG .NET SDK was featured on episode 1997 of .NET Rocks:&nbsp;<a target="_blank" href="https://www.dotnetrocks.com/details/1997">.NET Rocks! Agentic RAG with Ed Charbeneau</a></li><li>Getting started videos by Jeff (Csharp) Fritz</li></ul><div sf-youtube-url="https://youtu.be/ilJpB9Y7waA?si=nIm6nTg2HLc0Bvkf"><iframe frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" title="Build Your First AI Search in .NET with Progress Agentic RAG" width="640" height="360" src="https://www.youtube.com/embed/ilJpB9Y7waA?si=nIm6nTg2HLc0Bvkf&amp;enablejsapi=1&amp;origin=https%3A%2F%2Fwww.telerik.com&amp;widgetid=3&amp;forigin=https%3A%2F%2Fwww.telerik.com%2FSitefinity%2Fadminapp%2Fcontent%2Fblogs%2Fc2c9ae54-03a9-4243-86cc-9c50fcc0a754%2Fblogposts%2F89e0e3fc-f615-4718-b937-f4de1ceba07a%2Fedit%3Fsf_provider%3DOpenAccessDataProvider%26sf_culture%3Den&amp;aoriginsup=1&amp;vf=1"></iframe></div><div sf-youtube-url="https://youtu.be/qE6zy75btLo?si=ZferEV00m-sRamDA"><iframe frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" title="Build Your First AI Search in .NET with Progress Agentic RAG Part 2" width="640" height="360" src="https://www.youtube.com/embed/qE6zy75btLo?si=ZferEV00m-sRamDA&amp;enablejsapi=1&amp;origin=https%3A%2F%2Fwww.telerik.com&amp;widgetid=2&amp;forigin=https%3A%2F%2Fwww.telerik.com%2FSitefinity%2Fadminapp%2Fcontent%2Fblogs%2Fc2c9ae54-03a9-4243-86cc-9c50fcc0a754%2Fblogposts%2F89e0e3fc-f615-4718-b937-f4de1ceba07a%2Fedit%3Fsf_provider%3DOpenAccessDataProvider%26sf_culture%3Den&amp;aoriginsup=1&amp;vf=1"></iframe></div>]]></content>
  </entry>
</feed>
