<?xml version="1.0" encoding="UTF-8" standalone="no"?><rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" version="2.0">

<channel>
	<title>Nick Randolph's .NET Travels</title>
	<atom:link href="https://nicksnettravels.builttoroam.com/feed/" rel="self" type="application/rss+xml"/>
	<link>https://nicksnettravels.builttoroam.com/</link>
	<description>Continually looking for the yellow brick road so I can catch me a wizard....Join me as I explore the world of cool devices, neat technology and uber geeks. I spend most of my time talking about Microsoft related technologies such as the .NET Framework, SQL Server, Windows Mobile, SQL Server Compact Edition but I also discuss the current IT industry, the movers and shakers, and trends I observe from time to time.</description>
	<lastBuildDate>Sun, 01 Mar 2026 17:08:34 +0000</lastBuildDate>
	<language>en-AU</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.4</generator>

<image>
	<url>/wp-content/uploads/2020/04/cropped-BTR-ICON-PRIMARY-512-1-32x32.png</url>
	<title>Nick's .NET Travels</title>
	<link>https://nicksnettravels.builttoroam.com/</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>Ralph built a Cross-Platform app using Uno Platform whilst I slept.</title>
		<link>https://nicksnettravels.builttoroam.com/ralph-built-a-cross-platform-app/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=ralph-built-a-cross-platform-app</link>
					<comments>https://nicksnettravels.builttoroam.com/ralph-built-a-cross-platform-app/#respond</comments>
		
		<dc:creator><![CDATA[Nick]]></dc:creator>
		<pubDate>Sun, 01 Mar 2026 17:08:32 +0000</pubDate>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[AI]]></category>
		<category><![CDATA[Claude]]></category>
		<category><![CDATA[Ralph]]></category>
		<category><![CDATA[Uno Platform]]></category>
		<guid isPermaLink="false">https://nicksnettravels.builttoroam.com/?p=3601</guid>

					<description><![CDATA[<p>There&#8217;s been quite a bit of hype around the use of AI for vibe coding applications. Add in the use of a Ralph loop and we&#8217;re getting close to being able to automatically generate entire applications. But how much of this is hype and how much is reality. In this post I&#8217;ll walk through using ... <a title="Ralph built a Cross-Platform app using Uno Platform whilst I slept." class="read-more" href="https://nicksnettravels.builttoroam.com/ralph-built-a-cross-platform-app/" aria-label="Read more about Ralph built a Cross-Platform app using Uno Platform whilst I slept.">Read more</a></p>
<p>The post <a href="https://nicksnettravels.builttoroam.com/ralph-built-a-cross-platform-app/">Ralph built a Cross-Platform app using Uno Platform whilst I slept.</a> appeared first on <a href="https://nicksnettravels.builttoroam.com">Nick&#039;s .NET Travels</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>There&#8217;s been quite a bit of hype around the use of AI for vibe coding applications. Add in the use of a Ralph loop and we&#8217;re getting close to being able to automatically generate entire applications. But how much of this is hype and how much is reality. In this post I&#8217;ll walk through using a simple Ralph loop with the latest Uno Platform AI tooling to build an application from just a simple specification. I let it run overnight whilst I slept, so we&#8217;ll see what it produced and where we should go next.</p>



<p>So, here&#8217;s a quick overview of my setup:</p>



<ul class="wp-block-list">
<li>Running on Windows with VSCode</li>



<li>Using a devcontainer setup under WSL to make sure Claude can&#8217;t go rogue on my PC</li>



<li>I created the initial Uno Platform application using &#8220;<code>dotnet new unoapp -preset recommended</code>&#8221; to create my application using the latest Uno Platform guidance (Material, MVUX, Navigation etc)</li>



<li>I&#8217;m using Claude Code</li>



<li>I&#8217;ve added both Uno Platform <a href="https://platform.uno/docs/articles/get-started-ai-claude.html?tabs=windows#setting-up-uno-platform-mcps">MCP servers</a></li>



<li>Validated that <strong>both</strong> Uno Platform MCPs are connected <strong>and</strong> have tools loaded</li>
</ul>



<p><strong>IMPORTANT: </strong>In order to get a good outcome it&#8217;s very important that the Uno Platform App MCP is connected and is reporting tools (there should be 11 at the time of writing). If the tools don&#8217;t load after 30 seconds (default timeout), it&#8217;s likely to be a result of one or two reasons:</p>



<ul class="wp-block-list">
<li>Not Authenticated with Uno Platform account. If you&#8217;re in a container/WSL you can launch the Studio app by running (substitute {version} with the version that you have. If none, run dotnet restore on your Uno Platform app):<br><code>dotnet ~/.nuget/packages/uno.settings.devserver/{version}/tools/manager/Uno.Settings.dll</code></li>



<li>Not able to resolve Solution or Project that references Uno Platform. Change to the directory that has the Solution (.sln) file before running Claude.</li>
</ul>



<p>Whilst I&#8217;m using Claude in this example, the above setup, including the instructions for validating MCPs, applies to other AI agent CLIs (eg Codex).</p>



<h2 class="wp-block-heading">Application Specification</h2>



<p>Before I got started building the application I launched an interactive session with Claude and in Plan mode proceeded to describe the set of features for my application. I started with a brief description of the app:</p>



<p><strong>&#8220;Help me determine the specifications for a financial tracking and planning application&#8221;</strong></p>



<p>Through structured Q&amp;A, , the following was established:</p>



<ul class="wp-block-list">
<li><strong>Audience:</strong>&nbsp;Personal/household use</li>



<li><strong>Platforms:</strong>&nbsp;Web (WASM), Desktop (Win/Mac/Linux), Mobile (iOS/Android)</li>



<li><strong>Tech stack:</strong>&nbsp;Uno Platform (.NET/C#), SQLite, MVUX, Uno Material, LiveCharts2</li>



<li><strong>Data entry:</strong>&nbsp;Manual only (no bank sync/import)</li>



<li><strong>Storage:</strong>&nbsp;Local only (no cloud)</li>



<li><strong>Auth:</strong>&nbsp;Local account — username + BCrypt password + recovery phrase + optional PIN</li>
</ul>



<p><strong>8 features were defined (F1–F8):</strong></p>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>#</th><th>Feature</th></tr></thead><tbody><tr><td>F1</td><td>Account Management — multiple account types, offset accounts, reconciliation</td></tr><tr><td>F2</td><td>Transaction Tracking — Manual vs Planned, recurring rules, interest charge computation</td></tr><tr><td>F3</td><td>Planning (Scenario Modelling) — branching scenarios, projection engine, comparison view (replaced the original &#8220;Budgeting&#8221; feature at your request)</td></tr><tr><td>F4</td><td>Net Worth Tracking — share holdings, properties, loan-secured property equity/LTV</td></tr><tr><td>F5</td><td>Financial Goal Planning — savings targets, debt payoff, on-track status</td></tr><tr><td>F6</td><td>Reporting &amp; Visualization — 5 chart types, CSV export</td></tr><tr><td>F7</td><td>Authentication &amp; Security — registration, login, optional PIN, forgot-password flow</td></tr><tr><td>F8</td><td>Settings &amp; Data Management — categories, recurring rules, localisation, data export</td></tr></tbody></table></figure>



<p>All 8 features were broken down into 42 issues on GitHub with full acceptance criteria and linked to their parent epics.</p>



<h2 class="wp-block-heading">Basic Ralph</h2>



<p>Sometimes when I hear Ralph discussed it ends up being overly complex, for example requiring the use of plugins. This is one of those topics that you can make as complex as you want. For me, it&#8217;s just a basic execution loop that works through a predefined list of tasks until completed.</p>



<p>With this in mind, the first thing to do was to create an ordered list of my GitHub issues for my Ralph loop to work through. Again, I used Claude for this with the following prompt:</p>



<p><code>Retrieve all open github issues. Sort them in the order that they should be completed (ignore epics) and write them to a file openissues.md</code></p>



<p>This created an openissues.md file with issues listed as follows:</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2026/03/image.png"><img fetchpriority="high" decoding="async" width="300" height="216" src="https://wordpressblogimages.builttoroam.com/blogimages/2026/03/image-300x216.png" alt="" class="wp-image-3608" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2026/03/image-300x216.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2026/03/image-768x552.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2026/03/image.png 924w" sizes="(max-width: 300px) 100vw, 300px" /></a></figure>



<p>Now onto the Ralph loop itself. This is just a bash script (Credit to Dan Vega in his video <a href="https://www.youtube.com/watch?v=CV97l0GkPHo">The Ralph Loop Explained: Automate AI Coding Tasks in Java</a> where I borrowed the structure of this script from).</p>



<pre class="wp-block-code"><code>#!/bin/bash

SLEEP_BETWEEN=10
LOG_DIR="logs"

mkdir -p "$LOG_DIR"

for ((i=1; i&lt;=$1; i++)); do
  echo ""
  echo "****************************************"
  echo "Iteration $i of $1"
  echo "****************************************"

  outfile="$LOG_DIR/iteration_${i}.log"

  claude --dangerously-skip-permissions -p "@openissues.md @progress.txt \
0. Make sure uno and unoapp MCP are connected and that unoapp MCP has 11 tools available. After 30s if the unoapp MCP tools are not available, do not update GitHub issue and exit immediately. \
1. Read progress.txt to see what has been completed. \
2. Get the next issue from openissues.md. \
3. If there are no issues, output &lt;promise>COMPLETE&lt;/promise> and exit. \
4. Complete the issue as required. \
5. If the issue requires code changes, make the necessary changes and commit them to GitHub. \
6. Ensure there are adequates tests for the changes you made. \
7. If the issue requires documentation changes, update the relevant documentation. \
8. Run the application and verify that the issue is resolved. Capture screenshots or logs as evidence of the fix. \
9. Update the GitHub issue with a comment describing how you resolved the issue, including any screenshots or logs. Close the GitHub issue as done. \
10. Append your progress to progress.txt with what you completed. \
11. If ALL tasks in openissues.md are complete, output &lt;promise>COMPLETE&lt;/promise>. \
ONLY WORK ON ONE TASK PER ITERATION." > "$outfile" 2>&amp;1 || {
    echo "Warning: Iteration $i failed (exit code $?). See $outfile for details. Continuing..."
    continue
  }

  cat "$outfile"

  if grep -q '&lt;promise>COMPLETE&lt;/promise>' "$outfile"; then
    echo ""
    echo "openissues.md complete after $i iterations!"
    exit 0
  fi

  if (( i &lt; $1 )); then
    sleep "$SLEEP_BETWEEN"
  fi
done

echo ""
echo "Reached $1 iterations. openissues.md may not be complete."
</code></pre>



<p>To execute you can just call</p>



<p><code>bash ralph.sh 100</code></p>



<p>This will run the loop 100 times, which in my case was enough to complete all 42, non-epic, GitHub issues. </p>



<p>And now you wait&#8230;.. and wait&#8230;. and once you&#8217;ve verified that the first iteration doesn&#8217;t blow up and something is happening (you should see files being created and logs written)&#8230;. you can leave Ralph to it and come back in a few hours. I actually just went to bed and checked on the progress when I work up.</p>



<h2 class="wp-block-heading">Ralph is Not a Designer</h2>



<p>Actually, this should be Claude isn&#8217;t a designer, or at least is no substitute for a good UX designer. After working all night my Ralph loop and Claude had concocted what I&#8217;m sure is a fully functional app that meets my specifications. In fact, the over 1200 tests it created hopefully verifies that at least the functionality works. However, as the following screenshot of the MainPage will attest to, there was no thought towards building a usable interface.</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2026/03/image-69a46ebf43cb9.png"><img decoding="async" width="229" height="300" src="https://wordpressblogimages.builttoroam.com/blogimages/2026/03/image-69a46ebf43cb9-229x300.png" alt="" class="wp-image-3609" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2026/03/image-69a46ebf43cb9-229x300.png 229w, https://wordpressblogimages.builttoroam.com/blogimages/2026/03/image-69a46ebf43cb9-780x1024.png 780w, https://wordpressblogimages.builttoroam.com/blogimages/2026/03/image-69a46ebf43cb9-768x1008.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2026/03/image-69a46ebf43cb9.png 819w" sizes="(max-width: 229px) 100vw, 229px" /></a></figure>



<p>There&#8217;s no doubt that Claude, Codex etc are all super powerful tools but if you don&#8217;t provide them with enough input, you&#8217;re at their mercy. In this case I&#8217;d come up with a detailed specification but hadn&#8217;t spent time working out what the UX should be. I ended up with a basic, input based, UX where there were CRUD style interfaces for each of the elements of the data model.</p>



<h2 class="wp-block-heading">Summary</h2>



<p>There are two clear takeaways from this. Firstly, building apps, even cross platform apps, has been dramatically condensed &#8211; we&#8217;re talking weeks, perhaps even months, of development down to a mere few hours. Secondly, that more time spent coming up with specifications, application flow, designs, will significantly improve the quality of the outcome.</p>



<p>From here I clearly need to spend more time with Claude coming up with a better UX for the application. In the past, this would have required reworking the application to adapt it to the new UX. However, since it only took a few hours to build the first version, and I don&#8217;t need to worry or care about users having to upgrade to a new version, why not completely rebuild the application from scratch!!! I&#8217;ll leave you with this thought &#8211; whether it&#8217;s better to adapt or rebuild, now that development cost isn&#8217;t what it used to be.</p>
<p>The post <a href="https://nicksnettravels.builttoroam.com/ralph-built-a-cross-platform-app/">Ralph built a Cross-Platform app using Uno Platform whilst I slept.</a> appeared first on <a href="https://nicksnettravels.builttoroam.com">Nick&#039;s .NET Travels</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://nicksnettravels.builttoroam.com/ralph-built-a-cross-platform-app/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>I used to be a Windows Developer….. and I still am (sort of)</title>
		<link>https://nicksnettravels.builttoroam.com/i-used-to-be-a-windows-developer/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=i-used-to-be-a-windows-developer</link>
					<comments>https://nicksnettravels.builttoroam.com/i-used-to-be-a-windows-developer/#respond</comments>
		
		<dc:creator><![CDATA[Nick]]></dc:creator>
		<pubDate>Sat, 21 Feb 2026 18:05:24 +0000</pubDate>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[AI]]></category>
		<category><![CDATA[Uno Platform]]></category>
		<category><![CDATA[Windows]]></category>
		<category><![CDATA[XAML]]></category>
		<guid isPermaLink="false">https://nicksnettravels.builttoroam.com/?p=3603</guid>

					<description><![CDATA[<p>For most of my career, I’ve been a proud Windows developer. I build Windows apps. I run Windows as my primary dev machine. It’s been home. But recently? That’s been challenged — not by another OS, but by AI. Developer workflow is changing fast. Agents, containers, automation — they’re reshaping how we build software. So ... <a title="I used to be a Windows Developer&#8230;.. and I still am (sort of)" class="read-more" href="https://nicksnettravels.builttoroam.com/i-used-to-be-a-windows-developer/" aria-label="Read more about I used to be a Windows Developer&#8230;.. and I still am (sort of)">Read more</a></p>
<p>The post <a href="https://nicksnettravels.builttoroam.com/i-used-to-be-a-windows-developer/">I used to be a Windows Developer&#8230;.. and I still am (sort of)</a> appeared first on <a href="https://nicksnettravels.builttoroam.com">Nick&#039;s .NET Travels</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>For most of my career, I’ve been a proud Windows developer.</p>



<p>I build Windows apps. I run Windows as my primary dev machine. It’s been home.</p>



<p>But recently? That’s been challenged — not by another OS, but by AI.</p>



<p>Developer workflow is changing fast. Agents, containers, automation — they’re reshaping how we build software. So let’s rewind a little, talk about <strong>why Windows</strong>, and then look at what’s shifting under our feet.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">Why Windows?</h2>



<p>There are really two answers.</p>



<h3 class="wp-block-heading">1&#xfe0f;&#x20e3; The Tools — Visual Studio</h3>



<p>For years, <strong>Visual Studio</strong> was untouchable.</p>



<p>While others were sprinkling <code>Console.WriteLine</code> or scanning logs, Windows developers had:</p>



<ul class="wp-block-list">
<li>Step-through debugging</li>



<li>Deep variable inspection (even the gnarly ones)</li>



<li>Conditional breakpoints</li>



<li>Edit-and-Continue (Hot Reload)</li>



<li>Integrated build, test, and profiling</li>
</ul>



<p>It wasn’t just an editor — it was a command center.</p>



<p>And honestly? It still is when I need serious debugging power.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading">2&#xfe0f;&#x20e3; The Stack — XAML and Beyond</h3>



<p>The second reason: the Windows UI stack.</p>



<p>Since the early days of WPF and Silverlight, I’ve loved XAML. Declarative UI. Clean separation. Powerful binding.</p>



<p>As the platform evolved — WPF → Win8 → UWP → WinUI — XAML stayed central.</p>



<p>Now with the <strong>Uno Platform</strong>, that same XAML lets me target:</p>



<ul class="wp-block-list">
<li>Windows (WinUI &amp; Desktop)</li>



<li>macOS</li>



<li>Linux</li>



<li>Android</li>



<li>iOS</li>



<li>Web (WASM)</li>
</ul>



<p>One UI definition. Everywhere.</p>



<p>Pair that with MVVM and you get a clean, structured architecture. Add MVUX from Uno and you get a reactive, modern state management model.</p>



<p>It’s simple. Powerful. Productive.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">So What Changed?</h2>



<p>For the first time in my career…</p>



<p>I’m not building for WinUI first.</p>



<p>That used to be my workflow:</p>



<ol class="wp-block-list">
<li>Build and debug on WinUI</li>



<li>Then test on other Uno targets</li>
</ol>



<p>But when Uno recommended the Skia backend, things shifted.</p>



<p>Now I default to the Desktop target (Windows, macOS, Linux). Why?</p>



<ul class="wp-block-list">
<li>Faster build and launch</li>



<li>Clearer XAML errors</li>



<li>Better day-to-day debugging flow</li>
</ul>



<p>Ironically, building for Windows became less about WinUI itself.</p>



<p>And that shift matters — because an even bigger shift was coming.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">Enter AI Agents + App MCP</h2>



<p>This is where things really changed.</p>



<p>With AI agents — whether it’s Claude, Copilot, or Codex — and the Uno Platform App MCP:</p>



<p>An agent can:</p>



<ul class="wp-block-list">
<li>Build the app</li>



<li>Run it</li>



<li>Take screenshots</li>



<li>Verify changes</li>



<li>Repeat across Desktop, Web, and Mobile</li>
</ul>



<p>I can now assign an entire issue to an agent.</p>



<p>It will:</p>



<ol class="wp-block-list">
<li>Plan the solution</li>



<li>Implement it</li>



<li>Run the app</li>



<li>Validate the outcome</li>
</ol>



<p>Across multiple platforms.</p>



<p>That’s not autocomplete.</p>



<p>That’s delegation.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">Containers, YOLO Mode, and Dev Isolation</h2>



<p>The next evolution?</p>



<p>Running agents in YOLO mode inside a dev container.</p>



<p>I’m using:</p>



<ul class="wp-block-list">
<li>A Linux container</li>



<li>Running on WSL</li>



<li>Connected via VS Code</li>
</ul>



<p>The dev container stays locked down:</p>



<ul class="wp-block-list">
<li>Limited GitHub access</li>



<li>Controlled environment</li>



<li>Isolation from the host</li>
</ul>



<p>I can still launch desktop and web targets for debugging — but the agent operates in a contained sandbox.</p>



<p>It’s structured chaos.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">Where That Leaves Me</h2>



<p>So here I am.</p>



<p>Still using Windows.<br>Still building for Windows.<br>But not the way I used to.</p>



<p>Visual Studio is now my “serious debugging” tool.</p>



<p>Day-to-day development?<br>Often handled by an AI agent — inside a container — through whatever console I happen to be using.</p>



<p>That’s a massive shift.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">The Bigger Picture</h2>



<p>AI isn’t just speeding up development.</p>



<p>It’s redefining the workflow.</p>



<p>Agents. Sub-agents. Teams of agents.<br>Parallelizing feature work.<br>Burning down backlogs.<br>Testing across platforms automatically.</p>



<p>The tooling and models are evolving monthly.</p>



<p>Six months from now? The workflow may look completely different again.</p>



<p>One thing is clear:</p>



<p>Being a developer today isn’t just about writing code.</p>



<p>It’s about orchestrating intelligence.</p>
<p>The post <a href="https://nicksnettravels.builttoroam.com/i-used-to-be-a-windows-developer/">I used to be a Windows Developer&#8230;.. and I still am (sort of)</a> appeared first on <a href="https://nicksnettravels.builttoroam.com">Nick&#039;s .NET Travels</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://nicksnettravels.builttoroam.com/i-used-to-be-a-windows-developer/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Use AI to Build Cross Platform Applications with Uno Platform, VS Code, Agents and MCPs</title>
		<link>https://nicksnettravels.builttoroam.com/uno-mcps/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=uno-mcps</link>
					<comments>https://nicksnettravels.builttoroam.com/uno-mcps/#respond</comments>
		
		<dc:creator><![CDATA[Nick]]></dc:creator>
		<pubDate>Tue, 13 Jan 2026 13:14:53 +0000</pubDate>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[AI]]></category>
		<category><![CDATA[Cross-Platform]]></category>
		<category><![CDATA[MCP]]></category>
		<category><![CDATA[Uno Platform]]></category>
		<guid isPermaLink="false">https://nicksnettravels.builttoroam.com/?p=3578</guid>

					<description><![CDATA[<p>The world of software development has been inverted by the introduction of AI. This started off as an assistive role but quite rapidly AI is taking on more and more autonomy. In fact, the recent hype around Ralph (Ralph Wiggum as a &#8220;software engineer&#8221;) is evidence enough that whole sections of work can now be ... <a title="Use AI to Build Cross Platform Applications with Uno Platform, VS Code, Agents and MCPs" class="read-more" href="https://nicksnettravels.builttoroam.com/uno-mcps/" aria-label="Read more about Use AI to Build Cross Platform Applications with Uno Platform, VS Code, Agents and MCPs">Read more</a></p>
<p>The post <a href="https://nicksnettravels.builttoroam.com/uno-mcps/">Use AI to Build Cross Platform Applications with Uno Platform, VS Code, Agents and MCPs</a> appeared first on <a href="https://nicksnettravels.builttoroam.com">Nick&#039;s .NET Travels</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>The world of software development has been inverted by the introduction of AI. This started off as an assistive role but quite rapidly AI is taking on more and more autonomy. In fact, the recent hype around <a href="https://github.com/snarktank/ralph">Ralph </a>(<a href="https://ghuntley.com/ralph/">Ralph Wiggum as a &#8220;software engineer&#8221;</a>) is evidence enough that whole sections of work can now be fielded off to agents, that will simply report back when they&#8217;re done. In this post we&#8217;re not going to go that far but we are going to look at how you can use AI to rapidly build out your next cross platform application using the Uno Platform.</p>



<p>Today you can pick any one of the leading AI models and ask it to create you a cross-platform application using the Uno Platform. This will have varying levels of success depending on whether the model is able to find the dotnet new templates (see <a href="https://www.nuget.org/packages/Uno.Templates">uno.templates</a>) and whether it&#8217;s able to disambiguate the Uno Platform documentation from the other XAML related documentation (WPF, WinUI, Maui etc). </p>



<p>The secrete to being successful in the use of AI to build Uno Platform applications is through the use of the two MCPs that are packages with the IDE extensions. To get started, make sure you install the appropriate extension for your IDE (see <a href="https://platform.uno/docs/articles/get-started.html">Getting Started</a>). </p>



<p>As I mentioned the MCPs are packaged with the IDE extensions, which means they&#8217;re only enabled once the extension is loaded. The extensions are loaded when an Uno Platform app is detected, which means you first need to create an Uno Platform application. If you&#8217;re already familiar with this you can jump the next section that goes through the flow of creating an Uno Platform application (in VS Code in this instance)</p>



<div data-wp-context="{ &quot;autoclose&quot;: false, &quot;accordionItems&quot;: [] }" data-wp-interactive="core/accordion" role="group" class="wp-block-accordion is-layout-flow wp-block-accordion-is-layout-flow">
<div data-wp-class--is-open="state.isOpen" data-wp-context="{ &quot;id&quot;: &quot;accordion-item-1&quot;, &quot;openByDefault&quot;: false }" data-wp-init="callbacks.initAccordionItems" data-wp-on-window--hashchange="callbacks.hashChange" class="wp-block-accordion-item is-layout-flow wp-block-accordion-item-is-layout-flow">
<h3 class="wp-block-accordion-heading"><button aria-expanded="false" aria-controls="accordion-item-1-panel" data-wp-bind--aria-expanded="state.isOpen" data-wp-on--click="actions.toggle" data-wp-on--keydown="actions.handleKeyDown" id="accordion-item-1" class="wp-block-accordion-heading__toggle"><span class="wp-block-accordion-heading__toggle-title">Creating an Uno Platform Application</span><span class="wp-block-accordion-heading__toggle-icon" aria-hidden="true">+</span></button></h3>



<div inert aria-labelledby="accordion-item-1" data-wp-bind--inert="!state.isOpen" id="accordion-item-1-panel" role="region" class="wp-block-accordion-panel is-layout-flow wp-block-accordion-panel-is-layout-flow">
<p>Start by going to <a href="https://new.platform.uno">https://new.platform.uno</a> and enter an application name.</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2026/01/image.png"><img decoding="async" width="300" height="227" src="https://wordpressblogimages.builttoroam.com/blogimages/2026/01/image-300x227.png" alt="" class="wp-image-3580" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2026/01/image-300x227.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2026/01/image-1024x774.png 1024w, https://wordpressblogimages.builttoroam.com/blogimages/2026/01/image-768x581.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2026/01/image.png 1514w" sizes="(max-width: 300px) 100vw, 300px" /></a></figure>



<p>Select the various options you want to include in your application &#8211; in this case I&#8217;m just going to go with a Basic app to keep things simple since I want AI to create a simple one page application.</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2026/01/image-6963a9872db0d.png"><img loading="lazy" decoding="async" width="300" height="227" src="https://wordpressblogimages.builttoroam.com/blogimages/2026/01/image-6963a9872db0d-300x227.png" alt="" class="wp-image-3581" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2026/01/image-6963a9872db0d-300x227.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2026/01/image-6963a9872db0d-1024x774.png 1024w, https://wordpressblogimages.builttoroam.com/blogimages/2026/01/image-6963a9872db0d-768x581.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2026/01/image-6963a9872db0d.png 1514w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>Once you&#8217;re done selecting the options, click the Create button and copy the dotnet new command.</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2026/01/image-6963aad6efd69.png"><img loading="lazy" decoding="async" width="300" height="227" src="https://wordpressblogimages.builttoroam.com/blogimages/2026/01/image-6963aad6efd69-300x227.png" alt="" class="wp-image-3582" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2026/01/image-6963aad6efd69-300x227.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2026/01/image-6963aad6efd69-1024x774.png 1024w, https://wordpressblogimages.builttoroam.com/blogimages/2026/01/image-6963aad6efd69-768x581.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2026/01/image-6963aad6efd69.png 1514w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>Drop the copied dotnet new command into a terminal window and let dotnet new create the application from the Uno Platform templates.</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2026/01/image-6963ac65a3d38.png"><img loading="lazy" decoding="async" width="300" height="132" src="https://wordpressblogimages.builttoroam.com/blogimages/2026/01/image-6963ac65a3d38-300x132.png" alt="" class="wp-image-3584" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2026/01/image-6963ac65a3d38-300x132.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2026/01/image-6963ac65a3d38-1024x452.png 1024w, https://wordpressblogimages.builttoroam.com/blogimages/2026/01/image-6963ac65a3d38-768x339.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2026/01/image-6963ac65a3d38.png 1081w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>Once the command has finished executing, open the newly created folder in VS Code.</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2026/01/image-6963b07c2f41e.png"><img loading="lazy" decoding="async" width="300" height="174" src="https://wordpressblogimages.builttoroam.com/blogimages/2026/01/image-6963b07c2f41e-300x174.png" alt="" class="wp-image-3585" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2026/01/image-6963b07c2f41e-300x174.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2026/01/image-6963b07c2f41e-1024x592.png 1024w, https://wordpressblogimages.builttoroam.com/blogimages/2026/01/image-6963b07c2f41e-768x444.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2026/01/image-6963b07c2f41e-1536x889.png 1536w, https://wordpressblogimages.builttoroam.com/blogimages/2026/01/image-6963b07c2f41e.png 1948w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>VS Code will automatically run uno-check, which you can see as the icon in the middle of the status bar. Clicking the icon will show the Uno Platform Status page. In this case my installation is reporting an error as I haven&#8217;t finished off setting up the Android SDK. What&#8217;s critical is that the solution has been correctly loaded and that Dev Server is ready (required for Hot Reload and Hot Design to work).</p>



<p>Now, from the status bar, pick the target platform you want to run on (I&#8217;ve selected desktop) and then you can run with or without the debugger. Note that Hot Design is only supported in VS Code when running without the debugger.</p>



<p>Clicking the Hot Design button (left icon in the floating toolbar) for the first time, it indicates I need to sign in with an Uno Platform account, via the Uno Platform Studio app.</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2026/01/image-6963b286ab1ba.png"><img loading="lazy" decoding="async" width="300" height="184" src="https://wordpressblogimages.builttoroam.com/blogimages/2026/01/image-6963b286ab1ba-300x184.png" alt="" class="wp-image-3586" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2026/01/image-6963b286ab1ba-300x184.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2026/01/image-6963b286ab1ba-768x472.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2026/01/image-6963b286ab1ba.png 872w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>From here I can click the Register (first time users) or Sign In buttons.</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2026/01/image-6963b2a4827cf.png"><img loading="lazy" decoding="async" width="295" height="300" src="https://wordpressblogimages.builttoroam.com/blogimages/2026/01/image-6963b2a4827cf-295x300.png" alt="" class="wp-image-3587" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2026/01/image-6963b2a4827cf-295x300.png 295w, https://wordpressblogimages.builttoroam.com/blogimages/2026/01/image-6963b2a4827cf.png 582w" sizes="auto, (max-width: 295px) 100vw, 295px" /></a></figure>



<p>After being redirected to the Uno Platform website to register and/or sign in, returning to the running app you should see that both icons have updated. Here we can see that Hot Reload is connected and ready to go. The Hot Design icon is not green because I&#8217;m currently using an account that is in the initial (free) trial period.</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2026/01/image-6963b86d8c229.png"><img loading="lazy" decoding="async" width="300" height="214" src="https://wordpressblogimages.builttoroam.com/blogimages/2026/01/image-6963b86d8c229-300x214.png" alt="" class="wp-image-3588" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2026/01/image-6963b86d8c229-300x214.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2026/01/image-6963b86d8c229-1024x730.png 1024w, https://wordpressblogimages.builttoroam.com/blogimages/2026/01/image-6963b86d8c229-768x547.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2026/01/image-6963b86d8c229.png 1044w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>Clicking the Hot Design button enters design mode &#8211; the app is still running but is placed in the center of the window surrounded by the Hot Design tooling. If you&#8217;ve seen Hot Design in the past, you may not have seen the new Agent mode, which allows you to create an entire page using AI from a prompt within Hot Design. Experiment with different prompts and then pick the best outcome. </p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2026/01/image-6963b88b469f1.png"><img loading="lazy" decoding="async" width="300" height="168" src="https://wordpressblogimages.builttoroam.com/blogimages/2026/01/image-6963b88b469f1-300x168.png" alt="" class="wp-image-3589" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2026/01/image-6963b88b469f1-300x168.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2026/01/image-6963b88b469f1-1024x574.png 1024w, https://wordpressblogimages.builttoroam.com/blogimages/2026/01/image-6963b88b469f1-768x430.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2026/01/image-6963b88b469f1-1536x860.png 1536w, https://wordpressblogimages.builttoroam.com/blogimages/2026/01/image-6963b88b469f1.png 1744w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p></p>
</div>
</div>
</div>



<p>Ok, now that we have a basic Uno Platform application, let&#8217;s open up the Chat window in VS Code. If you click on the Configure Tool button (to the right of the AI model selector at the bottom of the Chat window) you can see that the two Uno MCP servers are enabled. This will upskill the AI agent with access to the Uno Platform documentation, as well as the ability to launch and interact with the application.</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2026/01/image-6963b8d68716e.png"><img loading="lazy" decoding="async" width="300" height="250" src="https://wordpressblogimages.builttoroam.com/blogimages/2026/01/image-6963b8d68716e-300x250.png" alt="" class="wp-image-3590" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2026/01/image-6963b8d68716e-300x250.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2026/01/image-6963b8d68716e-1024x852.png 1024w, https://wordpressblogimages.builttoroam.com/blogimages/2026/01/image-6963b8d68716e-768x639.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2026/01/image-6963b8d68716e-1536x1278.png 1536w, https://wordpressblogimages.builttoroam.com/blogimages/2026/01/image-6963b8d68716e.png 1853w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>Let&#8217;s enter the following prompt: &#8220;Create an interest calculator app that is acble to calculate fixed or variable interest for a loan over a specified period. Fixed interest has a single interest rate that&#8217;s applied for the full duration of the loan. Variable interest has a starting rate and then can be adjusted any number of times throughout the loan.&#8221; When you click the Send button, you&#8217;ll see the agent kick in and start building out the application. </p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2026/01/image-6963b9948d51b.png"><img loading="lazy" decoding="async" width="195" height="300" src="https://wordpressblogimages.builttoroam.com/blogimages/2026/01/image-6963b9948d51b-195x300.png" alt="" class="wp-image-3591" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2026/01/image-6963b9948d51b-195x300.png 195w, https://wordpressblogimages.builttoroam.com/blogimages/2026/01/image-6963b9948d51b-667x1024.png 667w, https://wordpressblogimages.builttoroam.com/blogimages/2026/01/image-6963b9948d51b-768x1180.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2026/01/image-6963b9948d51b.png 953w" sizes="auto, (max-width: 195px) 100vw, 195px" /></a></figure>



<p>The first iteration of the app, based on numerous calls to the Uno MCP servers is already very functional. During the creation I left the application running and it was periodically updated to reflect the changes being made.</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2026/01/image-6963bf7745422.png"><img loading="lazy" decoding="async" width="236" height="300" src="https://wordpressblogimages.builttoroam.com/blogimages/2026/01/image-6963bf7745422-236x300.png" alt="" class="wp-image-3593" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2026/01/image-6963bf7745422-236x300.png 236w, https://wordpressblogimages.builttoroam.com/blogimages/2026/01/image-6963bf7745422-804x1024.png 804w, https://wordpressblogimages.builttoroam.com/blogimages/2026/01/image-6963bf7745422-768x978.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2026/01/image-6963bf7745422.png 1151w" sizes="auto, (max-width: 236px) 100vw, 236px" /></a></figure>



<p>Whilst this application is functional, it&#8217;s not particularly pleasing to look at. Let&#8217;s get the agent to improve this somewhat with the prompt: &#8220;Improve the appearance of the application by making it more modern and add a more pleasing theme&#8221;.</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2026/01/image-69646306d0aa1.png"><img loading="lazy" decoding="async" width="266" height="300" src="https://wordpressblogimages.builttoroam.com/blogimages/2026/01/image-69646306d0aa1-266x300.png" alt="" class="wp-image-3596" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2026/01/image-69646306d0aa1-266x300.png 266w, https://wordpressblogimages.builttoroam.com/blogimages/2026/01/image-69646306d0aa1.png 539w" sizes="auto, (max-width: 266px) 100vw, 266px" /></a></figure>



<p>What&#8217;s interesting here is that you can see that the agent is launching and then taking a screenshot of the application, in order to verify the visual changes being made.</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2026/01/image-6964633ea1208.png"><img loading="lazy" decoding="async" width="143" height="300" src="https://wordpressblogimages.builttoroam.com/blogimages/2026/01/image-6964633ea1208-143x300.png" alt="" class="wp-image-3597" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2026/01/image-6964633ea1208-143x300.png 143w, https://wordpressblogimages.builttoroam.com/blogimages/2026/01/image-6964633ea1208-486x1024.png 486w, https://wordpressblogimages.builttoroam.com/blogimages/2026/01/image-6964633ea1208.png 533w" sizes="auto, (max-width: 143px) 100vw, 143px" /></a></figure>



<p>The outcome is a much nicer looking application</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2026/01/image-6964627f3a7de.png"><img loading="lazy" decoding="async" width="288" height="300" src="https://wordpressblogimages.builttoroam.com/blogimages/2026/01/image-6964627f3a7de-288x300.png" alt="" class="wp-image-3594" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2026/01/image-6964627f3a7de-288x300.png 288w, https://wordpressblogimages.builttoroam.com/blogimages/2026/01/image-6964627f3a7de-983x1024.png 983w, https://wordpressblogimages.builttoroam.com/blogimages/2026/01/image-6964627f3a7de-768x800.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2026/01/image-6964627f3a7de.png 1189w" sizes="auto, (max-width: 288px) 100vw, 288px" /></a></figure>



<p>The agent was even able to nicely format the list of interest payments.</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2026/01/image-69646299268f2.png"><img loading="lazy" decoding="async" width="288" height="300" src="https://wordpressblogimages.builttoroam.com/blogimages/2026/01/image-69646299268f2-288x300.png" alt="" class="wp-image-3595" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2026/01/image-69646299268f2-288x300.png 288w, https://wordpressblogimages.builttoroam.com/blogimages/2026/01/image-69646299268f2-983x1024.png 983w, https://wordpressblogimages.builttoroam.com/blogimages/2026/01/image-69646299268f2-768x800.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2026/01/image-69646299268f2.png 1189w" sizes="auto, (max-width: 288px) 100vw, 288px" /></a></figure>



<p>In this post we walked through using AI to create a cross platform Uno Platform application using a combination of the MCP servers that are provided as part of the Uno Platform IDE extensions.</p>
<p>The post <a href="https://nicksnettravels.builttoroam.com/uno-mcps/">Use AI to Build Cross Platform Applications with Uno Platform, VS Code, Agents and MCPs</a> appeared first on <a href="https://nicksnettravels.builttoroam.com">Nick&#039;s .NET Travels</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://nicksnettravels.builttoroam.com/uno-mcps/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Development Process with AI</title>
		<link>https://nicksnettravels.builttoroam.com/development-process-with-ai/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=development-process-with-ai</link>
					<comments>https://nicksnettravels.builttoroam.com/development-process-with-ai/#respond</comments>
		
		<dc:creator><![CDATA[Nick]]></dc:creator>
		<pubDate>Mon, 29 Dec 2025 15:16:36 +0000</pubDate>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[AI]]></category>
		<category><![CDATA[Development Process]]></category>
		<guid isPermaLink="false">https://nicksnettravels.builttoroam.com/?p=3572</guid>

					<description><![CDATA[<p>With every update to the various models and tools, AI becomes more capable and in a lot of ways more independent. In much the same way as a junior developer learns over time and can take on more complex tasks, and can carry the tasks out with less supervision, we&#8217;ve seen AI mature to the ... <a title="Development Process with AI" class="read-more" href="https://nicksnettravels.builttoroam.com/development-process-with-ai/" aria-label="Read more about Development Process with AI">Read more</a></p>
<p>The post <a href="https://nicksnettravels.builttoroam.com/development-process-with-ai/">Development Process with AI</a> appeared first on <a href="https://nicksnettravels.builttoroam.com">Nick&#039;s .NET Travels</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>With every update to the various models and tools, AI becomes more capable and in a lot of ways more independent. In much the same way as a junior developer learns over time and can take on more complex tasks, and can carry the tasks out with less supervision, we&#8217;ve seen AI mature to the point where you can assign it entire units of work, with relatively little guidance and review. As developers adopt AI into their workflow, it is causing a massive shift in the development process, and in fact the process of creating and shipping software. In this post we&#8217;ll look at traditional development workflows and how they are being affected by the use of AI.</p>



<p>In discussing the development process I don&#8217;t want to get into the debate over the relative merits of different processes, such as Waterfall, Agile, Scrum, etc. Instead, I&#8217;m going to focus our attention on the relatively low-level workflow that a developer might follow when going about their work. Let&#8217;s assume that this starts with being assigned, or self-assigning, an issue to work on. The developer would go about doing the necessary investigation, planning, design, coding, tests etc required in order to complete the work. Once they&#8217;re done, there&#8217;s probably some sort of review process from a peer, or manager, before the work is either merged (if it needs to be combined into an existing code base), or published (if it&#8217;s a standalone tool/app/site). This might seem overly simplistic but let&#8217;s examine how this looks when we introduce AI.</p>



<p>Again, for the purpose of this discussion, let&#8217;s keep our attention on the developer workflow. Of course, AI can be incorporated into many other aspects of the product development lifecycle but for now, let&#8217;s look at in the context of the workflow we&#8217;ve just described. To start with, let&#8217;s start at the point the developer picks up the issue to work on. Normally it would be up to the developer to start investigating the issue in order to work out either the cause of the bug, or what needs to be done to implement a feature. With AI, depending on which tool you&#8217;re using, this initial step can either be skipped, or altered.</p>



<p>Some tools, like GitHub and Codex, support the full delegation of an issue, allowing the agent to investigate, plan and complete the implementation. The output is either a branch or a pull request, which can then be reviewed by the human-in-the-loop. This might result in further direction to the agent to continue development. Alternatively, the developer might pick up the work and either complete it, or adjust the work, in order to provide more direction to how the agent should complete the work. This is not too dissimilar to the role of a senior developer delegating work to a more junior developer.</p>



<p>Alternatively, the developer might want to be more involved. Rather than simply assigning the issue to the agent they can pick up the issue themselves. However, again, instead of going at it alone, the developer can interact with AI using chat to ask, plan and even code some of the work, much like when developers pair program.</p>



<p>In either of these two augmented workflows the developer is leveraging AI to both increase their productivity as well as their effectiveness. The developer is moving away from being a day-coder, into more of an orchestrator role. </p>



<p>In this post we&#8217;ve briefly examined one area where AI is making a difference in the development process. What&#8217;s becoming clear is that whilst there&#8217;s currently no clear guidlines for developers to follow when using AI, developers need to become familiar with the evolving world of AI agents and tools. Understanding when to delegate steps in the process to AI will become a key skill required to be a successful developer in the world of AI engineering.</p>
<p>The post <a href="https://nicksnettravels.builttoroam.com/development-process-with-ai/">Development Process with AI</a> appeared first on <a href="https://nicksnettravels.builttoroam.com">Nick&#039;s .NET Travels</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://nicksnettravels.builttoroam.com/development-process-with-ai/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Getting Started with MCP on Windows</title>
		<link>https://nicksnettravels.builttoroam.com/getting-started-with-mcp-on-windows/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=getting-started-with-mcp-on-windows</link>
					<comments>https://nicksnettravels.builttoroam.com/getting-started-with-mcp-on-windows/#respond</comments>
		
		<dc:creator><![CDATA[Nick]]></dc:creator>
		<pubDate>Wed, 17 Dec 2025 05:03:29 +0000</pubDate>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[AI]]></category>
		<category><![CDATA[MCP]]></category>
		<category><![CDATA[ODR]]></category>
		<category><![CDATA[Windows]]></category>
		<guid isPermaLink="false">https://nicksnettravels.builttoroam.com/?p=3557</guid>

					<description><![CDATA[<p>Earlier this year Microsoft was touting all the work they&#8217;re putting into Windows in order to make it AI ready. This includes a slew of features that will show up only on their copilot enabled computers. However, there are some features that will be more widely available. One of these is the support added to ... <a title="Getting Started with MCP on Windows" class="read-more" href="https://nicksnettravels.builttoroam.com/getting-started-with-mcp-on-windows/" aria-label="Read more about Getting Started with MCP on Windows">Read more</a></p>
<p>The post <a href="https://nicksnettravels.builttoroam.com/getting-started-with-mcp-on-windows/">Getting Started with MCP on Windows</a> appeared first on <a href="https://nicksnettravels.builttoroam.com">Nick&#039;s .NET Travels</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>Earlier this year Microsoft was touting all the work they&#8217;re putting into Windows in order to make it AI ready. This includes a slew of features that will show up only on their copilot enabled computers. However, there are some features that will be more widely available. One of these is the support added to Windows for an on-device agent registry, or Windows ODR for short. Initially this will be used to allow for the registration and listing of Model Context Protocol servers. This is going to be an initial post looking at the Windows ODR and building a Windows application that can register an MCP with the Windows ODR.</p>



<p>Before we get started, I will note that MCP on Windows is a prerelease feature and that I&#8217;m accessing it as part of the <a href="https://www.microsoft.com/en-us/windowsinsider/">Windows Insiders program</a>, on the dev channel. </p>



<p>To find out more about MCP on Windows and the Windows ODR you can start with the <a href="https://learn.microsoft.com/en-us/windows/ai/mcp/overview">Microsoft Learn documentation for MCP on Windows</a>. If you&#8217;re not familiar with MCP, I would suggest reading the <a href="https://modelcontextprotocol.io/docs/getting-started/intro">documentation</a> and then playing around with some MCPs in your AI tooling of choice (Copilot, Cursor, Codex etc).</p>



<h2 class="wp-block-heading">Enabling Experimental Agentic Features</h2>



<p>The Windows ODR comes with a convenient command line tool, odr.exe, which you can invoke from any command prompt. However, what you&#8217;ll find is that you will get an unintelligible error, <code>Fatal: No symbol result found with name "app-agents"</code>.</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2025/12/image.png"><img loading="lazy" decoding="async" width="300" height="117" src="https://wordpressblogimages.builttoroam.com/blogimages/2025/12/image-300x117.png" alt="" class="wp-image-3558" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2025/12/image-300x117.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2025/12/image.png 736w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>Of course, what the documentation fails to point out is that this error actually indicates you haven&#8217;t enabled the experimental AI features on Windows. If you go to Settings > System > AI components, you&#8217;ll see a new Experimental agentic features option, that is set to Off by default.</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2025/12/image-69421330e1993.png"><img loading="lazy" decoding="async" width="300" height="233" src="https://wordpressblogimages.builttoroam.com/blogimages/2025/12/image-69421330e1993-300x233.png" alt="" class="wp-image-3559" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2025/12/image-69421330e1993-300x233.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2025/12/image-69421330e1993-1024x796.png 1024w, https://wordpressblogimages.builttoroam.com/blogimages/2025/12/image-69421330e1993-768x597.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2025/12/image-69421330e1993.png 1202w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>When you attempt to toggle this option to On, you&#8217;ll get prompted to confirm that you&#8217;re enabling experimental agentic features.</p>



<figure class="wp-block-image size-medium"><img loading="lazy" decoding="async" width="300" height="233" src="https://wordpressblogimages.builttoroam.com/blogimages/2025/12/image-694213542d303-300x233.png" alt="" class="wp-image-3560" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2025/12/image-694213542d303-300x233.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2025/12/image-694213542d303-1024x795.png 1024w, https://wordpressblogimages.builttoroam.com/blogimages/2025/12/image-694213542d303-768x596.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2025/12/image-694213542d303.png 1207w" sizes="auto, (max-width: 300px) 100vw, 300px" /></figure>



<p>Enabling experimental features is something you should only do on computers dedicated for testing out preview Windows features.</p>



<h2 class="wp-block-heading">Registering an MCP with ODR</h2>



<p>Now that we have enabled the experimental agentic features, we can take a look at the odr.exe command line tool. If you open a command prompt and simply type odr, you&#8217;ll see some basic help information, including a list of the commands. </p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2025/12/image-6942300f3c0d3.png"><img loading="lazy" decoding="async" width="300" height="194" src="https://wordpressblogimages.builttoroam.com/blogimages/2025/12/image-6942300f3c0d3-300x194.png" alt="" class="wp-image-3562" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2025/12/image-6942300f3c0d3-300x194.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2025/12/image-6942300f3c0d3.png 694w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>Currently there&#8217;s only one command supported, which is &#8220;mcp&#8221;. To get the options, you can execute odr with parameters <code>mcp</code> and <code>-h</code>.</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2025/12/image-6942306e3d88b.png"><img loading="lazy" decoding="async" width="300" height="203" src="https://wordpressblogimages.builttoroam.com/blogimages/2025/12/image-6942306e3d88b-300x203.png" alt="" class="wp-image-3563" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2025/12/image-6942306e3d88b-300x203.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2025/12/image-6942306e3d88b-768x519.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2025/12/image-6942306e3d88b.png 860w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>As the documentation section <a href="https://learn.microsoft.com/en-us/windows/ai/mcp/overview#mcp-agent-connectors-on-windows">MCP agent connectors on Windows</a> covers, Microsoft has already started to create Windows specific MCPs. Executing odr with parameters <code>mcp list</code> will return the list of currently registered MCPs. This includes the <a href="https://learn.microsoft.com/en-us/windows/ai/mcp/overview#mcp-agent-connectors-on-windows">Windows File Explorer MCP</a>.</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2025/12/image-6942314552e3e.png"><img loading="lazy" decoding="async" width="300" height="193" src="https://wordpressblogimages.builttoroam.com/blogimages/2025/12/image-6942314552e3e-300x193.png" alt="" class="wp-image-3564" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2025/12/image-6942314552e3e-300x193.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2025/12/image-6942314552e3e-768x493.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2025/12/image-6942314552e3e.png 878w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>From the help listing for the <code>mcp</code> parameter, there is an <code>add</code> option which can be combined with either a manifest file, or the uri of a remote server. Using this option we can register the Uno Platform <a href="https://platform.uno/docs/articles/features/using-the-uno-mcps.html#mcp-remote">remote MCP</a>.</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2025/12/image-694232cdafdf9.png"><img loading="lazy" decoding="async" width="300" height="200" src="https://wordpressblogimages.builttoroam.com/blogimages/2025/12/image-694232cdafdf9-300x200.png" alt="" class="wp-image-3565" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2025/12/image-694232cdafdf9-300x200.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2025/12/image-694232cdafdf9.png 500w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>Unfortunately, the information returned after adding the mcp, nor if we now run the <code>list</code> command, doesn&#8217;t include the server id of the MCP server. This makes it hard to remove the MCP registration. Luckily you can discover the id of the server by attempting to register the same server again.</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2025/12/image-69423345b9a8d.png"><img loading="lazy" decoding="async" width="300" height="50" src="https://wordpressblogimages.builttoroam.com/blogimages/2025/12/image-69423345b9a8d-300x50.png" alt="" class="wp-image-3566" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2025/12/image-69423345b9a8d-300x50.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2025/12/image-69423345b9a8d-768x129.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2025/12/image-69423345b9a8d.png 881w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>In this case the server id is <code>uno-docs-mcp-1.2.3</code> and this id can be used to remove the MCP registration.</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2025/12/image-6942337c03609.png"><img loading="lazy" decoding="async" width="300" height="54" src="https://wordpressblogimages.builttoroam.com/blogimages/2025/12/image-6942337c03609-300x54.png" alt="" class="wp-image-3567" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2025/12/image-6942337c03609-300x54.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2025/12/image-6942337c03609.png 625w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>One thing to note is that when you have registered an MCP, it now appears within Settings under the connectors available for a specific agent. From the System > AI components screen in Setttings, click on the Agents link.</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2025/12/image-694233e6e4440.png"><img loading="lazy" decoding="async" width="300" height="233" src="https://wordpressblogimages.builttoroam.com/blogimages/2025/12/image-694233e6e4440-300x233.png" alt="" class="wp-image-3568" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2025/12/image-694233e6e4440-300x233.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2025/12/image-694233e6e4440-1024x796.png 1024w, https://wordpressblogimages.builttoroam.com/blogimages/2025/12/image-694233e6e4440-768x597.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2025/12/image-694233e6e4440.png 1202w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>This will list the known agents, in this case just the Terminal I have open.</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2025/12/image-6942342218904.png"><img loading="lazy" decoding="async" width="300" height="233" src="https://wordpressblogimages.builttoroam.com/blogimages/2025/12/image-6942342218904-300x233.png" alt="" class="wp-image-3569" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2025/12/image-6942342218904-300x233.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2025/12/image-6942342218904-1024x796.png 1024w, https://wordpressblogimages.builttoroam.com/blogimages/2025/12/image-6942342218904-768x597.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2025/12/image-6942342218904.png 1202w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>Clicking the Terminal item provides more information about the agent and the MCPs that are available.</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2025/12/image-694234717d37c.png"><img loading="lazy" decoding="async" width="300" height="233" src="https://wordpressblogimages.builttoroam.com/blogimages/2025/12/image-694234717d37c-300x233.png" alt="" class="wp-image-3570" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2025/12/image-694234717d37c-300x233.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2025/12/image-694234717d37c-1024x796.png 1024w, https://wordpressblogimages.builttoroam.com/blogimages/2025/12/image-694234717d37c-768x597.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2025/12/image-694234717d37c.png 1202w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>We can see here both the File Explorer and the uno-docs-mcp connectors.</p>



<p>We&#8217;ve covered some of the basics of getting started with MCP on Windows and the on-device agent registry (ODR). In subsequent posts will look at how we can access these registered MCPs and also how your Windows application can include, and register, an MCP server.</p>



<p></p>
<p>The post <a href="https://nicksnettravels.builttoroam.com/getting-started-with-mcp-on-windows/">Getting Started with MCP on Windows</a> appeared first on <a href="https://nicksnettravels.builttoroam.com">Nick&#039;s .NET Travels</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://nicksnettravels.builttoroam.com/getting-started-with-mcp-on-windows/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Is Vibe Coding Just a Cost Cutting Strategy, like Outsourcing/Offshore Development?</title>
		<link>https://nicksnettravels.builttoroam.com/vibe-coding/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=vibe-coding</link>
					<comments>https://nicksnettravels.builttoroam.com/vibe-coding/#respond</comments>
		
		<dc:creator><![CDATA[Nick]]></dc:creator>
		<pubDate>Fri, 26 Sep 2025 05:46:13 +0000</pubDate>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[AI]]></category>
		<category><![CDATA[Tools]]></category>
		<category><![CDATA[Vibe Coding]]></category>
		<guid isPermaLink="false">https://nicksnettravels.builttoroam.com/?p=3541</guid>

					<description><![CDATA[<p>One of the things about software development is that it is still inherently expensive to do; well at least, to do it well. There have been countless attempts to reduce the cost of software development leading to innovation in terms of both tooling and processes. In this post I&#8217;m going to discuss the more recent ... <a title="Is Vibe Coding Just a Cost Cutting Strategy, like Outsourcing/Offshore Development?" class="read-more" href="https://nicksnettravels.builttoroam.com/vibe-coding/" aria-label="Read more about Is Vibe Coding Just a Cost Cutting Strategy, like Outsourcing/Offshore Development?">Read more</a></p>
<p>The post <a href="https://nicksnettravels.builttoroam.com/vibe-coding/">Is Vibe Coding Just a Cost Cutting Strategy, like Outsourcing/Offshore Development?</a> appeared first on <a href="https://nicksnettravels.builttoroam.com">Nick&#039;s .NET Travels</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>One of the things about software development is that it is still inherently expensive to do; well at least, to do it well. There have been countless attempts to reduce the cost of software development leading to innovation in terms of both tooling and processes. In this post I&#8217;m going to discuss the more recent trend around Vibe Coding and specifically how it&#8217;s being applied to some of the AI-first tooling that&#8217;s available. The aim is to answer the question as to whether Vibe Coding will enable us to build better, or cheaper, software.</p>



<p>I want to start by saying that, as with most tools, technologies, processes etc, there&#8217;s going to be times when Vibe Coding is the <a href="https://english.stackexchange.com/questions/427559/a-saying-for-using-the-right-tools-to-do-the-right-job">right tool for the job</a> (I use the term &#8220;tool&#8221; here loosely here as it may not be a specific tool, perhaps instead a process, or lack thereof). Furthermore, you shouldn&#8217;t read into this post any judgement on whether Vibe Coding is a good or bad practice. At the end of the day, whether Vibe Coding is right or wrong, should be determined based on the achieved outcome in terms of time, cost and quality of the output.</p>



<p>Let&#8217;s back up a little and look at what we mean by Vibe Coding. For a quick summary we can track Vibe Coding from being an Internet meme through to being a more widely recognized practice in software development:</p>



<p><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f310.png" alt="🌐" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Internet meme → <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4bb.png" alt="💻" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Indie dev/streamer slang → <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f916.png" alt="🤖" class="wp-smiley" style="height: 1em; max-height: 1em;" /> AI-assisted era → <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f3a4.png" alt="🎤" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Recognized as a legit creative practice.</p>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>Phase</th><th>Description</th><th>Reference</th></tr></thead><tbody><tr><td><strong>1. Coined by Karpathy</strong></td><td><a href="https://x.com/karpathy/status/1886192184808149383">February 2, 2025 post on X</a> describing the concept</td><td>(<a href="https://trending.knowyourmeme.com/editorials/guides/what-does-vibe-coding-mean-the-new-ai-enabled-programming-trend-explained?utm_source=chatgpt.com">Know Your Meme</a>, <a href="https://www.dailydot.com/culture/what-is-vibe-coding-memes/?utm_source=chatgpt.com">The Daily Dot</a>)</td></tr><tr><td><strong>2. Meme Spread &amp; Community Jokes</strong></td><td>Rapid memetic adoption across X, Reddit, TikTok, Hacker News</td><td>(<a href="https://www.smartlab.at/vibe-coding-from-meme-to-movement-and-the-future-of-software-engineering/?utm_source=chatgpt.com">smartlab.at</a>, <a href="https://blog.vibecoding-hub.com/discover-what-developers-are-saying-about-vibe-coding-on-reddit-and-hackernews/?utm_source=chatgpt.com">blog.vibecoding-hub.com</a>, <a href="https://www.reddit.com/r/vibecoding/comments/1jisa6g?utm_source=chatgpt.com">Reddit</a>)</td></tr><tr><td><strong>3. AI-Assisted Coding Practice</strong></td><td>Shift to prompt-driven workflows, minimal code scrutiny</td><td>(<a href="https://en.wikipedia.org/wiki/Vibe_coding?utm_source=chatgpt.com">Wikipedia</a>, <a href="https://www.pluralsight.com/resources/blog/ai-and-data/vibe-coding-explained-btb?utm_source=chatgpt.com">Pluralsight</a>, <a href="https://github.com/resources/articles/ai/what-is-vibe-coding?utm_source=chatgpt.com">GitHub</a>)</td></tr><tr><td><strong>4. Cultural Legitimization</strong></td><td>Acknowledged in tech media, investment circles; recognized as creative method</td><td>(<a href="https://en.wikipedia.org/wiki/Vibe_coding?utm_source=chatgpt.com">Wikipedia</a>, <a href="https://www.forbes.com/councils/forbesbusinesscouncil/2025/06/04/vibe-coding-what-is-it-and-where-is-it-headed/?utm_source=chatgpt.com">Forbes</a>, <a href="https://www.businessinsider.com/andrew-ng-vibe-coding-unfortunate-term-exhausting-job-2025-6?utm_source=chatgpt.com">Business Insider</a>)</td></tr></tbody></table></figure>



<p>I have to say that I truly appreciate the honesty of the Merriam-Webster definition of vibe coding:</p>



<figure class="wp-block-pullquote"><blockquote><p>Writing computer code in a somewhat careless fashion, with AI assistance</p><cite><a href="https://www.merriam-webster.com/slang/vibe-coding">Merriam-Webster</a></cite></blockquote></figure>



<h2 class="wp-block-heading">In Practice</h2>



<p>One of the hip trends online is the slew of low or no-code online app builders such as <a href="https://lovable.dev/">Lovable</a>, <a href="https://www.tempo.new/">TemoLabs</a> and <a href="https://www.co.dev/">co.dev</a>. Most of these start with a singular prompt, encouraging you to give a one or two sentence description of the app that you want to build. The builder then goes off and builds a very rudimentary application that looks very run-of-the-mill.</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2025/09/image.png"><img loading="lazy" decoding="async" width="300" height="237" src="https://wordpressblogimages.builttoroam.com/blogimages/2025/09/image-300x237.png" alt="" class="wp-image-3544" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2025/09/image-300x237.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2025/09/image-768x606.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2025/09/image.png 855w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>The experience of then interacting with the builder site in order to coerce it to give you the application you want can be both rewarding and somewhat infuriating. The ability to create a fully-fledged application from a mere sentence or two is simply astounding, if you compare to where we were even 2 years ago in the world or low-code/no-code solutions. It can be really rewarding to have an idea, generate a simple, yet working, prototype and be able to validate the idea in minutes, rather than days, weeks or months.</p>



<p>On the flipside, sometimes the model can really struggle with what might seem like almost basic issues. This could be a simple compile error that for whatever reason the model can&#8217;t rectify without some intervention. As the models and site integration of the models improves this will get better but inevitably there will be compile errors, logic errors and complexity that is beyond the scope that can be resolve via a simple prompt-based interaction.</p>



<p>There&#8217;s also the cost aspect of these builder sites &#8211; they significantly reduce the cost of creating applications but at the expense of building something that has a strong architecture and is able to mature and grow with the requirements of the application. Furthermore, once you get beyond the included tokens, you need to start paying for tokens in order to keep feeding the AI algorithm. The more complexity in the app, the more likely the model will yield build errors, which in turn mean more tokens consumed to fix the errors the model created (yeh, there&#8217;s no &#8220;you broke it, so fix it for free&#8221; when it comes to AI).</p>



<p>If we consider the app builder sites as the completely hands-off approach, where you&#8217;re simply interacting via a prompt with minimal interaction with code, the other trend is to interact with AI models using IDE or console tools, like Cursor, Windsurf, GitHub Copilot (VS Code and/or Visual Studio), Codex, Warp etc. Most of these tools allow you to control which AI model you want to use and the type of interaction you want to have with the model. For example, this illustration is from the Chat pane inside VS Code, allowing you to configure the mode (Agent) and model (Claude Sonnet 4).</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="447" height="107" src="https://wordpressblogimages.builttoroam.com/blogimages/2025/09/image-68d6238de8f38.png" alt="" class="wp-image-3545" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2025/09/image-68d6238de8f38.png 447w, https://wordpressblogimages.builttoroam.com/blogimages/2025/09/image-68d6238de8f38-300x72.png 300w" sizes="auto, (max-width: 447px) 100vw, 447px" /></figure>



<p>What you select for the mode really determines the level of actual coding you want to be doing. If you&#8217;re deep in the trenches writing a lot of code, the Ask mode is great for suggesting ways to code a method, analysing existing code, providing hints and information on how to use an API etc. Of course, if you want the model to be more involved, you can switch to Edit mode, in which case the model will start to apply changes, and potentially changes across a number of files. Lastly, if you want to be really hands-off you can set the mode to Agent. Agent mode is great for where you want to hand off a coding task and simply be involved in the reviewing phase. In the recent release of Codex, this has gone one step further, making it easy to dispatch whole coding tasks into the cloud to be done in an asynchronous manner, freeing you up to continue with other tasks.</p>



<h2 class="wp-block-heading">Cost Cutting</h2>



<p>The opening premise of this post was to consider vibe coding in the context of building better, and cheaper, software. In the preceding section we looked at two of the approaches to vibe coding, app builders and AI enabled tooling, and I would argue that there&#8217;s a mix of pros and cons with both approaches.</p>



<p>If we look at the app builders there is definitely a cost saving when it comes to the ability to generate quick, working, prototypes in order to validate ideas. It&#8217;s questionable as to whether these can easily be used as the basis for quality production-ready application without substantial investment in developers to review, refactor and stabilize the codebase.</p>



<p>On the flipside, AI enabled tooling can offer a mixed bag of success. This is a much larger topic that&#8217;s really still in its infancy regarding the optimum way to interact with AI models but enough to say that even if you were to occasionally use the AI models in Ask mode, you&#8217;d still derive some benefit from the speed and knowledge that the AI model brings when it offers up solutions.</p>



<h2 class="wp-block-heading">In Summary</h2>



<p>I think it&#8217;s too early for companies to be making significant reductions in their development teams. Rather they should be investing in internal knowledge/research into the ways that AI can assist the existing development team to be more productive. Teams that can adopt AI tools and leverage agent mode will surely be able to deliver more features, quicker, and with more stability.</p>
<p>The post <a href="https://nicksnettravels.builttoroam.com/vibe-coding/">Is Vibe Coding Just a Cost Cutting Strategy, like Outsourcing/Offshore Development?</a> appeared first on <a href="https://nicksnettravels.builttoroam.com">Nick&#039;s .NET Travels</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://nicksnettravels.builttoroam.com/vibe-coding/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Windows AI – Click to Do with an Uno Platform Application as an IActionProvider</title>
		<link>https://nicksnettravels.builttoroam.com/windows-ai-click-to-do/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=windows-ai-click-to-do</link>
					<comments>https://nicksnettravels.builttoroam.com/windows-ai-click-to-do/#respond</comments>
		
		<dc:creator><![CDATA[Nick]]></dc:creator>
		<pubDate>Sat, 16 Aug 2025 05:05:33 +0000</pubDate>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[Click to Do]]></category>
		<category><![CDATA[Uno]]></category>
		<category><![CDATA[Uno Platform]]></category>
		<category><![CDATA[Windows]]></category>
		<guid isPermaLink="false">https://nicksnettravels.builttoroam.com/?p=3525</guid>

					<description><![CDATA[<p>In my previous post on Click to Do we created an application that is activated via a URI triggered by Click to Do. In this post we&#8217;ll register with Click to Do by implementing the IActionProvider interface and registering as COM Server. As with the previous post on Click to Do, this only works with ... <a title="Windows AI &#8211; Click to Do with an Uno Platform Application as an IActionProvider" class="read-more" href="https://nicksnettravels.builttoroam.com/windows-ai-click-to-do/" aria-label="Read more about Windows AI &#8211; Click to Do with an Uno Platform Application as an IActionProvider">Read more</a></p>
<p>The post <a href="https://nicksnettravels.builttoroam.com/windows-ai-click-to-do/">Windows AI &#8211; Click to Do with an Uno Platform Application as an IActionProvider</a> appeared first on <a href="https://nicksnettravels.builttoroam.com">Nick&#039;s .NET Travels</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>In my <a href="https://nicksnettravels.builttoroam.com/click-to-do-uri-protocol/">previous post</a> on Click to Do we created an application that is activated via a URI triggered by Click to Do. In this post we&#8217;ll register with Click to Do by implementing the IActionProvider interface and registering as COM Server. As with the previous post on Click to Do, this only works with the WinAppSdk target for the Uno Platform application.</p>



<p>Similar to how we implemented Click to Do using URI protocol activation, there are three steps in setting up the Uno Platform application (well, in fact, any Windows App Sdk based application) to integrate with Click to Do using the <a href="https://learn.microsoft.com/en-us/uwp/api/windows.ai.actions.provider.iactionprovider">IActionProvider</a> interface:</p>



<ol class="wp-block-list">
<li>Include action registration JSON file as Content in your application.</li>



<li>Register for the&nbsp;<code>com.microsoft.windows.ai.actions</code>&nbsp;extension in the packageappx.manifest, as well as defining a&nbsp;<code>windows.comServer</code> extension.</li>



<li>Implement the IActionProvider interface, including starting and registering the COM Server.</li>
</ol>



<p>We&#8217;ll start with another newly created Uno Platform application, BusinessSearchActionProviderApp, using the Blank preset and making sure we add Windows App SDK in the Platforms section of the wizard.</p>



<h2 class="wp-block-heading">Actions Registration</h2>



<p>Like we did previously, add a new file into the Assets folder. We’ll call it&nbsp;<code>actions.json</code>&nbsp;but you can call it what you want, just make sure you use the same name later in the packagappx.manifest. In this file, include the registration for your actions, for example.</p>



<pre class="hljs" style="display: block; overflow-x: auto; padding: 0.5em; background: rgb(255, 255, 255); color: rgb(0, 0, 0);">{
  <span class="hljs-attr" style="color: red;">"version"</span>: <span class="hljs-number">1</span>,
  <span class="hljs-attr" style="color: red;">"actions"</span>: [
    {
      <span class="hljs-attr" style="color: red;">"id"</span>: <span class="hljs-string" style="color: rgb(163, 21, 21);">"BusinessSearchActionProvider.Actions.NameSearch"</span>,
      <span class="hljs-attr" style="color: red;">"description"</span>: <span class="hljs-string" style="color: rgb(163, 21, 21);">"Name search with action provider"</span>,
      <span class="hljs-attr" style="color: red;">"inputs"</span>: [
        {
          <span class="hljs-attr" style="color: red;">"name"</span>: <span class="hljs-string" style="color: rgb(163, 21, 21);">"Message"</span>,
          <span class="hljs-attr" style="color: red;">"kind"</span>: <span class="hljs-string" style="color: rgb(163, 21, 21);">"Text"</span>
        }
      ],
      <span class="hljs-attr" style="color: red;">"outputs"</span>: [],
      <span class="hljs-attr" style="color: red;">"instantiationDescription"</span>: <span class="hljs-string" style="color: rgb(163, 21, 21);">"Business Name Search Action Provider: '${Message.ShortText}'"</span>,
      <span class="hljs-attr" style="color: red;">"invocation"</span>: {
        <span class="hljs-attr" style="color: red;">"type"</span>: <span class="hljs-string" style="color: rgb(163, 21, 21);">"COM"</span>,
        <span class="hljs-attr" style="color: red;">"clsid"</span>: <span class="hljs-string" style="color: rgb(163, 21, 21);">"4531D13F-5953-432E-8841-53A58EA26DFE"</span>
      }
    }
  ]
}
</pre>



<p>The details for the JSON schema can found in the&nbsp;<a href="https://learn.microsoft.com/en-us/windows/ai/app-actions/actions-json">documentation</a>&nbsp;but in brief, this JSON snippet registers a single action,&nbsp;<code>BusinessSearchActionProvider.UriActions.NameSearch</code>, that accepts a single input, Message, that is Text. The application will be invoked via COM &#8211; make sure you select a new GUID for your action provider (In Visual Studio, you can use the Create GUID item from the Tools menu).</p>



<h2 class="wp-block-heading">Package Manifest</h2>



<p>As we did in the previous post, we need to register the&nbsp;<code>com.microsoft.windows.ai.actions</code>&nbsp;extension, specifying the name of the JSON file that includes the actions to register.</p>



<p>The following packageappx.manifest has been modified to include additional namespacess <code>uap3</code>,&nbsp;com, com2 and com3, and an Extensions block that registers the actions extension, specifying the Actions.json file. It also registers a <code>windows.comServer</code> extensions, which will act as the entry point for the application when invoked from Click to Do. It&#8217;s important that the GUID specified in this extension matches the GUID specified in the Actions.json file.</p>



<pre class="hljs" style="display: block; overflow-x: auto; padding: 0.5em; background: rgb(255, 255, 255); color: rgb(0, 0, 0);"><span class="php"><span class="hljs-meta" style="color: rgb(43, 145, 175);">&lt;?</span>xml version=<span class="hljs-string" style="color: rgb(163, 21, 21);">"1.0"</span> encoding=<span class="hljs-string" style="color: rgb(163, 21, 21);">"utf-8"</span><span class="hljs-meta" style="color: rgb(43, 145, 175);">?&gt;</span></span>
<span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">Package</span>
  <span class="hljs-attr" style="color: red;">xmlns</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"http://schemas.microsoft.com/appx/manifest/foundation/windows10"</span>
  <span class="hljs-attr" style="color: red;">xmlns:uap</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"http://schemas.microsoft.com/appx/manifest/uap/windows10"</span>
  <b><span class="hljs-attr" style="color: red;">xmlns:uap3</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"http://schemas.microsoft.com/appx/manifest/uap/windows10/3"</span>
  <span class="hljs-attr" style="color: red;">xmlns:com</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"http://schemas.microsoft.com/appx/manifest/com/windows10"</span>
  <span class="hljs-attr" style="color: red;">xmlns:com2</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"http://schemas.microsoft.com/appx/manifest/com/windows10/2"</span>
  <span class="hljs-attr" style="color: red;">xmlns:com3</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"http://schemas.microsoft.com/appx/manifest/com/windows10/3"</span></b>
  <span class="hljs-attr" style="color: red;">xmlns:rescap</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"</span>
  <span class="hljs-attr" style="color: red;">IgnorableNamespaces</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"uap rescap"</span>&gt;</span>

    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">Identity</span> /&gt;</span>
    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">Properties</span> /&gt;</span>

    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">Dependencies</span>&gt;</span>
        <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">TargetDeviceFamily</span> <span class="hljs-attr" style="color: red;">Name</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Windows.Universal"</span> <span class="hljs-attr" style="color: red;">MinVersion</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"10.0.17763.0"</span> <span class="hljs-attr" style="color: red;">MaxVersionTested</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"10.0.19041.0"</span> /&gt;</span>
        <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">TargetDeviceFamily</span> <span class="hljs-attr" style="color: red;">Name</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Windows.Desktop"</span> <span class="hljs-attr" style="color: red;">MinVersion</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"10.0.17763.0"</span> <span class="hljs-attr" style="color: red;">MaxVersionTested</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"10.0.19041.0"</span> /&gt;</span>
    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">Dependencies</span>&gt;</span>

    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">Resources</span>&gt;</span>
        <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">Resource</span> <span class="hljs-attr" style="color: red;">Language</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"x-generate"</span>/&gt;</span>
    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">Resources</span>&gt;</span>

    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">Applications</span>&gt;</span>
        <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">Application</span> <span class="hljs-attr" style="color: red;">Id</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"App"</span>
          <span class="hljs-attr" style="color: red;">Executable</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"$targetnametoken$.exe"</span>
          <span class="hljs-attr" style="color: red;">EntryPoint</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"$targetentrypoint$"</span>&gt;</span>
            <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">uap:VisualElements</span> /&gt;</span>
            <b><span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">Extensions</span>&gt;</span>
                <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">uap3:Extension</span> <span class="hljs-attr" style="color: red;">Category</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"windows.appExtension"</span>&gt;</span>
                    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">uap3:AppExtension</span>
                    <span class="hljs-attr" style="color: red;">Name</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"com.microsoft.windows.ai.actions"</span>
                    <span class="hljs-attr" style="color: red;">Id</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"BusinessSearchActionsCOMServer"</span>
                    <span class="hljs-attr" style="color: red;">DisplayName</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Actions for Business Search COM Server"</span>
                    <span class="hljs-attr" style="color: red;">PublicFolder</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Assets"</span>&gt;</span>
                        <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">uap3:Properties</span>&gt;</span>
                            <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">Registration</span>&gt;</span>Actions.json<span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">Registration</span>&gt;</span>
                        <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">uap3:Properties</span>&gt;</span>
                    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">uap3:AppExtension</span>&gt;</span>
                <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">uap3:Extension</span>&gt;</span>
                <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">com2:Extension</span> <span class="hljs-attr" style="color: red;">Category</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"windows.comServer"</span>&gt;</span>
                    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">com2:ComServer</span>&gt;</span>
                        <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">com3:ExeServer</span> <span class="hljs-attr" style="color: red;">Executable</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"BusinessSearchActionProviderApp.exe"</span> <span class="hljs-attr" style="color: red;">DisplayName</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Business Search App COM Server"</span>&gt;</span>
                            <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">com:Class</span> <span class="hljs-attr" style="color: red;">Id</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"4531D13F-5953-432E-8841-53A58EA26DFE"</span> <span class="hljs-attr" style="color: red;">DisplayName</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Business Search App COM Server"</span> /&gt;</span>
                        <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">com3:ExeServer</span>&gt;</span>
                    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">com2:ComServer</span>&gt;</span>
                <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">com2:Extension</span>&gt;</span>
            <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">Extensions</span>&gt;</span></b>
        <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">Application</span>&gt;</span>
    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">Applications</span>&gt;</span>

    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">Capabilities</span>&gt;</span>
        <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">rescap:Capability</span> <span class="hljs-attr" style="color: red;">Name</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"runFullTrust"</span> /&gt;</span>
    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">Capabilities</span>&gt;</span>
<span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">Package</span>&gt;</span>
</pre>



<h2 class="wp-block-heading">Application and Startup Logic</h2>



<p>In order to register the COM server, we first need to disable the startup logic that the WinAppSdk tooling generates. Add the following property to the csproj</p>



<pre class="wp-block-preformatted">&lt;DefineConstants>DISABLE_XAML_GENERATED_MAIN&lt;/DefineConstants> </pre>



<p>With the property set, you&#8217;re now responsible for the startup logic for the application. Let&#8217;s create Program.cs in the Platforms\Windows folder and add the following code.</p>



<pre class="hljs" style="display: block; overflow-x: auto; padding: 0.5em; background: rgb(255, 255, 255); color: rgb(0, 0, 0);">
<span class="hljs-keyword" style="color: rgb(0, 0, 255);">using</span> Shmuelie.WinRTServer;
<span class="hljs-keyword" style="color: rgb(0, 0, 255);">using</span> System;
<span class="hljs-keyword" style="color: rgb(0, 0, 255);">using</span> System.Threading.Tasks;
<span class="hljs-keyword" style="color: rgb(0, 0, 255);">using</span> Shmuelie.WinRTServer.CsWinRT;
<span class="hljs-keyword" style="color: rgb(0, 0, 255);">using</span> System.Diagnostics;


<span class="hljs-keyword" style="color: rgb(0, 0, 255);">namespace</span> <span class="hljs-title" style="color: rgb(163, 21, 21);">BusinessSearchActionProviderApp</span>;

<span class="hljs-keyword" style="color: rgb(0, 0, 255);">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">static</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">class</span> <span class="hljs-title" style="color: rgb(163, 21, 21);">Program</span>
{
    [STAThread]
    <span class="hljs-function"><span class="hljs-keyword" style="color: rgb(0, 0, 255);">static</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">async</span> Task <span class="hljs-title" style="color: rgb(163, 21, 21);">Main</span>(<span class="hljs-params"><span class="hljs-keyword" style="color: rgb(0, 0, 255);">string</span>[] args</span>)
    </span>{
        WinRT.ComWrappersSupport.InitializeComWrappers();

        <span class="hljs-keyword" style="color: rgb(0, 0, 255);">await</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">using</span> (ComServer server = <span class="hljs-keyword" style="color: rgb(0, 0, 255);">new</span>())
        {
            <span class="hljs-keyword" style="color: rgb(0, 0, 255);">var</span> sampleActionProvider = <span class="hljs-keyword" style="color: rgb(0, 0, 255);">new</span> BusinessSearchActionProvider();
            server.RegisterClass&lt;BusinessSearchActionProvider, Windows.AI.Actions.Provider.IActionProvider&gt;(() =&gt; sampleActionProvider);
            server.Start();

            Application.Start((p) =&gt;
            {
                <span class="hljs-keyword" style="color: rgb(0, 0, 255);">var</span> context = <span class="hljs-keyword" style="color: rgb(0, 0, 255);">new</span> Microsoft.UI.Dispatching.DispatcherQueueSynchronizationContext(Microsoft.UI.Dispatching.DispatcherQueue.GetForCurrentThread());
                SynchronizationContext.SetSynchronizationContext(context);
                <span class="hljs-keyword" style="color: rgb(0, 0, 255);">new</span> App();
            });

            <span class="hljs-comment" style="color: green;">// Regular disposing of the ComServer is broken (https://github.com/shmuelie/Shmuelie.WinRTServer/issues/28).</span>
            <span class="hljs-comment" style="color: green;">// We instead call the UnsafeDispose method to dispose it.</span>
            server.UnsafeDispose();
        }
    }
}
</pre>



<p>In order for this to compile you&#8217;ll need to add some package references (which includes the ComServer implementation that simplifies registering a COM Server) and the BusinessSearchActionProvider (which implements the IActionProvider interface). Here are the package references you&#8217;ll need</p>



<pre class="hljs" style="display: block; overflow-x: auto; padding: 0.5em; background: rgb(255, 255, 255); color: rgb(0, 0, 0);">    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">ItemGroup</span> <span class="hljs-attr" style="color: red;">Condition</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"'$(TargetFramework)'=='net9.0-windows10.0.26100'"</span>&gt;</span>
        <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">PackageReference</span> <span class="hljs-attr" style="color: red;">Include</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Microsoft.Windows.CsWin32"</span>&gt;</span>
            <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">PrivateAssets</span>&gt;</span>all<span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">PrivateAssets</span>&gt;</span>
            <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">IncludeAssets</span>&gt;</span>runtime; build; native; contentfiles; analyzers; buildtransitive<span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">IncludeAssets</span>&gt;</span>
        <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">PackageReference</span>&gt;</span>
        <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">PackageReference</span> <span class="hljs-attr" style="color: red;">Include</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Microsoft.Windows.CsWinRT"</span> /&gt;</span>
        <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">PackageReference</span> <span class="hljs-attr" style="color: red;">Include</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Shmuelie.WinRTServer"</span> /&gt;</span>
    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">ItemGroup</span>&gt;</span></pre>



<p>And then the IActionProvider implementation. Make sure the Guid attribute value matches the Guid used in the Actions.json and the packageappx.manifest.</p>



<pre class="hljs" style="display: block; overflow-x: auto; padding: 0.5em; background: rgb(255, 255, 255); color: rgb(0, 0, 0);"><span class="hljs-keyword" style="color: rgb(0, 0, 255);">using</span> System.Runtime.InteropServices;
<span class="hljs-keyword" style="color: rgb(0, 0, 255);">using</span> Windows.AI.Actions;
<span class="hljs-keyword" style="color: rgb(0, 0, 255);">using</span> Windows.Foundation;
<span class="hljs-keyword" style="color: rgb(0, 0, 255);">using</span> WinRT;

<span class="hljs-keyword" style="color: rgb(0, 0, 255);">namespace</span> <span class="hljs-title" style="color: rgb(163, 21, 21);">BusinessSearchActionProviderApp</span>;

<span class="hljs-comment" style="color: green;">// Class is declared partial to allow cswinrt insert generated code to enable marshalling without using reflection</span>
[Guid(<span class="hljs-string" style="color: rgb(163, 21, 21);">"4531D13F-5953-432E-8841-53A58EA26DFE"</span>)]
<span class="hljs-keyword" style="color: rgb(0, 0, 255);">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">partial</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">class</span> <span class="hljs-title" style="color: rgb(163, 21, 21);">BusinessSearchActionProvider</span> : <span class="hljs-title" style="color: rgb(163, 21, 21);">Windows</span>.<span class="hljs-title" style="color: rgb(163, 21, 21);">AI</span>.<span class="hljs-title" style="color: rgb(163, 21, 21);">Actions</span>.<span class="hljs-title" style="color: rgb(163, 21, 21);">Provider</span>.<span class="hljs-title" style="color: rgb(163, 21, 21);">IActionProvider</span>
{
    <span class="hljs-function"><span class="hljs-keyword" style="color: rgb(0, 0, 255);">public</span> IAsyncAction <span class="hljs-title" style="color: rgb(163, 21, 21);">InvokeAsync</span>(<span class="hljs-params">ActionInvocationContext context</span>)
    </span>{
        <span class="hljs-keyword" style="color: rgb(0, 0, 255);">return</span> InvokeAsyncHelper(context).AsAsyncAction();
    }

    <span class="hljs-function"><span class="hljs-keyword" style="color: rgb(0, 0, 255);">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">static</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">async</span> Task <span class="hljs-title" style="color: rgb(163, 21, 21);">InvokeAsyncHelper</span>(<span class="hljs-params">ActionInvocationContext context</span>)
    </span>{
        <span class="hljs-keyword" style="color: rgb(0, 0, 255);">string</span> result = <span class="hljs-string" style="color: rgb(163, 21, 21);">"UnknownResult"</span>;

        <span class="hljs-keyword" style="color: rgb(0, 0, 255);">if</span> (context.ActionId.StartsWith(<span class="hljs-string" style="color: rgb(163, 21, 21);">"BusinessSearchActionProvider.Actions.NameSearch"</span>, StringComparison.Ordinal))
        {
            <span class="hljs-keyword" style="color: rgb(0, 0, 255);">bool</span> found = <span class="hljs-literal" style="color: rgb(163, 21, 21);">false</span>;
            NamedActionEntity[] inputs = context.GetInputEntities();
            <span class="hljs-keyword" style="color: rgb(0, 0, 255);">foreach</span> (NamedActionEntity namedEntity <span class="hljs-keyword" style="color: rgb(0, 0, 255);">in</span> inputs)
            {
                <span class="hljs-keyword" style="color: rgb(0, 0, 255);">if</span> ((namedEntity.Name.Equals(<span class="hljs-string" style="color: rgb(163, 21, 21);">"Message"</span>) || namedEntity.Name.Equals(<span class="hljs-string" style="color: rgb(163, 21, 21);">"Contact"</span>)) &amp;&amp; namedEntity.Entity.Kind == ActionEntityKind.Text)
                {
                    found = <span class="hljs-literal" style="color: rgb(163, 21, 21);">true</span>;

                    TextActionEntity textEntity = CastToType&lt;ActionEntity, TextActionEntity&gt;(namedEntity.Entity);
                    <span class="hljs-keyword" style="color: rgb(0, 0, 255);">string</span> message = textEntity.Text;

                    <span class="hljs-keyword" style="color: rgb(0, 0, 255);">await</span> EnsureAppIsInitialized();

                    <span class="hljs-keyword" style="color: rgb(0, 0, 255);">var</span> completion = <span class="hljs-keyword" style="color: rgb(0, 0, 255);">new</span> TaskCompletionSource&lt;<span class="hljs-keyword" style="color: rgb(0, 0, 255);">string</span>&gt;();
                    App.MainWindow.DispatcherQueue.TryEnqueue(<span class="hljs-keyword" style="color: rgb(0, 0, 255);">async</span> () =&gt;
                    {
                        <span class="hljs-keyword" style="color: rgb(0, 0, 255);">var</span> messageResult = <span class="hljs-keyword" style="color: rgb(0, 0, 255);">await</span> ((App.MainWindow!.Content <span class="hljs-keyword" style="color: rgb(0, 0, 255);">as</span> Frame)!.Content <span class="hljs-keyword" style="color: rgb(0, 0, 255);">as</span> MainPage)!.AddMessageAsync(message);
                        completion.SetResult(messageResult);
                    });
                    result = <span class="hljs-keyword" style="color: rgb(0, 0, 255);">await</span> completion.Task;
                }
            }

            <span class="hljs-keyword" style="color: rgb(0, 0, 255);">if</span> (!found)
            {
                context.ExtendedError = <span class="hljs-keyword" style="color: rgb(0, 0, 255);">new</span> KeyNotFoundException();
                context.Result = ActionInvocationResult.Unsupported;
            }
        }
        <span class="hljs-keyword" style="color: rgb(0, 0, 255);">else</span>
        {
            context.ExtendedError = <span class="hljs-keyword" style="color: rgb(0, 0, 255);">new</span> NotImplementedException();
            context.Result = ActionInvocationResult.Unsupported;
        }

        ActionEntity responseEntity = context.EntityFactory.CreateTextEntity(result);
        context.SetOutputEntity(<span class="hljs-string" style="color: rgb(163, 21, 21);">"MessageCount"</span>, responseEntity);
    }

    <span class="hljs-function"><span class="hljs-keyword" style="color: rgb(0, 0, 255);">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">static</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">async</span> Task <span class="hljs-title" style="color: rgb(163, 21, 21);">EnsureAppIsInitialized</span>(<span class="hljs-params"></span>)
    </span>{
        <span class="hljs-keyword" style="color: rgb(0, 0, 255);">if</span> (App.loaded.Task.IsCompleted)
        {
            <span class="hljs-keyword" style="color: rgb(0, 0, 255);">return</span>;
        }

        <span class="hljs-keyword" style="color: rgb(0, 0, 255);">await</span> App.loaded.Task;
    }

    <span class="hljs-keyword" style="color: rgb(0, 0, 255);">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">static</span> TTo CastToType&lt;TFrom, TTo&gt;(TFrom obj)
    {
        IntPtr abiPtr = <span class="hljs-keyword" style="color: rgb(0, 0, 255);">default</span>;
        <span class="hljs-keyword" style="color: rgb(0, 0, 255);">try</span>
        {
            abiPtr = MarshalInspectable&lt;TFrom&gt;.FromManaged(obj);
            <span class="hljs-keyword" style="color: rgb(0, 0, 255);">return</span> MarshalInspectable&lt;TTo&gt;.FromAbi(abiPtr);
        }
        <span class="hljs-keyword" style="color: rgb(0, 0, 255);">finally</span>
        {
            MarshalInspectable&lt;<span class="hljs-keyword" style="color: rgb(0, 0, 255);">object</span>&gt;.DisposeAbi(abiPtr);
        }
    }
}
</pre>



<p>As you can see from this code, this relies on being able to call the AddMessageAsync on the MainPage (the current Window Content). Here&#8217;s the codebehind for MainPage:</p>



<pre class="hljs" style="display: block; overflow-x: auto; padding: 0.5em; background: rgb(255, 255, 255); color: rgb(0, 0, 0);"><span class="hljs-keyword" style="color: rgb(0, 0, 255);">using</span> System.Collections.ObjectModel;

<span class="hljs-keyword" style="color: rgb(0, 0, 255);">namespace</span> <span class="hljs-title" style="color: rgb(163, 21, 21);">BusinessSearchActionProviderApp</span>;

<span class="hljs-keyword" style="color: rgb(0, 0, 255);">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">sealed</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">partial</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">class</span> <span class="hljs-title" style="color: rgb(163, 21, 21);">MainPage</span> : <span class="hljs-title" style="color: rgb(163, 21, 21);">Page</span>
{
    <span class="hljs-function"><span class="hljs-keyword" style="color: rgb(0, 0, 255);">public</span> <span class="hljs-title" style="color: rgb(163, 21, 21);">MainPage</span>(<span class="hljs-params"></span>)
    </span>{
        <span class="hljs-keyword" style="color: rgb(0, 0, 255);">this</span>.InitializeComponent();
    }

    <span class="hljs-keyword" style="color: rgb(0, 0, 255);">private</span> ObservableCollection&lt;<span class="hljs-keyword" style="color: rgb(0, 0, 255);">string</span>&gt; Messages { <span class="hljs-keyword" style="color: rgb(0, 0, 255);">get</span>; } = <span class="hljs-keyword" style="color: rgb(0, 0, 255);">new</span> ObservableCollection&lt;<span class="hljs-keyword" style="color: rgb(0, 0, 255);">string</span>&gt;();


    <span class="hljs-function"><span class="hljs-keyword" style="color: rgb(0, 0, 255);">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">async</span> Task&lt;<span class="hljs-keyword" style="color: rgb(0, 0, 255);">string</span>&gt; <span class="hljs-title" style="color: rgb(163, 21, 21);">AddMessageAsync</span>(<span class="hljs-params"><span class="hljs-keyword" style="color: rgb(0, 0, 255);">string</span> message</span>)
    </span>{
        TaskCompletionSource&lt;<span class="hljs-keyword" style="color: rgb(0, 0, 255);">string</span>&gt; tcs = <span class="hljs-keyword" style="color: rgb(0, 0, 255);">new</span>();
        DispatcherQueue.TryEnqueue(() =&gt;
        {
            Messages.Add(message);
            tcs.SetResult(<span class="hljs-string" style="color: rgb(163, 21, 21);">"Message received"</span>);
        });

        <span class="hljs-keyword" style="color: rgb(0, 0, 255);">return</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">await</span> tcs.Task;
    }
}
</pre>



<p>And that&#8217;s it for the major components required to create and register an IActionProvider implementation to be invoked by Click to Do.</p>



<figure class="wp-block-image size-large"><img decoding="async" src="https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-687d9dc0b70e2.png" alt=""/></figure>



<p></p>



<p>Note: As at the time of writing Click to Do seems to be broken in the latest dev insider preview. With each iteration of Windows there appears to be improvements across the board, so one can only hope that Click to Do will continue to evolve and improve.</p>



<p></p>
<p>The post <a href="https://nicksnettravels.builttoroam.com/windows-ai-click-to-do/">Windows AI &#8211; Click to Do with an Uno Platform Application as an IActionProvider</a> appeared first on <a href="https://nicksnettravels.builttoroam.com">Nick&#039;s .NET Travels</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://nicksnettravels.builttoroam.com/windows-ai-click-to-do/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Installing Older Versions of Visual Studio 2022</title>
		<link>https://nicksnettravels.builttoroam.com/installing-older-versions-of-visual-studio-2022/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=installing-older-versions-of-visual-studio-2022</link>
					<comments>https://nicksnettravels.builttoroam.com/installing-older-versions-of-visual-studio-2022/#comments</comments>
		
		<dc:creator><![CDATA[Nick]]></dc:creator>
		<pubDate>Wed, 06 Aug 2025 10:09:23 +0000</pubDate>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[Hack]]></category>
		<category><![CDATA[Visual Studio]]></category>
		<category><![CDATA[Visual Studio 2022]]></category>
		<guid isPermaLink="false">https://nicksnettravels.builttoroam.com/?p=3529</guid>

					<description><![CDATA[<p>This was going to be a post about using COM Server activation in a WinAppSdk application to interact with Click to Do. However, since there&#8217;s currently a major regression in the dev channel of the Windows insider builds (reported here, here and here), which prevents Visual Studio from debugging any applications, that&#8217;ll have to wait. ... <a title="Installing Older Versions of Visual Studio 2022" class="read-more" href="https://nicksnettravels.builttoroam.com/installing-older-versions-of-visual-studio-2022/" aria-label="Read more about Installing Older Versions of Visual Studio 2022">Read more</a></p>
<p>The post <a href="https://nicksnettravels.builttoroam.com/installing-older-versions-of-visual-studio-2022/">Installing Older Versions of Visual Studio 2022</a> appeared first on <a href="https://nicksnettravels.builttoroam.com">Nick&#039;s .NET Travels</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>This was going to be a post about using COM Server activation in a WinAppSdk application to interact with Click to Do. However, since there&#8217;s currently a major regression in the dev channel of the Windows insider builds (reported <a href="https://developercommunity.visualstudio.com/t/Crashes-all-the-time-just-disappers/10945078">here</a>, <a href="https://developercommunity.visualstudio.com/t/Visual-Studio-17149-ARM64-crashes-fr/10939974?viewtype=all">here</a> and <a href="https://developercommunity.visualstudio.com/t/Visual-Studio-keeps-crashing-when-attemp/10946352?viewtype=all">here</a>), which prevents Visual Studio from debugging any applications, that&#8217;ll have to wait. Instead, I&#8217;m going to walk through the steps I cobbled together to allow me to install prior versions of Visual Studio 2022. I&#8217;m sure that there&#8217;s probably a much nicer, easier strategy for how to install previous versions of Visual Studio 2022 but I wasn&#8217;t able to find it. For prior versions of Visual Studio (ie before VS 2022), you can use <a href="https://visualstudio.microsoft.com/vs/older-downloads/">this link</a>.</p>



<p>The first thing you&#8217;re going to need is the Microsoft Update Catalog. If you follow <a href="https://www.catalog.update.microsoft.com/Search.aspx?q=visual%20studio%202022">this link</a>, you&#8217;ll end up at the catalog with &#8220;Visual Studio 2022&#8221; already entered as the search term.</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2025/08/image.png"><img loading="lazy" decoding="async" width="300" height="183" src="https://wordpressblogimages.builttoroam.com/blogimages/2025/08/image-300x183.png" alt="" class="wp-image-3530" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2025/08/image-300x183.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2025/08/image-1024x626.png 1024w, https://wordpressblogimages.builttoroam.com/blogimages/2025/08/image-768x469.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2025/08/image-1536x939.png 1536w, https://wordpressblogimages.builttoroam.com/blogimages/2025/08/image.png 1579w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>Scan the list of updates and find the version you want to install. For example, let&#8217;s install 17.14.8. Click the Download button</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2025/08/image-6893259876e92.png"><img loading="lazy" decoding="async" width="300" height="244" src="https://wordpressblogimages.builttoroam.com/blogimages/2025/08/image-6893259876e92-300x244.png" alt="" class="wp-image-3531" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2025/08/image-6893259876e92-300x244.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2025/08/image-6893259876e92-768x626.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2025/08/image-6893259876e92.png 965w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>And then click the link in order to download an executable eg <code>visualstudioupdate-17.0.0to17.14.8-online_1f22e142e483a2bdf9de7e67271627023972d13a.exe</code>.</p>



<p>Ok, the next step can be a little tricky. When you run the executable, it&#8217;s going to extract the compressed contents to the Temp folder (eg C:\Users\[Username]\AppData\Local\Temp). However, once the executable has finished executing, it will clean up this folder, so you only have a few seconds to copy the extracted folder so that you can use it in the next step. For me I&#8217;ve copied the folder to <code>C:\temp\1facaca3398aca1c021efd11ff6df750</code>.</p>



<p>In order to install the version of Visual Studio 2022 you going to execute the vs_setup.exe in the extracted folder. However, the trick is that you need to tell it the location of the ChannelManifest.json file, which is alongside the vs_setup.exe in the extracted folder. Whilst it would have been super convenient if it would automatically search that folder by default, the only way I could get it to work was to setup a network share and specify that when executing vs_setup.exe. </p>



<p>To setup a folder as a network share, right click on the folder in Windows Explorer and open Properties. Click on the Sharing tab, and click the Share button. For simplicity (not secure!!!) I just added Everyone to the access list, and then clicked Share.</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2025/08/image-68932865cdf49.png"><img loading="lazy" decoding="async" width="300" height="248" src="https://wordpressblogimages.builttoroam.com/blogimages/2025/08/image-68932865cdf49-300x248.png" alt="" class="wp-image-3532" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2025/08/image-68932865cdf49-300x248.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2025/08/image-68932865cdf49-768x636.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2025/08/image-68932865cdf49.png 883w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>Once you&#8217;ve clicked Share, you can then right click on the shared folder and select Copy Link.</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2025/08/image-6893289329072.png"><img loading="lazy" decoding="async" width="300" height="252" src="https://wordpressblogimages.builttoroam.com/blogimages/2025/08/image-6893289329072-300x252.png" alt="" class="wp-image-3533" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2025/08/image-6893289329072-300x252.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2025/08/image-6893289329072-768x644.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2025/08/image-6893289329072.png 891w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>This should give you a link in the format <code>1facaca3398aca1c021efd11ff6df750 (file://NICKINSIDERPC/1facaca3398aca1c021efd11ff6df750)</code>. You&#8217;ll need to adjust this to include the full path to the ChannelManifest.json file eg <code>\NICKINSIDERPC\1facaca3398aca1c021efd11ff6df750\VisualStudioUpdate-17.0.0To17.14.8-Online\ChannelManifest.json</code>.</p>



<p>Now we&#8217;re in a good place to run vs-setup.exe using the following command.</p>



<pre class="wp-block-preformatted">vs_setup.exe install --channelURI \NICKINSIDERPC\1facaca3398aca1c021efd11ff6df750\VisualStudioUpdate-17.0.0To17.14.8-Online\ChannelManifest.json --channelId VisualStudio.17.Release --productId Microsoft.VisualStudio.Product.Professional</pre>



<p>This should launch the Visual Studio installer directly into the screen where you can pick the workloads you want to install.</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2025/08/image-6893298f06c51.png"><img loading="lazy" decoding="async" width="300" height="169" src="https://wordpressblogimages.builttoroam.com/blogimages/2025/08/image-6893298f06c51-300x169.png" alt="" class="wp-image-3534" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2025/08/image-6893298f06c51-300x169.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2025/08/image-6893298f06c51-1024x576.png 1024w, https://wordpressblogimages.builttoroam.com/blogimages/2025/08/image-6893298f06c51-768x432.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2025/08/image-6893298f06c51-1536x864.png 1536w, https://wordpressblogimages.builttoroam.com/blogimages/2025/08/image-6893298f06c51.png 1939w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>And there, that&#8217;s it, you&#8217;ve successfully installed a previous version of Visual Studio 2022.</p>
<p>The post <a href="https://nicksnettravels.builttoroam.com/installing-older-versions-of-visual-studio-2022/">Installing Older Versions of Visual Studio 2022</a> appeared first on <a href="https://nicksnettravels.builttoroam.com">Nick&#039;s .NET Travels</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://nicksnettravels.builttoroam.com/installing-older-versions-of-visual-studio-2022/feed/</wfw:commentRss>
			<slash:comments>3</slash:comments>
		
		
			</item>
		<item>
		<title>CherylUI theme for your Uno Platform Applications</title>
		<link>https://nicksnettravels.builttoroam.com/cherylui/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=cherylui</link>
					<comments>https://nicksnettravels.builttoroam.com/cherylui/#respond</comments>
		
		<dc:creator><![CDATA[Nick]]></dc:creator>
		<pubDate>Thu, 24 Jul 2025 03:41:15 +0000</pubDate>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[CherylUI]]></category>
		<category><![CDATA[Hot Design]]></category>
		<category><![CDATA[Uno]]></category>
		<category><![CDATA[Uno Platform]]></category>
		<guid isPermaLink="false">https://nicksnettravels.builttoroam.com/?p=3517</guid>

					<description><![CDATA[<p>I&#8217;ve talked a lot in the past about how XAML applications lend themselves to being styled using data and control templates. The Uno Platform, which defaults to the Fluent theme, also supports Material, which adjusts the control templates for the in-box controls according to the Material theme from Google. In this post we&#8217;re going to ... <a title="CherylUI theme for your Uno Platform Applications" class="read-more" href="https://nicksnettravels.builttoroam.com/cherylui/" aria-label="Read more about CherylUI theme for your Uno Platform Applications">Read more</a></p>
<p>The post <a href="https://nicksnettravels.builttoroam.com/cherylui/">CherylUI theme for your Uno Platform Applications</a> appeared first on <a href="https://nicksnettravels.builttoroam.com">Nick&#039;s .NET Travels</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>I&#8217;ve talked a lot in the past about how XAML applications lend themselves to being styled using data and control templates. The <a href="https://platform.uno">Uno Platform</a>, which defaults to the Fluent theme, also supports Material, which adjusts the control templates for the in-box controls according to the Material theme from Google. In this post we&#8217;re going to look at <a href="https://github.com/kikipoulet/CherylUI.Uno">CherylUI</a>, an open source theme that you can apply to your Uno Platform application.</p>



<h2 class="wp-block-heading">Getting Started</h2>



<p>To switch your Uno Platform application across to using the CherylUI theme, there&#8217;s three things you need to do:</p>



<ol class="wp-block-list">
<li>Add a reference to the <a href="https://www.nuget.org/packages/CherylUI.Uno">CherylUI.Uno nuget package</a></li>



<li>Add the Cheryl.Uno style dictionary to your App.xaml (ie <code>&lt;ResourceDictionary Source="ms-appx:///Cheryl.Uno/Styles/Index.xaml" /></code>)</li>



<li>Add the <code>InteractiveContainer</code> to the root of your Page.</li>
</ol>



<h2 class="wp-block-heading">Hot Design Enabled</h2>



<p>Now that you&#8217;ve got the setup done, you can start to build out the UI of your application. Here&#8217;s a short video where I replace the default content of the application with the <code>InteractiveContainer</code> and then proceed to add an instance of the <code>MobileDatePicker</code>. This is all done using <a href="https://platform.uno/hot-design/">Hot Design</a>, rather than having to manually write the XAML.</p>



<figure class="wp-block-video"><video height="748" style="aspect-ratio: 1366 / 748;" width="1366" controls src="https://wordpressblogimages.builttoroam.com/blogimages/2025/07/Screen-Recording-2025-07-24-005741.mp4"></video></figure>



<p>The great thing about the CherylUI nuget package is that it not only adjusts the theme of the built in controls, it also offers a number of great controls, such as the MobileDatePicker, that you can use as you build your application. You can even check out the GitHub repository in order to see the Styles and Templates that are being used.</p>
<p>The post <a href="https://nicksnettravels.builttoroam.com/cherylui/">CherylUI theme for your Uno Platform Applications</a> appeared first on <a href="https://nicksnettravels.builttoroam.com">Nick&#039;s .NET Travels</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://nicksnettravels.builttoroam.com/cherylui/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		<enclosure length="18415190" type="video/mp4" url="https://wordpressblogimages.builttoroam.com/blogimages/2025/07/Screen-Recording-2025-07-24-005741.mp4"/>

			</item>
		<item>
		<title>Windows AI – Click to Do with an Uno Platform Application</title>
		<link>https://nicksnettravels.builttoroam.com/click-to-do-uri-protocol/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=click-to-do-uri-protocol</link>
					<comments>https://nicksnettravels.builttoroam.com/click-to-do-uri-protocol/#respond</comments>
		
		<dc:creator><![CDATA[Nick]]></dc:creator>
		<pubDate>Mon, 21 Jul 2025 02:06:35 +0000</pubDate>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[AI]]></category>
		<category><![CDATA[Click to Do]]></category>
		<category><![CDATA[Uno]]></category>
		<category><![CDATA[Uno Platform]]></category>
		<category><![CDATA[Windows]]></category>
		<guid isPermaLink="false">https://nicksnettravels.builttoroam.com/?p=3509</guid>

					<description><![CDATA[<p>With the latest generation of Copilot+ PCs, Microsoft is integrating AI deep into the core of Windows with features like Recall and Click to Do. In this post we&#8217;ll look at Click to Do and how you can use it to launch an Uno Platform application. Before we jump into our Uno Platform application, let&#8217;s ... <a title="Windows AI &#8211; Click to Do with an Uno Platform Application" class="read-more" href="https://nicksnettravels.builttoroam.com/click-to-do-uri-protocol/" aria-label="Read more about Windows AI &#8211; Click to Do with an Uno Platform Application">Read more</a></p>
<p>The post <a href="https://nicksnettravels.builttoroam.com/click-to-do-uri-protocol/">Windows AI &#8211; Click to Do with an Uno Platform Application</a> appeared first on <a href="https://nicksnettravels.builttoroam.com">Nick&#039;s .NET Travels</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>With the latest generation of <a href="https://aka.ms/copilotpluspcs">Copilot+ PCs</a>, Microsoft is integrating AI deep into the core of Windows with features like Recall and <a href="https://support.microsoft.com/en-au/windows/click-to-do-do-more-with-what-s-on-your-screen-6848b7d5-7fb0-4c43-b08a-443d6d3f5955">Click to Do</a>. In this post we&#8217;ll look at Click to Do and how you can use it to launch an Uno Platform application.</p>



<p>Before we jump into our Uno Platform application, let&#8217;s take a quick look at Click to Do. Firstly, this Windows feature is still in preview &#8211; this is very evident as I kept having to restart it whilst working with it (you can do this by launching the &#8220;Click to Do (preview)&#8221; application from the Start menu). You also currently need to be a) on a Copilot+ PC and b) on the latest dev preview of Windows (at time of writing).</p>



<p>You can launch Click to Do by holding the Start key and either pressing Q on the keyboard, or clicking with the mouse. The latter I found easiest, particularly if you&#8217;re interested in a particular image or text on the screen. As you can see in the following image, when you trigger Click to Do, Windows attempts to highlight text on the screen (including embedded in images) and then provides you a context menu of actions you can perform with the selection.</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-687d944da61a8.png"><img loading="lazy" decoding="async" width="300" height="146" src="https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-687d944da61a8-300x146.png" alt="" class="wp-image-3510" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-687d944da61a8-300x146.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-687d944da61a8-1024x497.png 1024w, https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-687d944da61a8-768x373.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-687d944da61a8-1536x746.png 1536w, https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-687d944da61a8.png 1970w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>To get started integrating your application with Click to Do, you should start with the developer documentation (<a href="https://learn.microsoft.com/en-us/windows/ai/app-actions/">overview</a>, <a href="https://learn.microsoft.com/en-us/windows/ai/app-actions/actions-json">actions registration</a>, <a href="https://learn.microsoft.com/en-us/windows/ai/app-actions/actions-provider-manifest">package manifest</a>) and understand the different types of action entities and how you can launch your application either via URI or via COM. In this post we&#8217;re going to keep it simple and register an Uno Platform application to be launched via URI.</p>



<p>One thing to note is that as Click to Do is a Windows features, you&#8217;ll need to make sure you include the Windows App SDK target when creating your Uno Platform application.</p>



<figure class="wp-block-image size-medium"><img loading="lazy" decoding="async" width="300" height="214" src="https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-687d97786deae-300x214.png" alt="" class="wp-image-3511" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-687d97786deae-300x214.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-687d97786deae-1024x731.png 1024w, https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-687d97786deae-768x548.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-687d97786deae.png 1518w" sizes="auto, (max-width: 300px) 100vw, 300px" /></figure>



<p>There are three things you need to do in order to integrate your Uno Platform application with Click to Do:</p>



<ol class="wp-block-list">
<li>Include action registration JSON file as Content in your application.</li>



<li>Register for the <code>com.microsoft.windows.ai.actions</code> extension in the packageappx.manifest, as well as setting a <code>windows.protocol</code>, the URI protocol to use to launch the application.</li>



<li>Handle the launch arguments.</li>
</ol>



<p>Let&#8217;s go through each of these.</p>



<h2 class="wp-block-heading">Actions Registration</h2>



<p>Add a new file into the Assets folder. We&#8217;ll call it <code>actions.json</code> but you can call it what you want, just make sure you use the same name later in the packagappx.manifest. In this file, include the registration for your actions, for example.</p>



<pre class="hljs" style="display: block; overflow-x: auto; padding: 0.5em; background: rgb(255, 255, 255); color: rgb(0, 0, 0);">{
  <span class="hljs-attr" style="color: red;">"version"</span>: <span class="hljs-number">1</span>,
  <span class="hljs-attr" style="color: red;">"actions"</span>: [
    {
      <span class="hljs-attr" style="color: red;">"id"</span>: <span class="hljs-string" style="color: rgb(163, 21, 21);">"BusinessSearch.UriActions.NameSearch"</span>,
      <span class="hljs-attr" style="color: red;">"description"</span>: <span class="hljs-string" style="color: rgb(163, 21, 21);">"Name search"</span>,
      <span class="hljs-attr" style="color: red;">"inputs"</span>: [
        {
          <span class="hljs-attr" style="color: red;">"name"</span>: <span class="hljs-string" style="color: rgb(163, 21, 21);">"Message"</span>,
          <span class="hljs-attr" style="color: red;">"kind"</span>: <span class="hljs-string" style="color: rgb(163, 21, 21);">"Text"</span>
        }
      ],
      <span class="hljs-attr" style="color: red;">"outputs"</span>: [],
      <span class="hljs-attr" style="color: red;">"instantiationDescription"</span>: <span class="hljs-string" style="color: rgb(163, 21, 21);">"Business Name Search: '${Message.ShortText}'"</span>,
      <span class="hljs-attr" style="color: red;">"invocation"</span>: {
        <span class="hljs-attr" style="color: red;">"type"</span>: <span class="hljs-string" style="color: rgb(163, 21, 21);">"Uri"</span>,
        <span class="hljs-attr" style="color: red;">"uri"</span>: <span class="hljs-string" style="color: rgb(163, 21, 21);">"business-search://NameSearch?name=${Message.Text}"</span>
      }
    }
  ]
}
</pre>



<p>The details for the JSON schema can found in the <a href="https://learn.microsoft.com/en-us/windows/ai/app-actions/actions-json">documentation</a> but in brief, this JSON snippet registers a single action, <code>BusinessSearch.UriActions.NameSearch</code>, that accepts a single input, Message, that is Text. The application will be invoked using a Uri, and will used the defined uri template, which provides the Message.Text as the name query string value.</p>



<h2 class="wp-block-heading">Package Manifest</h2>



<p>Simply including a JSON file as Content isn&#8217;t enough, you need to update the packagappx.manifest file to register the <code>com.microsoft.windows.ai.actions</code> extension, specifying the name of the JSON file that includes the actions to register.</p>



<p>The following packageappx.manifest has been modified to include an additional namespace, <code>uap3</code>, and an Extensions block that registers the actions extension, specifying the Actions.json file, and registers the <code>business-search</code> protocol, which will be used to launch the application. Note that this protocol aligns with the uri template specified earlier in the Actions.json</p>



<pre class="hljs" style="display: block; overflow-x: auto; padding: 0.5em; background: rgb(255, 255, 255); color: rgb(0, 0, 0);"><span class="php"><span class="hljs-meta" style="color: rgb(43, 145, 175);">&lt;?</span>xml version=<span class="hljs-string" style="color: rgb(163, 21, 21);">"1.0"</span> encoding=<span class="hljs-string" style="color: rgb(163, 21, 21);">"utf-8"</span><span class="hljs-meta" style="color: rgb(43, 145, 175);">?&gt;</span></span>
<span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">Package</span>
  <span class="hljs-attr" style="color: red;">xmlns</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"http://schemas.microsoft.com/appx/manifest/foundation/windows10"</span>
  <span class="hljs-attr" style="color: red;">xmlns:uap</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"http://schemas.microsoft.com/appx/manifest/uap/windows10"</span>
  <b><span class="hljs-attr" style="color: red;">xmlns:uap3</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"http://schemas.microsoft.com/appx/manifest/uap/windows10/3"</span></b>
  <span class="hljs-attr" style="color: red;">xmlns:rescap</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"</span>
  <span class="hljs-attr" style="color: red;">IgnorableNamespaces</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"uap rescap"</span>&gt;</span>

    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">Identity</span> /&gt;</span>
    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">Properties</span> /&gt;</span>

    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">Dependencies</span>&gt;</span>
        <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">TargetDeviceFamily</span> <span class="hljs-attr" style="color: red;">Name</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Windows.Universal"</span> <span class="hljs-attr" style="color: red;">MinVersion</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"10.0.17763.0"</span> <span class="hljs-attr" style="color: red;">MaxVersionTested</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"10.0.19041.0"</span> /&gt;</span>
        <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">TargetDeviceFamily</span> <span class="hljs-attr" style="color: red;">Name</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Windows.Desktop"</span> <span class="hljs-attr" style="color: red;">MinVersion</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"10.0.17763.0"</span> <span class="hljs-attr" style="color: red;">MaxVersionTested</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"10.0.19041.0"</span> /&gt;</span>
    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">Dependencies</span>&gt;</span>

    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">Resources</span>&gt;</span>
        <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">Resource</span> <span class="hljs-attr" style="color: red;">Language</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"x-generate"</span>/&gt;</span>
    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">Resources</span>&gt;</span>

    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">Applications</span>&gt;</span>
        <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">Application</span> <span class="hljs-attr" style="color: red;">Id</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"App"</span>
          <span class="hljs-attr" style="color: red;">Executable</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"$targetnametoken$.exe"</span>
          <span class="hljs-attr" style="color: red;">EntryPoint</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"$targetentrypoint$"</span>&gt;</span>
            <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">uap:VisualElements</span> /&gt;</span>
            <b><span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">Extensions</span>&gt;</span>
                <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">uap3:Extension</span> <span class="hljs-attr" style="color: red;">Category</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"windows.appExtension"</span>&gt;</span>
                    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">uap3:AppExtension</span>
                    <span class="hljs-attr" style="color: red;">Name</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"com.microsoft.windows.ai.actions"</span>
                    <span class="hljs-attr" style="color: red;">Id</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"BusinessSearchActions"</span>
                    <span class="hljs-attr" style="color: red;">DisplayName</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Actions for Business Search"</span>
                    <span class="hljs-attr" style="color: red;">PublicFolder</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Assets"</span>&gt;</span>
                        <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">uap3:Properties</span>&gt;</span>
                            <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">Registration</span>&gt;</span>Actions.json<span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">Registration</span>&gt;</span>
                        <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">uap3:Properties</span>&gt;</span>
                    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">uap3:AppExtension</span>&gt;</span>
                <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">uap3:Extension</span>&gt;</span>
                <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">uap:Extension</span> <span class="hljs-attr" style="color: red;">Category</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"windows.protocol"</span>&gt;</span>
                    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">uap:Protocol</span> <span class="hljs-attr" style="color: red;">Name</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"business-search"</span>/&gt;</span>
                <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">uap:Extension</span>&gt;</span>
            <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">Extensions</span>&gt;</span></b>
        <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">Application</span>&gt;</span>
    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">Applications</span>&gt;</span>

    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">Capabilities</span>&gt;</span>
        <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">rescap:Capability</span> <span class="hljs-attr" style="color: red;">Name</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"runFullTrust"</span> /&gt;</span>
    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">Capabilities</span>&gt;</span>
<span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">Package</span>&gt;</span>
</pre>



<h2 class="wp-block-heading">Application Logic</h2>



<p>In the startup logic for the application the launch arguments need to be extracted and used by the application. For the purpose of this post we&#8217;re just going to extract the query string value and pass it through to the MainPage of the application.</p>



<pre class="hljs" style="display: block; overflow-x: auto; padding: 0.5em; background: rgb(255, 255, 255); color: rgb(0, 0, 0);">    <span class="hljs-function"><span class="hljs-keyword" style="color: rgb(0, 0, 255);">protected</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">override</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">void</span> <span class="hljs-title" style="color: rgb(163, 21, 21);">OnLaunched</span>(<span class="hljs-params">Microsoft.UI.Xaml.LaunchActivatedEventArgs args</span>)
    </span>{
        <b><span class="hljs-keyword" style="color: rgb(0, 0, 255);">var</span> message = <span class="hljs-string" style="color: rgb(163, 21, 21);">""</span>;

<span class="hljs-meta" style="color: rgb(43, 145, 175);">#<span class="hljs-meta-keyword">if</span> WINDOWS</span>
        <span class="hljs-keyword" style="color: rgb(0, 0, 255);">var</span> activationArgs = Microsoft.Windows.AppLifecycle.AppInstance.GetCurrent().GetActivatedEventArgs();
        <span class="hljs-keyword" style="color: rgb(0, 0, 255);">if</span> (activationArgs.Kind == ExtendedActivationKind.Protocol)
        {
            var protocolArgs = activationArgs.Data <span class="hljs-keyword" style="color: rgb(0, 0, 255);">as</span> ProtocolActivatedEventArgs;
            <span class="hljs-keyword" style="color: rgb(0, 0, 255);">if</span> (protocolArgs != <span class="hljs-literal" style="color: rgb(163, 21, 21);">null</span>)
            {
                <span class="hljs-keyword" style="color: rgb(0, 0, 255);">var</span> query = protocolArgs.Uri.Query;
                message = query.Substring(<span class="hljs-string" style="color: rgb(163, 21, 21);">"?name="</span>.Length);
            }
        }
<span class="hljs-meta" style="color: rgb(43, 145, 175);">#<span class="hljs-meta-keyword">endif</span></span></b>

        MainWindow = <span class="hljs-keyword" style="color: rgb(0, 0, 255);">new</span> Window();
<span class="hljs-meta" style="color: rgb(43, 145, 175);">#<span class="hljs-meta-keyword">if</span> DEBUG</span>
        MainWindow.UseStudio();
<span class="hljs-meta" style="color: rgb(43, 145, 175);">#<span class="hljs-meta-keyword">endif</span></span>


        <span class="hljs-comment" style="color: green;">// Do not repeat app initialization when the Window already has content,</span>
        <span class="hljs-comment" style="color: green;">// just ensure that the window is active</span>
        <span class="hljs-keyword" style="color: rgb(0, 0, 255);">if</span> (MainWindow.Content <span class="hljs-keyword" style="color: rgb(0, 0, 255);">is</span> not Frame rootFrame)
        {
            <span class="hljs-comment" style="color: green;">// Create a Frame to act as the navigation context and navigate to the first page</span>
            rootFrame = <span class="hljs-keyword" style="color: rgb(0, 0, 255);">new</span> Frame();

            <span class="hljs-comment" style="color: green;">// Place the frame in the current Window</span>
            MainWindow.Content = rootFrame;

            rootFrame.NavigationFailed += OnNavigationFailed;
        }

        <span class="hljs-keyword" style="color: rgb(0, 0, 255);">if</span> (rootFrame.Content == <span class="hljs-literal" style="color: rgb(163, 21, 21);">null</span>)
        {
            <span class="hljs-comment" style="color: green;">// When the navigation stack isn't restored navigate to the first page,</span>
            <span class="hljs-comment" style="color: green;">// configuring the new page by passing required information as a navigation</span>
            <span class="hljs-comment" style="color: green;">// parameter</span>
            <b>rootFrame.Navigate(<span class="hljs-keyword" style="color: rgb(0, 0, 255);">typeof</span>(MainPage), message);</b>
        }

        MainWindow.SetWindowIcon();
        <span class="hljs-comment" style="color: green;">// Ensure the current window is active</span>
        MainWindow.Activate();
    }</pre>



<p>And now all we need to do is run the application for the first time in order for the actions to be registered. After running the application, you can check to confirm the actions have been registered by pressing Start and typing App Actions &#8211; there&#8217;s a new section under Settings that will appear in the Start menu. The Apps > Actions section of Settings allows you to see all registered actions, and opt in/out of them.</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-687d9f459da29.png"><img loading="lazy" decoding="async" width="300" height="191" src="https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-687d9f459da29-300x191.png" alt="" class="wp-image-3514" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-687d9f459da29-300x191.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-687d9f459da29-1024x651.png 1024w, https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-687d9f459da29-768x489.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-687d9f459da29-1536x977.png 1536w, https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-687d9f459da29.png 1888w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>With our Uno Platform application successfully registered, let&#8217;s trigger Click to Do and use it to launch the application. Here we&#8217;ve triggered Click to Do using Start + Q (Start + mouse click will work too) and have selected a block of text. At the bottom of the Click to Do context menu is our newly registered action, Business Search&#8221; </p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-687d9dc0b70e2.png"><img loading="lazy" decoding="async" width="300" height="118" src="https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-687d9dc0b70e2-300x118.png" alt="" class="wp-image-3512" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-687d9dc0b70e2-300x118.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-687d9dc0b70e2-1024x404.png 1024w, https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-687d9dc0b70e2-768x303.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-687d9dc0b70e2-1536x606.png 1536w, https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-687d9dc0b70e2.png 1734w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>Clicking the Business Search will launch the Uno Platform application, displaying the text as it&#8217;s defined in the query string value.</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-687d9e18dc6c9.png"><img loading="lazy" decoding="async" width="300" height="272" src="https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-687d9e18dc6c9-300x272.png" alt="" class="wp-image-3513" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-687d9e18dc6c9-300x272.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-687d9e18dc6c9.png 596w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>Obviously, our application should do more to process and use the provided Message.Text value.</p>



<p>In this post we&#8217;ve connected an Uno Platform application to Click to Do so that it&#8217;s launched via URI in order to take action on a specified piece of text. This is just one way you can include AI into your Uno Platform application.</p>
<p>The post <a href="https://nicksnettravels.builttoroam.com/click-to-do-uri-protocol/">Windows AI &#8211; Click to Do with an Uno Platform Application</a> appeared first on <a href="https://nicksnettravels.builttoroam.com">Nick&#039;s .NET Travels</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://nicksnettravels.builttoroam.com/click-to-do-uri-protocol/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>ChatGPT Guide to Building Cross Platform Applications</title>
		<link>https://nicksnettravels.builttoroam.com/chatgpt-guide-to-building-cross-platform-applications/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=chatgpt-guide-to-building-cross-platform-applications</link>
					<comments>https://nicksnettravels.builttoroam.com/chatgpt-guide-to-building-cross-platform-applications/#respond</comments>
		
		<dc:creator><![CDATA[Nick]]></dc:creator>
		<pubDate>Fri, 18 Jul 2025 07:24:33 +0000</pubDate>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[ChatGPT]]></category>
		<category><![CDATA[Cross-Platform]]></category>
		<category><![CDATA[Guidance]]></category>
		<category><![CDATA[Uno]]></category>
		<category><![CDATA[Uno Platform]]></category>
		<category><![CDATA[Uno Platform Studio]]></category>
		<guid isPermaLink="false">https://nicksnettravels.builttoroam.com/?p=3507</guid>

					<description><![CDATA[<p>I decided to ask ChatGPT what suggestions it had for building cross platform applications. Here&#8217;s it&#8217;s response, along with some commentary, specifically around the offering by the Uno Platform. What's the best guidance for building cross platform applications? From ChatGPT: The best guidance for building cross-platform applications can be broken into strategic decisions, tooling choices, ... <a title="ChatGPT Guide to Building Cross Platform Applications" class="read-more" href="https://nicksnettravels.builttoroam.com/chatgpt-guide-to-building-cross-platform-applications/" aria-label="Read more about ChatGPT Guide to Building Cross Platform Applications">Read more</a></p>
<p>The post <a href="https://nicksnettravels.builttoroam.com/chatgpt-guide-to-building-cross-platform-applications/">ChatGPT Guide to Building Cross Platform Applications</a> appeared first on <a href="https://nicksnettravels.builttoroam.com">Nick&#039;s .NET Travels</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>I decided to ask ChatGPT what suggestions it had for building cross platform applications. Here&#8217;s it&#8217;s response, along with some commentary, specifically around the offering by the Uno Platform.</p>



<pre class="wp-block-preformatted">What's the best guidance for building cross platform applications?</pre>



<p><strong>From ChatGPT:</strong></p>



<p>The best guidance for building cross-platform applications can be broken into <strong>strategic decisions</strong>, <strong>tooling choices</strong>, and <strong>development best practices</strong>. Here&#8217;s a comprehensive set of recommendations tailored for modern app development in 2025:</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f9ed.png" alt="🧭" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Strategic Decisions</h2>



<h3 class="wp-block-heading">1. <strong>Define “Cross-Platform” Clearly</strong></h3>



<p>Decide what platforms you actually need to support:</p>



<ul class="wp-block-list">
<li>Mobile (iOS, Android)</li>



<li>Desktop (Windows, macOS, Linux)</li>



<li>Web (browsers)</li>



<li>Embedded or smart devices?</li>
</ul>



<p>Also clarify performance, UX, and platform-specific functionality requirements. “Write once, run anywhere” often needs compromises.</p>



<pre class="wp-block-preformatted">Uno Platform enables the creation of applications that targets all of the above targets. Whether you're building for mobile, desktop, web or devices, you can build your application from a single code base with the Uno Platform.</pre>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f6e0.png" alt="🛠" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Tooling &amp; Framework Choices</h2>



<h3 class="wp-block-heading">2. <strong>Choose the Right Technology Stack</strong></h3>



<p>Each stack has trade-offs in performance, tooling, community, and long-term support:</p>



<h4 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f539.png" alt="🔹" class="wp-smiley" style="height: 1em; max-height: 1em;" /> <strong>.NET MAUI / Uno Platform</strong></h4>



<ul class="wp-block-list">
<li>Best for .NET developers</li>



<li>MAUI: Good for mobile/desktop; limited web support (via Blazor)</li>



<li>Uno Platform: Stronger web and Windows support, good for enterprise/WinUI compatibility</li>
</ul>



<h4 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f539.png" alt="🔹" class="wp-smiley" style="height: 1em; max-height: 1em;" /> <strong>Flutter</strong></h4>



<ul class="wp-block-list">
<li>Excellent native performance</li>



<li>Great UI consistency across platforms</li>



<li>Web support improving but still behind mobile</li>
</ul>



<h4 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f539.png" alt="🔹" class="wp-smiley" style="height: 1em; max-height: 1em;" /> <strong>React Native + Expo</strong></h4>



<ul class="wp-block-list">
<li>Strong JavaScript ecosystem</li>



<li>Good native module support</li>



<li>Can reuse code with React for Web</li>
</ul>



<h4 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f539.png" alt="🔹" class="wp-smiley" style="height: 1em; max-height: 1em;" /> <strong>Electron / Tauri</strong></h4>



<ul class="wp-block-list">
<li>Electron: Easy desktop apps with web tech, heavier footprint</li>



<li>Tauri: Lightweight, Rust-backed alternative, gaining traction</li>
</ul>



<h4 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f539.png" alt="🔹" class="wp-smiley" style="height: 1em; max-height: 1em;" /> <strong>Progressive Web Apps (PWAs)</strong></h4>



<ul class="wp-block-list">
<li>Great for broad reach (especially web and mobile)</li>



<li>Limited access to native APIs</li>
</ul>



<p>Choose based on:</p>



<ul class="wp-block-list">
<li>Team skills (C#, Dart, JS, etc.)</li>



<li>Performance and UX needs</li>



<li>Platform coverage</li>
</ul>



<pre class="wp-block-preformatted">Uno Platform provides developers with a variety of options when it comes to building their cross platform application. It supports developers working on Windows, MacOS or Linux, with extensions/plugins for Visual Studio, VS Code and Rider. The UI can be written in XAML or C#; there's support for both the traditional MVVM and MVUX, a more modern, MVU-based, approach to state management. </pre>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f9d1-200d-1f4bb.png" alt="🧑‍💻" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Development Best Practices</h2>



<h3 class="wp-block-heading">3. <strong>Architect for Scalability and Portability</strong></h3>



<ul class="wp-block-list">
<li>Use <strong>clean architecture</strong> with clear separation of UI, logic, and services</li>



<li>Apply <strong>MVUX</strong>, <strong>MVVM</strong>, or <strong>Redux</strong> patterns based on framework</li>



<li>Leverage <strong>dependency injection</strong> to swap platform-specific implementations</li>
</ul>



<h3 class="wp-block-heading">4. <strong>Maximize Code Sharing</strong></h3>



<ul class="wp-block-list">
<li>Share business logic and models across all platforms</li>



<li>Use abstraction layers for platform-specific services (e.g., camera, storage)</li>



<li>Use shared resources for styling/themes when possible</li>
</ul>



<h3 class="wp-block-heading">5. <strong>Build for Native UX</strong></h3>



<ul class="wp-block-list">
<li>Respect platform conventions (navigation, gestures, typography)</li>



<li>Use adaptive layout techniques</li>



<li>Provide platform-specific polish where it matters</li>
</ul>



<pre class="wp-block-preformatted">In addition to the core platform, Uno Platform offers a number of libraries that support the creation of well architected applications. Uno.Extensions leverages the Microsoft Extensions to provide feature such as Dependency Injection, Configuration, Logging and Navigation. As mentioned earlier, there's support for both MVVM (Recommending the Community Toolkit MVVM for a code generation based approach) and MVUX for state management. As the entire platform is .NET based, it makes it easy to leverage other community packages and to reuse logic across both the client application and any server logic. Lastly, unlike some of the web-based offerings, Uno Platform creates a native application that ensures high performance across all target platforms. </pre>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f50d.png" alt="🔍" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Testing &amp; Tooling</h2>



<h3 class="wp-block-heading">6. <strong>Automate Testing Across Platforms</strong></h3>



<ul class="wp-block-list">
<li>Use unit tests for core logic</li>



<li>UI automation tools (e.g., Appium, Playwright, XCUITest)</li>



<li>Use CI/CD pipelines with tools like GitHub Actions, Azure DevOps, Bitrise, etc.</li>
</ul>



<h3 class="wp-block-heading">7. <strong>Use Hot Reload / Live Preview</strong></h3>



<ul class="wp-block-list">
<li>Drastically speeds up development feedback loops</li>



<li>Available in MAUI, Uno Platform, Flutter, React Native</li>
</ul>



<pre class="wp-block-preformatted">The Uno Platform is, and will continue to be, free and open source. Recently Uno Platform Studio was released, which is a subscription based offering that's aimed at making development of Uno Platform applications even quicker and easier. The Community license includes improved Hot Reload support, whilst the Pro license includes Hot Design, a runtime designer experience that allows you to adjust the layout of your application whilst it's running. No more messing around with fake/mock data at design time; now you can see exactly how your application looks as you make changes. </pre>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f30d.png" alt="🌍" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Deployment &amp; Maintenance</h2>



<h3 class="wp-block-heading">8. <strong>Plan for Platform-Specific Deployments</strong></h3>



<ul class="wp-block-list">
<li>App Stores (Apple, Google, Microsoft)</li>



<li>Web hosting (for PWA/web builds)</li>



<li>Manage signing, updates, versioning per platform</li>
</ul>



<h3 class="wp-block-heading">9. <strong>Monitor and Analyze</strong></h3>



<ul class="wp-block-list">
<li>Use tools like App Center, Firebase, Sentry, or custom telemetry</li>



<li>Track usage and crash analytics per platform</li>
</ul>



<h3 class="wp-block-heading">10. <strong>Keep Dependencies Up-to-Date</strong></h3>



<ul class="wp-block-list">
<li>Use LTS (Long-Term Support) versions of frameworks</li>



<li>Stay on top of breaking changes across OS versions</li>
</ul>



<pre class="wp-block-preformatted">You can publish your Uno Platform application to the appropriate platform stores. There are existing .NET libraries for various monitoring and analytic tools, which can be used with an Uno Platform application. As Microsoft announces new versions of the .NET Framework, the Uno Platform is right there with near day-on-day releases to ensure you're always able to take advantage of the latest features and improvements.</pre>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f680.png" alt="🚀" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Final Thought</h2>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>The <strong>best cross-platform apps</strong> don’t just run everywhere — they <strong>feel native</strong>, perform well, and are <strong>maintainable</strong> by the team that builds them.</p>
</blockquote>



<p>If you tell me what languages you prefer, which platforms you&#8217;re targeting, or what kind of app you&#8217;re building (consumer, enterprise, internal tool), I can tailor this even more.</p>



<p></p>



<pre class="wp-block-preformatted">Ok, that's a wrap - I thought ChatGPT did a relatively good job of providing guidance for cross platform developers. Hopefully the additional information specific to the Uno Platform provided in this post will help you in the selection of your cross platform technology as you embark on your next application.</pre>



<p></p>
<p>The post <a href="https://nicksnettravels.builttoroam.com/chatgpt-guide-to-building-cross-platform-applications/">ChatGPT Guide to Building Cross Platform Applications</a> appeared first on <a href="https://nicksnettravels.builttoroam.com">Nick&#039;s .NET Travels</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://nicksnettravels.builttoroam.com/chatgpt-guide-to-building-cross-platform-applications/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Launching and Exploring Hot Design for Uno Platform</title>
		<link>https://nicksnettravels.builttoroam.com/launching-hot-design/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=launching-hot-design</link>
					<comments>https://nicksnettravels.builttoroam.com/launching-hot-design/#respond</comments>
		
		<dc:creator><![CDATA[Nick]]></dc:creator>
		<pubDate>Thu, 17 Jul 2025 09:23:48 +0000</pubDate>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[Hot Design]]></category>
		<category><![CDATA[Hot Reload]]></category>
		<category><![CDATA[Uno]]></category>
		<category><![CDATA[Uno Platform]]></category>
		<category><![CDATA[Uno Platform Studio]]></category>
		<guid isPermaLink="false">https://nicksnettravels.builttoroam.com/?p=3488</guid>

					<description><![CDATA[<p>As I discussed in my previous post the Uno Platform team have release a subscription based offering, Uno Platform Studio, which includes a runtime visual designer, Hot Design. In this post we&#8217;re going to use a new application to launch Hot Design and take a look around. The first thing to be aware of after ... <a title="Launching and Exploring Hot Design for Uno Platform" class="read-more" href="https://nicksnettravels.builttoroam.com/launching-hot-design/" aria-label="Read more about Launching and Exploring Hot Design for Uno Platform">Read more</a></p>
<p>The post <a href="https://nicksnettravels.builttoroam.com/launching-hot-design/">Launching and Exploring Hot Design for Uno Platform</a> appeared first on <a href="https://nicksnettravels.builttoroam.com">Nick&#039;s .NET Travels</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>As I discussed in my <a href="https://nicksnettravels.builttoroam.com/uno-platform-vs-uno-platform-studio/">previous post</a> the <a href="https://platform.uno">Uno Platform</a> team have release a subscription based offering, <a href="https://platform.uno/studio/">Uno Platform Studio</a>, which includes a runtime visual designer, <a href="https://platform.uno/hot-design/">Hot Design</a>. In this post we&#8217;re going to use a new application to launch Hot Design and take a look around.</p>



<p>The first thing to be aware of after creating, or even opening an existing, Uno Platform application is any Uno Check prompts that might appear. If you see one of these prompts, take a few minutes to fix any of the identified issues, to avoid countless hours wondering why you can&#8217;t build, launch, debug or publish your application.</p>



<figure class="wp-block-image size-medium is-resized"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-6878b8f80087c.png"><img loading="lazy" decoding="async" width="300" height="79" src="https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-6878b8f80087c-300x79.png" alt="" class="wp-image-3489" style="width:304px;height:auto" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-6878b8f80087c-300x79.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-6878b8f80087c-1024x270.png 1024w, https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-6878b8f80087c-768x202.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-6878b8f80087c.png 1170w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>Once you&#8217;ve fixed any issues, you can go ahead and run the application &#8211; Both the Hot Reload and Hot Design experiences work with a running application. Check out the <a href="https://platform.uno/docs/articles/studio/Hot%20Reload/hot-reload-overview.html?tabs=vswin%2Cwindows%2Cskia-desktop%2Ccommon-issues#supported-features-per-os">Hot Reload support matrix</a> to determine whether to run with or without the debugger &#8211; Hot Reload is required for Hot Design, so make sure you pick the debugging option that enables Hot Reload. </p>



<h2 class="wp-block-heading">Studio Toolbar</h2>



<p>When you launch an Uno Platform application in debug, you&#8217;ll see the Studio Toolbar, which currently includes the Hot Design (left) and Hot Reload (right) icons.</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-6878bb017b16e.png"><img loading="lazy" decoding="async" width="300" height="124" src="https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-6878bb017b16e-300x124.png" alt="" class="wp-image-3490" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-6878bb017b16e-300x124.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-6878bb017b16e.png 689w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>If instead the toolbar buttons appear with a blue dot (see below image), this means that you either don&#8217;t have an Uno Platform account, or you&#8217;re not signed into your account.</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-6878bb5d98ee5.png"><img loading="lazy" decoding="async" width="300" height="199" src="https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-6878bb5d98ee5-300x199.png" alt="" class="wp-image-3491" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-6878bb5d98ee5-300x199.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-6878bb5d98ee5.png 418w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>Clicking on either button will show a teaching tip with more information and a button to launch the Studio app, that comes with the IDE extension/plugin.</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="418" height="277" src="https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-6878bba503f9c.png" alt="" class="wp-image-3492" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-6878bba503f9c.png 418w, https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-6878bba503f9c-300x199.png 300w" sizes="auto, (max-width: 418px) 100vw, 418px" /></figure>



<p>The Studio application will appear (if it&#8217;s not visible, it may have launched behind other windows) and will give you options to register or sign in. Both options require opening the Uno Platform website and creating or signing into your account.</p>



<p>Once you&#8217;re signed in, the buttons in the Studio toolbar will automatically update, as too will the information in the Studio app.</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-6878bc23bb8d8.png"><img loading="lazy" decoding="async" width="300" height="167" src="https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-6878bc23bb8d8-300x167.png" alt="" class="wp-image-3493" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-6878bc23bb8d8-300x167.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-6878bc23bb8d8-768x426.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-6878bc23bb8d8.png 859w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<h2 class="wp-block-heading">Launching Hot Design</h2>



<p>Clicking the Hot Design button will launch the designer experience.</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-6878bc746ea4c.png"><img loading="lazy" decoding="async" width="300" height="161" src="https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-6878bc746ea4c-300x161.png" alt="" class="wp-image-3494" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-6878bc746ea4c-300x161.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-6878bc746ea4c-1024x550.png 1024w, https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-6878bc746ea4c-768x413.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-6878bc746ea4c.png 1351w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<h3 class="wp-block-heading">Toolbox</h3>



<p>In the top-left is the Toolbox, listing available controls which can be added to the application.</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-6878bc9b3f0a2.png"><img loading="lazy" decoding="async" width="300" height="161" src="https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-6878bc9b3f0a2-300x161.png" alt="" class="wp-image-3495" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-6878bc9b3f0a2-300x161.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-6878bc9b3f0a2-1024x550.png 1024w, https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-6878bc9b3f0a2-768x413.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-6878bc9b3f0a2.png 1351w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>Controls in the Toolbox can be dragged onto either the canvas (design area in the middle) or the Elements tree</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2025/07/Recording-2025-07-17-190642.gif"><img loading="lazy" decoding="async" width="300" height="161" src="https://wordpressblogimages.builttoroam.com/blogimages/2025/07/Recording-2025-07-17-190642-300x161.gif" alt="" class="wp-image-3496" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2025/07/Recording-2025-07-17-190642-300x161.gif 300w, https://wordpressblogimages.builttoroam.com/blogimages/2025/07/Recording-2025-07-17-190642-1024x551.gif 1024w, https://wordpressblogimages.builttoroam.com/blogimages/2025/07/Recording-2025-07-17-190642-768x413.gif 768w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<h3 class="wp-block-heading">Elements</h3>



<p>The Elements tree shows a hierarchical breakdown of the UI elements visible in the current Window.</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-6878be3eb9006.png"><img loading="lazy" decoding="async" width="300" height="161" src="https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-6878be3eb9006-300x161.png" alt="" class="wp-image-3499" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-6878be3eb9006-300x161.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-6878be3eb9006-1024x550.png 1024w, https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-6878be3eb9006-768x413.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-6878be3eb9006.png 1351w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>In the Elements tree existing elements can be individually, or multi, selected.</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2025/07/Recording-2025-07-17-191021.gif"><img loading="lazy" decoding="async" width="300" height="161" src="https://wordpressblogimages.builttoroam.com/blogimages/2025/07/Recording-2025-07-17-191021-300x161.gif" alt="" class="wp-image-3500" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2025/07/Recording-2025-07-17-191021-300x161.gif 300w, https://wordpressblogimages.builttoroam.com/blogimages/2025/07/Recording-2025-07-17-191021-1024x551.gif 1024w, https://wordpressblogimages.builttoroam.com/blogimages/2025/07/Recording-2025-07-17-191021-768x413.gif 768w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<h3 class="wp-block-heading">Properties</h3>



<p>With items selected (either from the Elements tree, or clicking on them in the canvas), the available properites for the selected selements is available in the Properties.</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-6878bebdc1853.png"><img loading="lazy" decoding="async" width="300" height="161" src="https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-6878bebdc1853-300x161.png" alt="" class="wp-image-3501" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-6878bebdc1853-300x161.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-6878bebdc1853-1024x550.png 1024w, https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-6878bebdc1853-768x413.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-6878bebdc1853.png 1351w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>In addition to showing the current property values, the Properties can also be used to update property values.</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2025/07/Recording-2025-07-17-191457.gif"><img loading="lazy" decoding="async" width="300" height="162" src="https://wordpressblogimages.builttoroam.com/blogimages/2025/07/Recording-2025-07-17-191457-300x162.gif" alt="" class="wp-image-3502" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2025/07/Recording-2025-07-17-191457-300x162.gif 300w, https://wordpressblogimages.builttoroam.com/blogimages/2025/07/Recording-2025-07-17-191457-1024x551.gif 1024w, https://wordpressblogimages.builttoroam.com/blogimages/2025/07/Recording-2025-07-17-191457-768x414.gif 768w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<h3 class="wp-block-heading">Studio Toolbar</h3>



<p>Once inside Hot Design, the Studio Toolbar transforms into a toolbar that assists with testing different form factors, different themes, toggling into interaction mode and performing undo/redo operations.</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-6878bf9f6e251.png"><img loading="lazy" decoding="async" width="300" height="161" src="https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-6878bf9f6e251-300x161.png" alt="" class="wp-image-3503" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-6878bf9f6e251-300x161.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-6878bf9f6e251-1024x551.png 1024w, https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-6878bf9f6e251-768x413.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-6878bf9f6e251.png 1351w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>The form factor flyout allows for adjusting the design size of the application, with predefined devices sizes and the ability to enter a custom size. The flyout can also be used to adjust the zoom applied to the design canvas.</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2025/07/Video-Project-8.gif"><img loading="lazy" decoding="async" width="300" height="169" src="https://wordpressblogimages.builttoroam.com/blogimages/2025/07/Video-Project-8-300x169.gif" alt="" class="wp-image-3504"/></a></figure>



<p>In this post we&#8217;ve touched on a few of the key tool windows that make up Hot Design. Stay tuned for more feature deep dives in the coming posts.</p>
<p>The post <a href="https://nicksnettravels.builttoroam.com/launching-hot-design/">Launching and Exploring Hot Design for Uno Platform</a> appeared first on <a href="https://nicksnettravels.builttoroam.com">Nick&#039;s .NET Travels</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://nicksnettravels.builttoroam.com/launching-hot-design/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>&#127379; Uno Platform vs &#128188; Uno Platform Studio: What’s the Difference?</title>
		<link>https://nicksnettravels.builttoroam.com/uno-platform-vs-uno-platform-studio/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=uno-platform-vs-uno-platform-studio</link>
					<comments>https://nicksnettravels.builttoroam.com/uno-platform-vs-uno-platform-studio/#respond</comments>
		
		<dc:creator><![CDATA[Nick]]></dc:creator>
		<pubDate>Wed, 16 Jul 2025 06:32:50 +0000</pubDate>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[Hot Design]]></category>
		<category><![CDATA[Uno]]></category>
		<category><![CDATA[Uno Platform]]></category>
		<category><![CDATA[Uno Platform Studio]]></category>
		<guid isPermaLink="false">https://nicksnettravels.builttoroam.com/?p=3486</guid>

					<description><![CDATA[<p>As the .NET ecosystem continues to grow and evolve, so does the need for robust tooling that helps developers build cross-platform applications faster and more efficiently. If you’ve been exploring the Uno Platform ecosystem, you may have come across two offerings: the free, open-source Uno Platform and the paid Uno Platform Studio. While they’re closely ... <a title="🆓 Uno Platform vs 💼 Uno Platform Studio: What&#8217;s the Difference?" class="read-more" href="https://nicksnettravels.builttoroam.com/uno-platform-vs-uno-platform-studio/" aria-label="Read more about 🆓 Uno Platform vs 💼 Uno Platform Studio: What&#8217;s the Difference?">Read more</a></p>
<p>The post <a href="https://nicksnettravels.builttoroam.com/uno-platform-vs-uno-platform-studio/">🆓 Uno Platform vs 💼 Uno Platform Studio: What&#8217;s the Difference?</a> appeared first on <a href="https://nicksnettravels.builttoroam.com">Nick&#039;s .NET Travels</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>As the .NET ecosystem continues to grow and evolve, so does the need for robust tooling that helps developers build cross-platform applications faster and more efficiently. If you’ve been exploring the Uno Platform ecosystem, you may have come across two offerings: the <strong>free, open-source Uno Platform</strong> and the <strong>paid Uno Platform Studio</strong>. While they’re closely related, they serve different purposes—and understanding the distinction can help you decide what’s right for your development needs.</p>



<p>Let’s break it down.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f6e0.png" alt="🛠" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Uno Platform (Free &amp; Open Source)</h2>



<p><strong>Uno Platform</strong> is an open-source project that lets you build single-codebase applications using C# and XAML across all major platforms:</p>



<ul class="wp-block-list">
<li><strong>Desktop (Windows, Linux, MacOS)</strong></li>



<li><strong>Mobile (iOS, Android)</strong></li>



<li><strong>Web (WebAssembly)</strong></li>
</ul>



<h3 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2728.png" alt="✨" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Key Features</h3>



<ul class="wp-block-list">
<li>State management options with <strong>MVUX </strong>and <strong>MVVM</strong></li>



<li><strong>XAML Hot Reload</strong></li>



<li><strong>C# Markup support</strong></li>
</ul>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>Uno Platform is completely free to use and is released under the <strong>Apache 2.0 license</strong>.</p>
</blockquote>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4bc.png" alt="💼" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Uno Platform Studio (Commercial Productivity Suite)</h2>



<p><strong>Uno Platform Studio</strong> is a paid, proprietary set of tools built on top of the Uno Platform. It’s designed to make application development faster, more visual, and more accessible—especially for design-oriented developers or teams with mixed skill sets.</p>



<h3 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2728.png" alt="✨" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Key Features</h3>



<ul class="wp-block-list">
<li><strong>Hot Design</strong>: Drag-and-drop UI designer that syncs with XAML and your app’s live preview.</li>



<li><strong>Live Property Editing</strong>: Modify properties via the property grid with real-time feedback.</li>



<li><strong>Template and Style Application</strong>: Easily apply control templates and styles visually.</li>



<li><strong>Element Tree &amp; Canvas Sync</strong>: Navigate, inspect, and modify your UI elements in real time.</li>



<li><strong>Project Scaffolding &amp; App Templates</strong>: Kickstart your app with built-in templates and patterns.</li>
</ul>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>Uno Platform Studio is a <strong>commercial offering</strong> with licensing and support options tailored for professional teams.</p>
</blockquote>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f9e9.png" alt="🧩" class="wp-smiley" style="height: 1em; max-height: 1em;" /> How They Work Together</h2>



<p>You don&#8217;t have to choose one or the other—they’re designed to be complementary:</p>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>Feature</th><th>Uno Platform (OSS)</th><th>Uno Platform Studio (Paid)</th></tr></thead><tbody><tr><td>Cross-platform runtime</td><td><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /></td><td><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /></td></tr><tr><td>XAML/C# app development</td><td><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /></td><td><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /></td></tr><tr><td>Drag-and-drop designer</td><td><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/274c.png" alt="❌" class="wp-smiley" style="height: 1em; max-height: 1em;" /></td><td><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /></td></tr><tr><td>Property Grid</td><td><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/274c.png" alt="❌" class="wp-smiley" style="height: 1em; max-height: 1em;" /></td><td><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /></td></tr><tr><td>Visual template editing</td><td><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/274c.png" alt="❌" class="wp-smiley" style="height: 1em; max-height: 1em;" /></td><td><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /></td></tr><tr><td>Cost</td><td>Free</td><td>Subscription-based</td></tr></tbody></table></figure>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f3af.png" alt="🎯" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Which One Should You Use?</h2>



<ul class="wp-block-list">
<li><strong>Start with Uno Platform</strong> if you’re a developer who wants to build cross-platform apps with full control over your stack.</li>



<li><strong>Add Uno Platform Studio</strong> if you want to speed up development with visual tools, streamline styling and layout, or improve collaboration across your team.</li>
</ul>



<p>Whether you&#8217;re prototyping or shipping production-ready apps, Uno Platform Studio builds on the power of Uno Platform to help you <strong>move faster, design better, and build smarter.</strong></p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f517.png" alt="🔗" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Learn More</h2>



<ul class="wp-block-list">
<li><a href="https://github.com/unoplatform/uno">Explore Uno Platform on GitHub</a></li>



<li><a href="https://platform.uno/studio">Try Uno Platform Studio</a></li>



<li><a href="https://platform.uno/docs">Read the Documentation</a></li>
</ul>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<p></p>
<p>The post <a href="https://nicksnettravels.builttoroam.com/uno-platform-vs-uno-platform-studio/">🆓 Uno Platform vs 💼 Uno Platform Studio: What&#8217;s the Difference?</a> appeared first on <a href="https://nicksnettravels.builttoroam.com">Nick&#039;s .NET Travels</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://nicksnettravels.builttoroam.com/uno-platform-vs-uno-platform-studio/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>How to do Validation in Windows and Uno Platform Applications – the Easy Way</title>
		<link>https://nicksnettravels.builttoroam.com/winui-validation/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=winui-validation</link>
					<comments>https://nicksnettravels.builttoroam.com/winui-validation/#respond</comments>
		
		<dc:creator><![CDATA[Nick]]></dc:creator>
		<pubDate>Mon, 14 Jul 2025 04:57:44 +0000</pubDate>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[Uno]]></category>
		<category><![CDATA[Uno Platform]]></category>
		<category><![CDATA[Validation]]></category>
		<category><![CDATA[Windows]]></category>
		<category><![CDATA[XAML]]></category>
		<guid isPermaLink="false">https://nicksnettravels.builttoroam.com/?p=3480</guid>

					<description><![CDATA[<p>Quite often I hear the complaint that WinUI, and thus Uno Platform, doesn&#8217;t include validation. There was some evidence a while ago that it was being worked on by the WinUI team (ie commented out validation XAML in the WinUI styles), but there doesn&#8217;t seem to be any more progress in this area, despite a ... <a title="How to do Validation in Windows and Uno Platform Applications &#8211; the Easy Way" class="read-more" href="https://nicksnettravels.builttoroam.com/winui-validation/" aria-label="Read more about How to do Validation in Windows and Uno Platform Applications &#8211; the Easy Way">Read more</a></p>
<p>The post <a href="https://nicksnettravels.builttoroam.com/winui-validation/">How to do Validation in Windows and Uno Platform Applications &#8211; the Easy Way</a> appeared first on <a href="https://nicksnettravels.builttoroam.com">Nick&#039;s .NET Travels</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>Quite often I hear the complaint that WinUI, and thus Uno Platform, doesn&#8217;t include validation. There was some evidence a while ago that it was being worked on by the WinUI team (ie commented out validation XAML in the WinUI styles), but there doesn&#8217;t seem to be any more progress in this area, despite a lot of enterprise customers claiming it to be a core requirement. I&#8217;ve often thought the lack of built in support for validation was a weird requirement when selecting a technology because in XAML it&#8217;s so easy to add it in. In this post I&#8217;m going to cover a simple way that you can add validation to any control by changing the control template and adding a single attached property.</p>



<h2 class="wp-block-heading">Lack of Visual States</h2>



<p>If we consider that validation of an input control, such as a TextBox, is basically a visual state, then the control can either being in a ValidState, or an InvalidState. As WinUI controls don&#8217;t have these as built in states, we&#8217;re going to have to create them. Luckily XAML was built to support the ad-hoc addition of visual states. Since validation is mutually exclusive to any other built in state, such as disabled or focused, the validation state should exist in their own state group. </p>



<p>In order to add the validation states, we&#8217;re going to clone the <a href="https://github.com/unoplatform/uno/blob/b5651bedb72d41a971994c4fbb7b26e019708f30/src/Uno.UI.FluentTheme.v2/Resources/Version2/Priority02/TextBox_themeresources.xaml#L186">DefaultTextBoxStyle</a> into our application. Note that we&#8217;ll use the BasedOn attribute so that we only need to include the Setter for the Template, rather than the other default property values. I&#8217;ve omitted unmodified parts of the original style for brevity.</p>



<pre class="hljs" style="display: block; overflow-x: auto; padding: 0.5em; background: rgb(255, 255, 255); color: rgb(0, 0, 0);"><span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">ResourceDictionary.ThemeDictionaries</span>&gt;</span>
    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">ResourceDictionary</span> <span class="hljs-attr" style="color: red;">x:Key</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Default"</span>&gt;</span>
        <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">SolidColorBrush</span> <span class="hljs-attr" style="color: red;">x:Key</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"ValidationErrorBorderBrush"</span> <span class="hljs-attr" style="color: red;">Color</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"#FFB00020"</span> /&gt;</span>
    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">ResourceDictionary</span>&gt;</span>
    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">ResourceDictionary</span> <span class="hljs-attr" style="color: red;">x:Key</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Light"</span>&gt;</span>
        <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">SolidColorBrush</span> <span class="hljs-attr" style="color: red;">x:Key</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"ValidationErrorBorderBrush"</span> <span class="hljs-attr" style="color: red;">Color</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"#FFB00020"</span> /&gt;</span>
    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">ResourceDictionary</span>&gt;</span>
<span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">ResourceDictionary.ThemeDictionaries</span>&gt;</span>

<span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">Style</span> <span class="hljs-attr" style="color: red;">x:Key</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"ValidationTextBoxStyle"</span>
        <span class="hljs-attr" style="color: red;">TargetType</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"TextBox"</span>
        <span class="hljs-attr" style="color: red;">BasedOn</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"{StaticResource DefaultTextBoxStyle}"</span>&gt;</span><span class="xml">
    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">Setter</span> <span class="hljs-attr" style="color: red;">Property</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Template"</span>&gt;</span>
        <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">Setter.Value</span>&gt;</span>
            <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">ControlTemplate</span> <span class="hljs-attr" style="color: red;">TargetType</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"TextBox"</span>&gt;</span>
                <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">Grid</span>&gt;</span>
                    ...
                    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">VisualStateManager.VisualStateGroups</span>&gt;</span>
                        ...
                        <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">VisualStateGroup</span> <span class="hljs-attr" style="color: red;">x:Name</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"ValidationStates"</span>&gt;</span>
                            <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">VisualState</span> <span class="hljs-attr" style="color: red;">x:Name</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"ValidState"</span> /&gt;</span>
                            <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">VisualState</span> <span class="hljs-attr" style="color: red;">x:Name</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"InvalidState"</span>&gt;</span>
                                <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">VisualState.Setters</span>&gt;</span>
                                    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">Setter</span> <span class="hljs-attr" style="color: red;">Target</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"ValidationBorder.Visibility"</span> <span class="hljs-attr" style="color: red;">Value</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Visible"</span> /&gt;</span>
                                <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">VisualState.Setters</span>&gt;</span>
                            <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">VisualState</span>&gt;</span>
                        <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">VisualStateGroup</span>&gt;</span>
                    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">VisualStateManager.VisualStateGroups</span>&gt;</span>
                    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">Grid.RowDefinitions</span>&gt;</span>
                        <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">RowDefinition</span> <span class="hljs-attr" style="color: red;">Height</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Auto"</span> /&gt;</span>
                        <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">RowDefinition</span> <span class="hljs-attr" style="color: red;">Height</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"*"</span> /&gt;</span>
                        <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">RowDefinition</span> <span class="hljs-attr" style="color: red;">Height</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Auto"</span> /&gt;</span>
                        <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">RowDefinition</span> <span class="hljs-attr" style="color: red;">Height</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Auto"</span> /&gt;</span>
                    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">Grid.RowDefinitions</span>&gt;</span>
                    ...
                    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">Border</span> <span class="hljs-attr" style="color: red;">x:Name</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"ValidationBorder"</span>
                            <span class="hljs-attr" style="color: red;">Grid.Row</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"3"</span> <span class="hljs-attr" style="color: red;">Grid.ColumnSpan</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"2"</span>
                            <span class="hljs-attr" style="color: red;">Background</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"{ThemeResource ValidationErrorBorderBrush}"</span>
                            <span class="hljs-attr" style="color: red;">Height</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"2"</span> <span class="hljs-attr" style="color: red;">Margin</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"0,-2,0,0"</span>
                            <span class="hljs-attr" style="color: red;">Visibility</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Collapsed"</span> /&gt;</span>
                <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">Grid</span>&gt;</span>
            <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">ControlTemplate</span>&gt;</span>
        <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">Setter.Value</span>&gt;</span>
    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">Setter</span>&gt;</span>
</span><span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">Style</span>&gt;</span>

<span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">Style</span> <span class="hljs-attr" style="color: red;">TargetType</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"TextBox"</span> <span class="hljs-attr" style="color: red;">BasedOn</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"{StaticResource ValidationTextBoxStyle}"</span> /&gt;</span><span class="undefined">
</span></pre>



<p>What you can see here is that there&#8217;s an additional border that appears under the TextBox in order to indicate validation state. The border is made visible by the InvalidState visual states.</p>



<h2 class="wp-block-heading">IsValid Attached Property</h2>



<p>Since the implementation of the TextBox doesn&#8217;t know about the ValidState or InvalidState visual states, we&#8217;re going to have to invoke the state change using the <code>VisualStateManager.GoToState</code> method. For this, we&#8217;re going to use an attached property (as an aside, the entire code for this attached property was created, without modification, by Copilot in agent mode with Claud Sonnet 4).</p>



<pre class="hljs" style="display: block; overflow-x: auto; padding: 0.5em; background: rgb(255, 255, 255); color: rgb(0, 0, 0);"><span class="hljs-comment" style="color: green;"><span class="hljs-doctag" style="color: grey;">///</span> <span class="hljs-doctag" style="color: grey;">&lt;summary&gt;</span></span>
<span class="hljs-comment" style="color: green;"><span class="hljs-doctag" style="color: grey;">///</span> Attached properties for validation state management</span>
<span class="hljs-comment" style="color: green;"><span class="hljs-doctag" style="color: grey;">///</span> <span class="hljs-doctag" style="color: grey;">&lt;/summary&gt;</span></span>
<span class="hljs-keyword" style="color: rgb(0, 0, 255);">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">static</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">class</span> <span class="hljs-title" style="color: rgb(163, 21, 21);">ValidationProperties</span>
{
    <span class="hljs-comment" style="color: green;"><span class="hljs-doctag" style="color: grey;">///</span> <span class="hljs-doctag" style="color: grey;">&lt;summary&gt;</span></span>
    <span class="hljs-comment" style="color: green;"><span class="hljs-doctag" style="color: grey;">///</span> IsValid attached property that manages visual states</span>
    <span class="hljs-comment" style="color: green;"><span class="hljs-doctag" style="color: grey;">///</span> <span class="hljs-doctag" style="color: grey;">&lt;/summary&gt;</span></span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 255);">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">static</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">readonly</span> DependencyProperty IsValidProperty =
        DependencyProperty.RegisterAttached(
            <span class="hljs-string" style="color: rgb(163, 21, 21);">"IsValid"</span>,
            <span class="hljs-keyword" style="color: rgb(0, 0, 255);">typeof</span>(<span class="hljs-keyword" style="color: rgb(0, 0, 255);">bool</span>),
            <span class="hljs-keyword" style="color: rgb(0, 0, 255);">typeof</span>(ValidationProperties),
            <span class="hljs-keyword" style="color: rgb(0, 0, 255);">new</span> PropertyMetadata(<span class="hljs-literal" style="color: rgb(163, 21, 21);">true</span>, OnIsValidChanged));

    <span class="hljs-comment" style="color: green;"><span class="hljs-doctag" style="color: grey;">///</span> <span class="hljs-doctag" style="color: grey;">&lt;summary&gt;</span></span>
    <span class="hljs-comment" style="color: green;"><span class="hljs-doctag" style="color: grey;">///</span> Gets the IsValid property value</span>
    <span class="hljs-comment" style="color: green;"><span class="hljs-doctag" style="color: grey;">///</span> <span class="hljs-doctag" style="color: grey;">&lt;/summary&gt;</span></span>
    <span class="hljs-comment" style="color: green;"><span class="hljs-doctag" style="color: grey;">///</span> <span class="hljs-doctag" style="color: grey;">&lt;param name="obj"&gt;</span>The target object<span class="hljs-doctag" style="color: grey;">&lt;/param&gt;</span></span>
    <span class="hljs-comment" style="color: green;"><span class="hljs-doctag" style="color: grey;">///</span> <span class="hljs-doctag" style="color: grey;">&lt;returns&gt;</span>The IsValid value<span class="hljs-doctag" style="color: grey;">&lt;/returns&gt;</span></span>
    <span class="hljs-function"><span class="hljs-keyword" style="color: rgb(0, 0, 255);">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">static</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">bool</span> <span class="hljs-title" style="color: rgb(163, 21, 21);">GetIsValid</span>(<span class="hljs-params">DependencyObject obj</span>)
    </span>{
        <span class="hljs-keyword" style="color: rgb(0, 0, 255);">return</span> (<span class="hljs-keyword" style="color: rgb(0, 0, 255);">bool</span>)obj.GetValue(IsValidProperty);
    }

    <span class="hljs-comment" style="color: green;"><span class="hljs-doctag" style="color: grey;">///</span> <span class="hljs-doctag" style="color: grey;">&lt;summary&gt;</span></span>
    <span class="hljs-comment" style="color: green;"><span class="hljs-doctag" style="color: grey;">///</span> Sets the IsValid property value</span>
    <span class="hljs-comment" style="color: green;"><span class="hljs-doctag" style="color: grey;">///</span> <span class="hljs-doctag" style="color: grey;">&lt;/summary&gt;</span></span>
    <span class="hljs-comment" style="color: green;"><span class="hljs-doctag" style="color: grey;">///</span> <span class="hljs-doctag" style="color: grey;">&lt;param name="obj"&gt;</span>The target object<span class="hljs-doctag" style="color: grey;">&lt;/param&gt;</span></span>
    <span class="hljs-comment" style="color: green;"><span class="hljs-doctag" style="color: grey;">///</span> <span class="hljs-doctag" style="color: grey;">&lt;param name="value"&gt;</span>The IsValid value<span class="hljs-doctag" style="color: grey;">&lt;/param&gt;</span></span>
    <span class="hljs-function"><span class="hljs-keyword" style="color: rgb(0, 0, 255);">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">static</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">void</span> <span class="hljs-title" style="color: rgb(163, 21, 21);">SetIsValid</span>(<span class="hljs-params">DependencyObject obj, <span class="hljs-keyword" style="color: rgb(0, 0, 255);">bool</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">value</span></span>)
    </span>{
        obj.SetValue(IsValidProperty, <span class="hljs-keyword" style="color: rgb(0, 0, 255);">value</span>);
    }

    <span class="hljs-comment" style="color: green;"><span class="hljs-doctag" style="color: grey;">///</span> <span class="hljs-doctag" style="color: grey;">&lt;summary&gt;</span></span>
    <span class="hljs-comment" style="color: green;"><span class="hljs-doctag" style="color: grey;">///</span> Handles the IsValid property changed event</span>
    <span class="hljs-comment" style="color: green;"><span class="hljs-doctag" style="color: grey;">///</span> <span class="hljs-doctag" style="color: grey;">&lt;/summary&gt;</span></span>
    <span class="hljs-comment" style="color: green;"><span class="hljs-doctag" style="color: grey;">///</span> <span class="hljs-doctag" style="color: grey;">&lt;param name="d"&gt;</span>The dependency object<span class="hljs-doctag" style="color: grey;">&lt;/param&gt;</span></span>
    <span class="hljs-comment" style="color: green;"><span class="hljs-doctag" style="color: grey;">///</span> <span class="hljs-doctag" style="color: grey;">&lt;param name="e"&gt;</span>The event args<span class="hljs-doctag" style="color: grey;">&lt;/param&gt;</span></span>
    <span class="hljs-function"><span class="hljs-keyword" style="color: rgb(0, 0, 255);">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">static</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">void</span> <span class="hljs-title" style="color: rgb(163, 21, 21);">OnIsValidChanged</span>(<span class="hljs-params">DependencyObject d, DependencyPropertyChangedEventArgs e</span>)
    </span>{
        <span class="hljs-keyword" style="color: rgb(0, 0, 255);">if</span> (d <span class="hljs-keyword" style="color: rgb(0, 0, 255);">is</span> Control control)
        {
            <span class="hljs-keyword" style="color: rgb(0, 0, 255);">bool</span> isValid = (<span class="hljs-keyword" style="color: rgb(0, 0, 255);">bool</span>)e.NewValue;
            <span class="hljs-keyword" style="color: rgb(0, 0, 255);">string</span> stateName = isValid ? <span class="hljs-string" style="color: rgb(163, 21, 21);">"ValidState"</span> : <span class="hljs-string" style="color: rgb(163, 21, 21);">"InvalidState"</span>;
            
            VisualStateManager.GoToState(control, stateName, <span class="hljs-literal" style="color: rgb(163, 21, 21);">true</span>);
        }
    }
}</pre>



<p>We can apply this to our TextBox:</p>



<pre class="hljs" style="display: block; overflow-x: auto; padding: 0.5em; background: rgb(255, 255, 255); color: rgb(0, 0, 0);">xmlns:validation="using:ValidationSampleApp.AttachedProperties"

<span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">TextBox</span> <span class="hljs-attr" style="color: red;">Text</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"{Binding Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"</span>
            <span class="hljs-attr" style="color: red;">PlaceholderText</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Enter your name:"</span>
            <span class="hljs-attr" style="color: red;">validation:ValidationProperties.IsValid</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"{Binding NameIsValid}"</span> /&gt;</span></pre>



<p>And of course, we&#8217;ll need to update our ViewModel to expose the <code>NameIsValid</code> property.</p>



<pre class="hljs" style="display: block; overflow-x: auto; padding: 0.5em; background: rgb(255, 255, 255); color: rgb(0, 0, 0);"><span class="hljs-keyword" style="color: rgb(0, 0, 255);">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">partial</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">class</span> <span class="hljs-title" style="color: rgb(163, 21, 21);">MainViewModel</span> : <span class="hljs-title" style="color: rgb(163, 21, 21);">ObservableObject</span>
{
    [ObservableProperty]
    [NotifyPropertyChangedFor(<span class="hljs-keyword" style="color: rgb(0, 0, 255);">nameof</span>(NameIsValid))]
    <span class="hljs-keyword" style="color: rgb(0, 0, 255);">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">string</span>? name;

    <span class="hljs-keyword" style="color: rgb(0, 0, 255);">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">bool</span> NameIsValid =&gt; Name <span class="hljs-keyword" style="color: rgb(0, 0, 255);">is</span> { Length: &gt; <span class="hljs-number">0</span> };
</pre>



<p>(and yes, before all you smart people out there decide to comment that this is using MVVM, despite my &#8220;<a href="https://nicksnettravels.builttoroam.com/stop-using-mvvm/">Stop using MVVM</a>&#8221; post, you&#8217;re 100% right, this is MVVM. The same mechanism will work nicely with MVUX, or any other framework you use, so long as you have a mechanism to trigger the state change between ValidState and InvalidState).</p>



<p>Ok, so now let&#8217;s see this in action.</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2025/07/Recording-2025-07-14-145404.gif"><img loading="lazy" decoding="async" width="300" height="246" src="https://wordpressblogimages.builttoroam.com/blogimages/2025/07/Recording-2025-07-14-145404-300x246.gif" alt="" class="wp-image-3481"/></a></figure>



<p>As you can see, this is an incredibly simple way to add validation to your application. It requires modifying the control template for each control where you want to add validation. However, once you&#8217;ve done it once, you can set it to be the default style (which is what we did in the last line of the earlier XAML) and it will be available everywhere, even if you don&#8217;t need validation on a particular instance of the control.</p>
<p>The post <a href="https://nicksnettravels.builttoroam.com/winui-validation/">How to do Validation in Windows and Uno Platform Applications &#8211; the Easy Way</a> appeared first on <a href="https://nicksnettravels.builttoroam.com">Nick&#039;s .NET Travels</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://nicksnettravels.builttoroam.com/winui-validation/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Stop Using MVVM</title>
		<link>https://nicksnettravels.builttoroam.com/stop-using-mvvm/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=stop-using-mvvm</link>
					<comments>https://nicksnettravels.builttoroam.com/stop-using-mvvm/#comments</comments>
		
		<dc:creator><![CDATA[Nick]]></dc:creator>
		<pubDate>Sun, 13 Jul 2025 18:47:06 +0000</pubDate>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[Guidance]]></category>
		<category><![CDATA[MVUX]]></category>
		<category><![CDATA[MVVM]]></category>
		<category><![CDATA[Patterns]]></category>
		<guid isPermaLink="false">https://nicksnettravels.builttoroam.com/?p=3476</guid>

					<description><![CDATA[<p>The Model-View-ViewModel (MVVM) pattern has long been a cornerstone in building maintainable and testable UIs across frameworks like WPF, Xamarin, Uno Platform, and others. It provides a clean separation of concerns and enables powerful data binding. But despite its popularity and maturity, MVVM often introduces unnecessary complexity and friction—particularly when it comes to state management ... <a title="Stop Using MVVM" class="read-more" href="https://nicksnettravels.builttoroam.com/stop-using-mvvm/" aria-label="Read more about Stop Using MVVM">Read more</a></p>
<p>The post <a href="https://nicksnettravels.builttoroam.com/stop-using-mvvm/">Stop Using MVVM</a> appeared first on <a href="https://nicksnettravels.builttoroam.com">Nick&#039;s .NET Travels</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>The Model-View-ViewModel (MVVM) pattern has long been a cornerstone in building maintainable and testable UIs across frameworks like WPF, Xamarin, Uno Platform, and others. It provides a clean separation of concerns and enables powerful data binding. But despite its popularity and maturity, MVVM often introduces unnecessary complexity and friction—particularly when it comes to state management and event-driven UI updates.</p>



<p>Enter <strong>MVUX</strong>—a modern, state-driven evolution of MVVM inspired by unidirectional data flow architectures like Redux. MVUX simplifies UI development by shifting the focus from object binding and manual state tracking to declarative, immutable state and reactive updates. Let’s explore why developers should consider moving from MVVM to MVUX.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f9ed.png" alt="🧭" class="wp-smiley" style="height: 1em; max-height: 1em;" /> A Quick Overview of MVVM</h2>



<p>MVVM is composed of three main components:</p>



<ul class="wp-block-list">
<li><strong>Model</strong>: Represents the domain data or business logic.</li>



<li><strong>View</strong>: The UI layer (XAML, HTML, etc.).</li>



<li><strong>ViewModel</strong>: The intermediary that exposes data and commands for the View.</li>
</ul>



<p>The View binds to the ViewModel using data binding (e.g., <code>INotifyPropertyChanged</code> in .NET). Commands are typically exposed as <code>ICommand</code> implementations for interaction handling.</p>



<h3 class="wp-block-heading">Benefits of MVVM:</h3>



<ul class="wp-block-list">
<li>Clear separation of UI and logic.</li>



<li>Enables testing without a UI.</li>



<li>Promotes reuse and abstraction.</li>
</ul>



<p>But for all its benefits, MVVM has its share of pain points.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f9f1.png" alt="🧱" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Limitations of MVVM</h2>



<h3 class="wp-block-heading">1. <strong>Boilerplate and Verbosity</strong></h3>



<p>MVVM often requires a lot of boilerplate: implementing <code>INotifyPropertyChanged</code>, managing backing fields, writing <code>RelayCommand</code>s or <code>DelegateCommand</code>s, etc.</p>



<pre class="wp-block-preformatted">csharpCopyEdit<code>private string _name;
public string Name
{
    get =&gt; _name;
    set
    {
        _name = value;
        OnPropertyChanged();
    }
}
</code></pre>



<p>This is repeated across most ViewModels, inflating code and reducing developer productivity.</p>



<h3 class="wp-block-heading">2. <strong>State Synchronization is Hard</strong></h3>



<p>In MVVM, state is often distributed across multiple properties and can become difficult to track, especially in complex UIs. There’s no single source of truth for UI state.</p>



<h3 class="wp-block-heading">3. <strong>Command Explosion</strong></h3>



<p>Every user interaction typically requires a dedicated command. This leads to an explosion of <code>ICommand</code> implementations or lambdas, often with overlapping responsibilities.</p>



<h3 class="wp-block-heading">4. <strong>Implicit Flow and Debugging Difficulty</strong></h3>



<p>MVVM relies on implicit bindings between View and ViewModel. When things go wrong, debugging a broken binding or a misfired command can be a frustrating experience.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f680.png" alt="🚀" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Introducing MVUX: A Better Way</h2>



<p><strong>MVUX</strong> (Model-View-Update-eXtended) is a modern take on state-driven UI development. It&#8217;s designed to reduce boilerplate, centralize state, and embrace unidirectional data flow with immutable updates—leading to simpler, more maintainable, and predictable UIs.</p>



<h3 class="wp-block-heading">MVUX Core Concepts:</h3>



<ul class="wp-block-list">
<li><strong>State</strong>: A single immutable object representing the UI state.</li>



<li><strong>Reducers</strong>: Pure functions that return new state based on an input and the current state.</li>



<li><strong>Effects</strong>: Handle asynchronous operations like API calls or side-effects.</li>



<li><strong>View</strong>: Declaratively renders UI based on the current state.</li>
</ul>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f9ea.png" alt="🧪" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Side-by-Side Example: Business Search</h2>



<p>Application includes a service that exposes a SearchAsync method.</p>



<pre class="hljs" style="display: block; overflow-x: auto; padding: 0.5em; background: rgb(255, 255, 255); color: rgb(0, 0, 0);"><span class="hljs-keyword" style="color: rgb(0, 0, 255);">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">interface</span> <span class="hljs-title" style="color: rgb(163, 21, 21);">IAbnLookupService</span>
{
   ValueTask&lt;IImmutableList&lt;BusinessResult&gt;&gt; SearchAsync(<span class="hljs-keyword" style="color: rgb(0, 0, 255);">string</span> name, CancellationToken cancellationToken = <span class="hljs-keyword" style="color: rgb(0, 0, 255);">default</span>);
}</pre>



<p>The MainPage of the application includes a TextBox where the user can enter a business name or ABN, and a ListView that displays the search results. Here is the MainViewModel as defined using MVVM (<a href="https://learn.microsoft.com/en-us/dotnet/communitytoolkit/mvvm/">MVVM Toolkit</a>).</p>



<pre class="hljs" style="display: block; overflow-x: auto; padding: 0.5em; background: rgb(255, 255, 255); color: rgb(0, 0, 0);"><span class="hljs-keyword" style="color: rgb(0, 0, 255);">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">partial</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">class</span> <span class="hljs-title" style="color: rgb(163, 21, 21);">MainViewModel</span> : <span class="hljs-title" style="color: rgb(163, 21, 21);">ObservableObject</span>
{
    <span class="hljs-keyword" style="color: rgb(0, 0, 255);">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">readonly</span> IAbnLookupService _abnLookupService;

    [ObservableProperty]
    <span class="hljs-keyword" style="color: rgb(0, 0, 255);">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">string</span> _searchText = <span class="hljs-keyword" style="color: rgb(0, 0, 255);">string</span>.Empty;
    <span class="hljs-keyword" style="color: rgb(0, 0, 255);">public</span> ObservableCollection&lt;BusinessResult&gt; SearchResults { <span class="hljs-keyword" style="color: rgb(0, 0, 255);">get</span>; }

    [ObservableProperty]
    [NotifyPropertyChangedFor(<span class="hljs-keyword" style="color: rgb(0, 0, 255);">nameof</span>(CanSearch), <span class="hljs-keyword" style="color: rgb(0, 0, 255);">nameof</span>(SearchButtonText))]
    [NotifyCanExecuteChangedFor(<span class="hljs-keyword" style="color: rgb(0, 0, 255);">nameof</span>(SearchCommand))]
    <span class="hljs-keyword" style="color: rgb(0, 0, 255);">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">bool</span> _isSearching = <span class="hljs-literal" style="color: rgb(163, 21, 21);">false</span>;
    <span class="hljs-keyword" style="color: rgb(0, 0, 255);">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">bool</span> CanSearch =&gt; !IsSearching;

    <span class="hljs-keyword" style="color: rgb(0, 0, 255);">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">string</span> SearchButtonText =&gt; IsSearching ? <span class="hljs-string" style="color: rgb(163, 21, 21);">"Searching..."</span> : <span class="hljs-string" style="color: rgb(163, 21, 21);">"Search"</span>;

    [RelayCommand]
    <span class="hljs-function"><span class="hljs-keyword" style="color: rgb(0, 0, 255);">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">async</span> Task <span class="hljs-title" style="color: rgb(163, 21, 21);">HandleEnterKeyAsync</span>(<span class="hljs-params"></span>)
    </span>{
        <span class="hljs-keyword" style="color: rgb(0, 0, 255);">if</span> (CanSearch)
        {
            <span class="hljs-keyword" style="color: rgb(0, 0, 255);">await</span> SearchAsync();
        }
    }

    <span class="hljs-function"><span class="hljs-keyword" style="color: rgb(0, 0, 255);">public</span> <span class="hljs-title" style="color: rgb(163, 21, 21);">MainViewModel</span>(<span class="hljs-params">IAbnLookupService abnLookupService</span>)
    </span>{
        _abnLookupService = abnLookupService;
        SearchResults = <span class="hljs-keyword" style="color: rgb(0, 0, 255);">new</span> ObservableCollection&lt;BusinessResult&gt;();
    }

    [RelayCommand(CanExecute = <span class="hljs-keyword" style="color: rgb(0, 0, 255);">nameof</span>(CanSearch))]
    <span class="hljs-function"><span class="hljs-keyword" style="color: rgb(0, 0, 255);">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">async</span> Task <span class="hljs-title" style="color: rgb(163, 21, 21);">SearchAsync</span>(<span class="hljs-params"></span>)
    </span>{
        <span class="hljs-keyword" style="color: rgb(0, 0, 255);">var</span> searchTerm = SearchText?.Trim();

        SearchResults.Clear();

        <span class="hljs-keyword" style="color: rgb(0, 0, 255);">if</span> (<span class="hljs-keyword" style="color: rgb(0, 0, 255);">string</span>.IsNullOrEmpty(searchTerm))
        {
            <span class="hljs-keyword" style="color: rgb(0, 0, 255);">return</span>;
        }

        <span class="hljs-comment" style="color: green;">// Show loading state</span>
        IsSearching = <span class="hljs-literal" style="color: rgb(163, 21, 21);">true</span>;

        <span class="hljs-keyword" style="color: rgb(0, 0, 255);">try</span>
        {
            <span class="hljs-keyword" style="color: rgb(0, 0, 255);">var</span> results = <span class="hljs-keyword" style="color: rgb(0, 0, 255);">await</span> _abnLookupService.SearchAsync(searchTerm);
            SearchResults.AddRange(results);
        }
        <span class="hljs-keyword" style="color: rgb(0, 0, 255);">finally</span>
        {
            <span class="hljs-comment" style="color: green;">// Reset button state</span>
            IsSearching = <span class="hljs-literal" style="color: rgb(163, 21, 21);">false</span>;
        }
    }
}
</pre>



<p>In addition to basic properties for SearchText and SearchResults, the MainViewModel exposes properties IsSearching and SearchResultText that are used to control the appearance of the Search button.</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2025/07/Recording-2025-07-14-043241.gif"><img loading="lazy" decoding="async" width="300" height="236" src="https://wordpressblogimages.builttoroam.com/blogimages/2025/07/Recording-2025-07-14-043241-300x236.gif" alt="" class="wp-image-3477" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2025/07/Recording-2025-07-14-043241-300x236.gif 300w, https://wordpressblogimages.builttoroam.com/blogimages/2025/07/Recording-2025-07-14-043241-768x603.gif 768w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>Here&#8217;s the equivalent using MVUX.</p>



<pre class="hljs" style="display: block; overflow-x: auto; padding: 0.5em; background: rgb(255, 255, 255); color: rgb(0, 0, 0);"><span class="hljs-function"><span class="hljs-keyword" style="color: rgb(0, 0, 255);">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">partial</span> record <span class="hljs-title" style="color: rgb(163, 21, 21);">MainModel</span>(<span class="hljs-params">IAbnLookupService abnLookupService</span>)
</span>{
    <span class="hljs-comment" style="color: green;">// State for search text</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 255);">public</span> IState&lt;<span class="hljs-keyword" style="color: rgb(0, 0, 255);">string</span>&gt; SearchText =&gt; State&lt;<span class="hljs-keyword" style="color: rgb(0, 0, 255);">string</span>&gt;.Value(<span class="hljs-keyword" style="color: rgb(0, 0, 255);">this</span>, () =&gt; <span class="hljs-keyword" style="color: rgb(0, 0, 255);">string</span>.Empty);

    <span class="hljs-comment" style="color: green;">// Feed for search results</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 255);">public</span> IListFeed&lt;BusinessResult&gt; SearchResults =&gt;
        SearchText
            .Where(text =&gt; !<span class="hljs-keyword" style="color: rgb(0, 0, 255);">string</span>.IsNullOrWhiteSpace(text))
            .SelectAsync(abnLookupService.SearchAsync)
            .AsListFeed(); 
}</pre>



<p>The SearchText property is two way data bound to the search TextBox, and the SearchResults feed is derived from the current SearchText value. As the user types in the TextBox, the SearchResults is automatically executed. There are no additional properties required to indicate that the search is in progress.</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2025/07/Recording-2025-07-14-043022.gif"><img loading="lazy" decoding="async" width="300" height="235" src="https://wordpressblogimages.builttoroam.com/blogimages/2025/07/Recording-2025-07-14-043022-300x235.gif" alt="" class="wp-image-3478" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2025/07/Recording-2025-07-14-043022-300x235.gif 300w, https://wordpressblogimages.builttoroam.com/blogimages/2025/07/Recording-2025-07-14-043022-768x603.gif 768w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>Note that MVUX makes use of a FeedView in the UI in order to automatically display a progress indicator when the search is being executed.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Advantages of MVUX</h2>



<h3 class="wp-block-heading">1. <strong>Centralized State</strong></h3>



<p>Everything is driven from a single state object. You always know where the source of truth lives, making debugging and testing far easier.</p>



<h3 class="wp-block-heading">2. <strong>Less Boilerplate</strong></h3>



<p>No property-changed notifications, no commands to wire up—just pure data and transformations.</p>



<h3 class="wp-block-heading">3. <strong>Predictable UI Behavior</strong></h3>



<p>With unidirectional data flow, each action leads to a new state, and the view renders from state. This makes behavior easier to reason about and reduces bugs from hidden bindings.</p>



<h3 class="wp-block-heading">4. <strong>Built-in Side Effect Management</strong></h3>



<p>MVUX separates side-effects (like network calls or file I/O) from state logic, making code cleaner and more testable.</p>



<h3 class="wp-block-heading">5. <strong>Better Testability</strong></h3>



<p>Reducers are pure functions: given the same input, they always return the same output. This makes unit testing trivial.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f9ea.png" alt="🧪" class="wp-smiley" style="height: 1em; max-height: 1em;" /> When Should You Use MVUX?</h2>



<p>MVUX is particularly well-suited for:</p>



<ul class="wp-block-list">
<li>Applications with complex UI state or flows.</li>



<li>Apps where you want strict control and visibility into state changes.</li>



<li>Teams looking to reduce code complexity and improve maintainability.</li>



<li>Developers familiar with Redux or functional paradigms.</li>
</ul>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f9e0.png" alt="🧠" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Conclusion</h2>



<p>MVVM has served us well, but it shows its age in modern, state-heavy applications. MVUX is a powerful evolution that embraces immutability, functional updates, and unidirectional data flow to make UI development simpler, clearer, and more maintainable.</p>



<p>If you’re tired of verbose ViewModels, hunting down binding errors, or managing a growing list of <code>ICommand</code>s, it might be time to rethink your architecture—and give MVUX a try.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<p><strong><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f517.png" alt="🔗" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Resources:</strong></p>



<ul class="wp-block-list">
<li><a href="https://platform.uno/docs/articles/mvux/index.html">MVUX in Uno Platform </a><a href="https://platform.uno/docs/articles/external/uno.extensions/doc/Learn/Mvux/Overview.html">Docs</a></li>



<li><a href="https://github.com/unoplatform/uno.extensions/tree/main/src/Uno.Extensions.Reactive">MVUX GitHub</a></li>
</ul>



<p></p>
<p>The post <a href="https://nicksnettravels.builttoroam.com/stop-using-mvvm/">Stop Using MVVM</a> appeared first on <a href="https://nicksnettravels.builttoroam.com">Nick&#039;s .NET Travels</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://nicksnettravels.builttoroam.com/stop-using-mvvm/feed/</wfw:commentRss>
			<slash:comments>10</slash:comments>
		
		
			</item>
		<item>
		<title>Using Instruction Files with VS Code Agent Mode and the Uno Platform</title>
		<link>https://nicksnettravels.builttoroam.com/using-instruction-files-with-vs-code/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=using-instruction-files-with-vs-code</link>
					<comments>https://nicksnettravels.builttoroam.com/using-instruction-files-with-vs-code/#comments</comments>
		
		<dc:creator><![CDATA[Nick]]></dc:creator>
		<pubDate>Sat, 12 Jul 2025 08:31:28 +0000</pubDate>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[AI]]></category>
		<category><![CDATA[Chat]]></category>
		<category><![CDATA[Copilot]]></category>
		<category><![CDATA[Uno]]></category>
		<category><![CDATA[Uno Platform]]></category>
		<category><![CDATA[VS Code]]></category>
		<guid isPermaLink="false">https://nicksnettravels.builttoroam.com/?p=3446</guid>

					<description><![CDATA[<p>In this post we&#8217;re going to do two things. Firstly, we&#8217;re going to step through how to create an Uno Platform application with VS Code. Then, we&#8217;re going to use VS Code to generate an instructions file that will help guide Copilot Chat to generate output that&#8217;s more consistent with your application structure. Setting up ... <a title="Using Instruction Files with VS Code Agent Mode and the Uno Platform" class="read-more" href="https://nicksnettravels.builttoroam.com/using-instruction-files-with-vs-code/" aria-label="Read more about Using Instruction Files with VS Code Agent Mode and the Uno Platform">Read more</a></p>
<p>The post <a href="https://nicksnettravels.builttoroam.com/using-instruction-files-with-vs-code/">Using Instruction Files with VS Code Agent Mode and the Uno Platform</a> appeared first on <a href="https://nicksnettravels.builttoroam.com">Nick&#039;s .NET Travels</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>In this post we&#8217;re going to do two things. Firstly, we&#8217;re going to step through how to create an Uno Platform application with VS Code. Then, we&#8217;re going to use VS Code to generate an instructions file that will help guide Copilot Chat to generate output that&#8217;s more consistent with your application structure.</p>



<h2 class="wp-block-heading">Setting up VS Code for Uno Platform Development</h2>



<p>The first step is to install the <a href="https://marketplace.visualstudio.com/items?itemName=unoplatform.vscode">Uno Platform extension for VS Code</a> (you can follow this link, or install from the Extensions list inside VS Code):</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-686f5b4a68d1a.png"><img loading="lazy" decoding="async" width="300" height="176" src="https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-686f5b4a68d1a-300x176.png" alt="" class="wp-image-3449" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-686f5b4a68d1a-300x176.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-686f5b4a68d1a-1024x601.png 1024w, https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-686f5b4a68d1a-768x451.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-686f5b4a68d1a-1536x901.png 1536w, https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-686f5b4a68d1a-2048x1202.png 2048w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>Once install, you&#8217;ll want to make sure you run <a href="https://platform.uno/docs/articles/external/uno.check/doc/using-uno-check.html">uno-check</a> to ensure all the dependencies are installed. In the past you would have had to download uno-check but it&#8217;s now part of the extension, so you can invoke it directly from the command palette.</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-686f5beb30246.png"><img loading="lazy" decoding="async" width="300" height="84" src="https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-686f5beb30246-300x84.png" alt="" class="wp-image-3451" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-686f5beb30246-300x84.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-686f5beb30246-1024x287.png 1024w, https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-686f5beb30246-768x215.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-686f5beb30246.png 1379w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>Uno-check will run as a separate process, stepping through each set of dependencies to make sure you&#8217;re all setup to build and run Uno Platform applications.</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-686f5c86c55b6.png"><img loading="lazy" decoding="async" width="300" height="170" src="https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-686f5c86c55b6-300x170.png" alt="" class="wp-image-3452" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-686f5c86c55b6-300x170.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-686f5c86c55b6-1024x582.png 1024w, https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-686f5c86c55b6-768x436.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-686f5c86c55b6.png 1350w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>Now that we have all the dependencies installed, let&#8217;s go ahead and create a new project. You can do this directly from the command line by exploring the options of the unoapp template by running <code>"dotnet new unoapp -h"</code>. Alternatively, you can use the <a href="https://new.platform.uno/">Uno Platform Live Wizard</a> to step through the available options and then generate the appropriate dotnet new command that you can run to create your application. </p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-686f5b9c89f90.png"><img loading="lazy" decoding="async" width="300" height="211" src="https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-686f5b9c89f90-300x211.png" alt="" class="wp-image-3450" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-686f5b9c89f90-300x211.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-686f5b9c89f90-1024x722.png 1024w, https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-686f5b9c89f90-768x541.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-686f5b9c89f90.png 1527w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>In this case we&#8217;re going to be creating a new application using the Recommended preset.</p>



<p><code>dotnet new unoapp -o InstructionsSampleApp -preset "recommended"</code></p>



<p>Inside a Terminal within VS Code we can execute this code in order to create the application.</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-6871452f03c1d.png"><img loading="lazy" decoding="async" width="300" height="89" src="https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-6871452f03c1d-300x89.png" alt="" class="wp-image-3455" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-6871452f03c1d-300x89.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-6871452f03c1d-1024x303.png 1024w, https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-6871452f03c1d-768x227.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-6871452f03c1d.png 1137w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>The last thing to do is to open the newly created InstructionsSampleApp folder in VS Code.</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-687145d379b9d.png"><img loading="lazy" decoding="async" width="300" height="263" src="https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-687145d379b9d-300x263.png" alt="" class="wp-image-3456" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-687145d379b9d-300x263.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-687145d379b9d.png 579w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>After opening the application in VS Code, use the highlighted (red) project selector button at the bottom of the screen to select the project file as the active project.</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-6872162c088a3.png"><img loading="lazy" decoding="async" width="300" height="176" src="https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-6872162c088a3-300x176.png" alt="" class="wp-image-3470" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-6872162c088a3-300x176.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-6872162c088a3-1024x602.png 1024w, https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-6872162c088a3-768x451.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-6872162c088a3.png 1217w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>Next, pick the target platform (click the target platform selector button at bottom of screen), in this case net9-desktop.</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-6872165453ff1.png"><img loading="lazy" decoding="async" width="300" height="174" src="https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-6872165453ff1-300x174.png" alt="" class="wp-image-3471" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-6872165453ff1-300x174.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-6872165453ff1-1024x593.png 1024w, https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-6872165453ff1-768x445.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-6872165453ff1.png 1231w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>Now we can run the application. If you run without the debugger you&#8217;ll see that the Hot Design button (left) in the Studio toolbar is enabled. </p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-68721699923d8.png"><img loading="lazy" decoding="async" width="300" height="188" src="https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-68721699923d8-300x188.png" alt="" class="wp-image-3472" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-68721699923d8-300x188.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-68721699923d8-1024x642.png 1024w, https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-68721699923d8-768x481.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-68721699923d8.png 1518w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>Clicking the Hot Design button will launch the runtime design experience, allowing the creation, selection and modification of elements in the running application.</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-687216c692524.png"><img loading="lazy" decoding="async" width="300" height="194" src="https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-687216c692524-300x194.png" alt="" class="wp-image-3473" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-687216c692524-300x194.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-687216c692524-1024x662.png 1024w, https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-687216c692524-768x497.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-687216c692524-1536x993.png 1536w, https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-687216c692524.png 1689w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>If you haven&#8217;t already checked out the Hot Design experience, give it a shot today as we&#8217;d love to hear your feedback.</p>



<h2 class="wp-block-heading">Creating Instruction files</h2>



<p>Ok, now we have our Uno Platform application setup and ready to go, we can use Copilot Chat in VS Code to use AI to modify our application. Chat can be launched from the View menu.</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-687145fcd3737.png"><img loading="lazy" decoding="async" width="278" height="300" src="https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-687145fcd3737-278x300.png" alt="" class="wp-image-3457" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-687145fcd3737-278x300.png 278w, https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-687145fcd3737.png 578w" sizes="auto, (max-width: 278px) 100vw, 278px" /></a></figure>



<p>Opening Copilot chat gives us various options to pick the AI model and the mode &#8211; in this case I&#8217;m using Agent mode with Claude.</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-687146231cbf8.png"><img loading="lazy" decoding="async" width="202" height="300" src="https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-687146231cbf8-202x300.png" alt="" class="wp-image-3458" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-687146231cbf8-202x300.png 202w, https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-687146231cbf8.png 611w" sizes="auto, (max-width: 202px) 100vw, 202px" /></a></figure>



<p>Before I start interacting with Copilot Chat, I make sure that I setup my application to guide AI as to how I want code to be created. To do this you can define <a href="https://code.visualstudio.com/docs/copilot/copilot-customization#_custom-instructions">instruction</a> files that will help guide AI. Rather than create instruction files manually, in the latest VS Code Preview, there&#8217;s a new option to Generate Instructions.</p>



<figure class="wp-block-image size-medium"><img loading="lazy" decoding="async" width="300" height="140" src="https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-687147345f5d9-300x140.png" alt="" class="wp-image-3463" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-687147345f5d9-300x140.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-687147345f5d9-768x360.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-687147345f5d9.png 831w" sizes="auto, (max-width: 300px) 100vw, 300px" /></figure>



<p>When you select this option, Copilot will spend a couple of minutes analyzing your existing project structure in order to determine the appropriate instructions.</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-687147630a943.png"><img loading="lazy" decoding="async" width="198" height="300" src="https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-687147630a943-198x300.png" alt="" class="wp-image-3464" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-687147630a943-198x300.png 198w, https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-687147630a943-677x1024.png 677w, https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-687147630a943-768x1162.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-687147630a943.png 843w" sizes="auto, (max-width: 198px) 100vw, 198px" /></a></figure>



<p>Here you can see a snapshot of the instructions created for our sample application &#8211; we created an application using the Recommended presets in the unoapp template, so the instructions are quite opinionated and use a lot of the Uno Platform features such as Toolkit and Extensions.</p>



<figure class="wp-block-image size-medium"><img loading="lazy" decoding="async" width="300" height="277" src="https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-687147b143657-300x277.png" alt="" class="wp-image-3465" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-687147b143657-300x277.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-687147b143657-1024x947.png 1024w, https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-687147b143657-768x710.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-687147b143657-1536x1420.png 1536w, https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-687147b143657.png 1573w" sizes="auto, (max-width: 300px) 100vw, 300px" /></figure>



<p>If I repeat this process using the Blank preset, the instructions file is still quite detailed but isn&#8217;t as opinionated when it comes to how code should be structured.</p>



<figure class="wp-block-image size-medium"><img loading="lazy" decoding="async" width="284" height="300" src="https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-687148d9ae10e-284x300.png" alt="" class="wp-image-3467" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-687148d9ae10e-284x300.png 284w, https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-687148d9ae10e-968x1024.png 968w, https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-687148d9ae10e-768x812.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2025/07/image-687148d9ae10e.png 1437w" sizes="auto, (max-width: 284px) 100vw, 284px" /></figure>



<p>After creating the instructions file, you should see that the output of any interaction with Copilot Chat will be more inline with the existing structure of your application. Of course, you&#8217;ll want to adjust and extend the generated instructions file as you continue to develop your application.</p>



<p>Hopefully in the post you&#8217;ve seen how to successfully create an Uno Platform application and how you can improve the output of Copilot Chat using instruction files.</p>



<p></p>



<p></p>



<p></p>



<p></p>



<p></p>



<p></p>



<p></p>
<p>The post <a href="https://nicksnettravels.builttoroam.com/using-instruction-files-with-vs-code/">Using Instruction Files with VS Code Agent Mode and the Uno Platform</a> appeared first on <a href="https://nicksnettravels.builttoroam.com">Nick&#039;s .NET Travels</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://nicksnettravels.builttoroam.com/using-instruction-files-with-vs-code/feed/</wfw:commentRss>
			<slash:comments>2</slash:comments>
		
		
			</item>
		<item>
		<title>Uno Platform 6.0 for Windows and Cross-Platform Applications</title>
		<link>https://nicksnettravels.builttoroam.com/uno-platform-6-0/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=uno-platform-6-0</link>
					<comments>https://nicksnettravels.builttoroam.com/uno-platform-6-0/#respond</comments>
		
		<dc:creator><![CDATA[Nick]]></dc:creator>
		<pubDate>Mon, 12 May 2025 03:25:16 +0000</pubDate>
				<category><![CDATA[Announcements]]></category>
		<category><![CDATA[Development]]></category>
		<category><![CDATA[Cross-Platform]]></category>
		<category><![CDATA[Hot Design]]></category>
		<category><![CDATA[Hot Reload]]></category>
		<category><![CDATA[Uno]]></category>
		<category><![CDATA[Uno Platform]]></category>
		<category><![CDATA[Windows]]></category>
		<category><![CDATA[XAML]]></category>
		<guid isPermaLink="false">https://nicksnettravels.builttoroam.com/?p=3428</guid>

					<description><![CDATA[<p>Last week v6.0 of the Uno Platform was released marking the cumulation of a number of years of investment in both the core cross platform framework, as well as the new Uno Platform Studio (including Hot Design), a set of tools that are designed to accelerate your development. In this post we&#8217;re going to take ... <a title="Uno Platform 6.0 for Windows and Cross-Platform Applications" class="read-more" href="https://nicksnettravels.builttoroam.com/uno-platform-6-0/" aria-label="Read more about Uno Platform 6.0 for Windows and Cross-Platform Applications">Read more</a></p>
<p>The post <a href="https://nicksnettravels.builttoroam.com/uno-platform-6-0/">Uno Platform 6.0 for Windows and Cross-Platform Applications</a> appeared first on <a href="https://nicksnettravels.builttoroam.com">Nick&#039;s .NET Travels</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>Last week v6.0 of the <a href="https://platform.uno/dotnettravels-uno">Uno Platform</a> was released marking the cumulation of a number of years of investment in both the core cross platform framework, as well as the new <a href="https://platform.uno/studio/">Uno Platform Studio</a> (including <a href="https://platform.uno/hot-design/">Hot Design</a>), a set of tools that are designed to accelerate your development. In this post we&#8217;re going to take a look at the new release, starting with the Visual Studio Template Wizard.</p>



<h2 class="wp-block-heading">Skia Renderers</h2>



<p>If you&#8217;re familiar with the Uno Platform, one of the most significant changes in v6 is the switch from native to Skia-based renderers for all Uno Platform targets (which excludes the WinAppSdk target, which continues to rely on Microsoft&#8217;s implementation). When you look at the Platforms tab in the wizard, you&#8217;ll see that there is a tag at the bottom of each of the tiles, indicating whether the platform uses native or Skia renderer. </p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2025/05/image.png"><img loading="lazy" decoding="async" width="300" height="292" src="https://wordpressblogimages.builttoroam.com/blogimages/2025/05/image-300x292.png" alt="" class="wp-image-3429" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2025/05/image-300x292.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2025/05/image-1024x996.png 1024w, https://wordpressblogimages.builttoroam.com/blogimages/2025/05/image-768x747.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2025/05/image-1536x1493.png 1536w, https://wordpressblogimages.builttoroam.com/blogimages/2025/05/image.png 1554w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>If you want to use the native renderers, they&#8217;re still available and supported. From the Features tab, you can switch between Skia and Native tiles.</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2025/05/image-68211b12570a4.png"><img loading="lazy" decoding="async" width="300" height="184" src="https://wordpressblogimages.builttoroam.com/blogimages/2025/05/image-68211b12570a4-300x184.png" alt="" class="wp-image-3430" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2025/05/image-68211b12570a4-300x184.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2025/05/image-68211b12570a4-1024x628.png 1024w, https://wordpressblogimages.builttoroam.com/blogimages/2025/05/image-68211b12570a4-768x471.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2025/05/image-68211b12570a4.png 1146w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>Switching to Native will adjust the tag on most of the Platform tiles. Note that the Desktop tile continues to use Skia as there&#8217;s no native alternative.</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2025/05/image-68211bb292d8f.png"><img loading="lazy" decoding="async" width="300" height="282" src="https://wordpressblogimages.builttoroam.com/blogimages/2025/05/image-68211bb292d8f-300x282.png" alt="" class="wp-image-3433" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2025/05/image-68211bb292d8f-300x282.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2025/05/image-68211bb292d8f-1024x962.png 1024w, https://wordpressblogimages.builttoroam.com/blogimages/2025/05/image-68211bb292d8f-768x721.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2025/05/image-68211bb292d8f-1536x1443.png 1536w, https://wordpressblogimages.builttoroam.com/blogimages/2025/05/image-68211bb292d8f.png 1610w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>It&#8217;s also worth noting that the WinAppSdk tile isn&#8217;t checked by default. We highly recommend checking out the Desktop platform for targeting Windows unless there are specific WinAppSdk features or third party controls that you want to take advantage of that isn&#8217;t available for the Desktop target.</p>



<h2 class="wp-block-heading">Kiota</h2>



<p>One of the other notable additions to the wizard is the option to use Kiota instead of Refit for the consumption of Swagger/OpenAPI endpoints. This option is enabled by default in the Recommended preset and is available under the Http section on the Extensions tab.</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2025/05/image-68211b5a5952a.png"><img loading="lazy" decoding="async" width="300" height="211" src="https://wordpressblogimages.builttoroam.com/blogimages/2025/05/image-68211b5a5952a-300x211.png" alt="" class="wp-image-3431" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2025/05/image-68211b5a5952a-300x211.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2025/05/image-68211b5a5952a-1024x719.png 1024w, https://wordpressblogimages.builttoroam.com/blogimages/2025/05/image-68211b5a5952a-768x539.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2025/05/image-68211b5a5952a-1536x1078.png 1536w, https://wordpressblogimages.builttoroam.com/blogimages/2025/05/image-68211b5a5952a.png 1543w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<h2 class="wp-block-heading">Uno Platform Studio: Hot Reload &amp; Hot Design</h2>



<p>As part of this release, Uno Platform Studio is now available, which includes <strong><a href="https://platform.uno/docs/articles/features/working-with-xaml-hot-reload.html">Hot Reload</a></strong> and <strong><a href="https://platform.uno/docs/articles/studio/Hot%20Design/hot-design-overview.html">Hot Design<sup>®</sup></a></strong>, as well as <strong><a href="https://platform.uno/docs/articles/external/figma-docs/get-started.html">Design-to-Code</a></strong>. We&#8217;ll go into these in more detail in subsequent posts but when you Debug an Uno Platform application, you&#8217;ll see the floating toolbar which includes the Hot Reload (right) and Hot Design (left) icons. If you don&#8217;t see the toolbar, make sure you&#8217;re debugging and Uno Platform target (ie not WinAppSdk) and that you&#8217;ve signed in using your Uno Platform account.</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2025/05/image-68211eb1235a9.png"><img loading="lazy" decoding="async" width="300" height="225" src="https://wordpressblogimages.builttoroam.com/blogimages/2025/05/image-68211eb1235a9-300x225.png" alt="" class="wp-image-3434" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2025/05/image-68211eb1235a9-300x225.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2025/05/image-68211eb1235a9-1024x767.png 1024w, https://wordpressblogimages.builttoroam.com/blogimages/2025/05/image-68211eb1235a9-768x575.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2025/05/image-68211eb1235a9.png 1027w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>Clicking on the Hot Design icon takes you into Hot Design mode where you can select, create, modify and delete elements via the runtime designer. The changes you make are persisted to XAML, making it possible to create and iterate your application without having to stop, rebuild and debug your application repeatedly.</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2025/05/image-68211ee51f697.png"><img loading="lazy" decoding="async" width="300" height="184" src="https://wordpressblogimages.builttoroam.com/blogimages/2025/05/image-68211ee51f697-300x184.png" alt="" class="wp-image-3435" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2025/05/image-68211ee51f697-300x184.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2025/05/image-68211ee51f697-1024x628.png 1024w, https://wordpressblogimages.builttoroam.com/blogimages/2025/05/image-68211ee51f697-768x471.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2025/05/image-68211ee51f697-1536x943.png 1536w, https://wordpressblogimages.builttoroam.com/blogimages/2025/05/image-68211ee51f697.png 1944w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>There&#8217;s plenty more to cover in the v6 release of the Uno Platform. In the meantime, get started with the extension for your choice of IDE (VS, VS Code or Rider) on Windows, MacOS, or Linux.</p>



<p></p>



<p></p>
<p>The post <a href="https://nicksnettravels.builttoroam.com/uno-platform-6-0/">Uno Platform 6.0 for Windows and Cross-Platform Applications</a> appeared first on <a href="https://nicksnettravels.builttoroam.com">Nick&#039;s .NET Travels</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://nicksnettravels.builttoroam.com/uno-platform-6-0/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>AI on Windows: Chat Styling</title>
		<link>https://nicksnettravels.builttoroam.com/ai-on-windows-chat-styling/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=ai-on-windows-chat-styling</link>
					<comments>https://nicksnettravels.builttoroam.com/ai-on-windows-chat-styling/#respond</comments>
		
		<dc:creator><![CDATA[Nick]]></dc:creator>
		<pubDate>Sun, 06 Apr 2025 17:25:05 +0000</pubDate>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[AI]]></category>
		<category><![CDATA[Hot Design]]></category>
		<category><![CDATA[Uno]]></category>
		<category><![CDATA[Uno Platform]]></category>
		<category><![CDATA[WinAppSdk]]></category>
		<category><![CDATA[Windows]]></category>
		<guid isPermaLink="false">https://nicksnettravels.builttoroam.com/?p=3420</guid>

					<description><![CDATA[<p>In the past three posts about working with AI on Windows, we covered connecting to Phi Silica, getting progress response, and building a chat experience. In this post we&#8217;re going to improve the styling of the chat by using data templates and including a system message to setup the chat interaction. At the end of the previous ... <a title="AI on Windows: Chat Styling" class="read-more" href="https://nicksnettravels.builttoroam.com/ai-on-windows-chat-styling/" aria-label="Read more about AI on Windows: Chat Styling">Read more</a></p>
<p>The post <a href="https://nicksnettravels.builttoroam.com/ai-on-windows-chat-styling/">AI on Windows: Chat Styling</a> appeared first on <a href="https://nicksnettravels.builttoroam.com">Nick&#039;s .NET Travels</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>In the past three posts about working with AI on Windows, we covered <a href="https://nicksnettravels.builttoroam.com/ai-on-windows-phi-silica/">connecting to Phi Silica</a>, getting <a href="https://nicksnettravels.builttoroam.com/ai-on-windows-progress-responses-phi-silica/">progress response</a>, and building a <a href="https://nicksnettravels.builttoroam.com/ai-on-windows-chat-with-phi-silica/">chat experience</a>. In this post we&#8217;re going to improve the styling of the chat by using data templates and including a system message to setup the chat interaction.</p>



<p>At the end of the previous post, the layout was relatively basic, with the formatting of each item in the ListView being the ToString representation of the PhiMessage object.</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2025/04/image.png"><img loading="lazy" decoding="async" width="300" height="236" src="https://wordpressblogimages.builttoroam.com/blogimages/2025/04/image-300x236.png" alt="" class="wp-image-3421" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2025/04/image-300x236.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2025/04/image-768x603.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2025/04/image.png 1022w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>To make it easier to distinguish between User input and the Assistant response, we&#8217;ll use two data templates that simply align the text to the left, for the Assistant, or the right, for the User. This will use a data template selector to pick which template to use based on the User property on the PhiMessage.</p>



<p>In the following video we create an ItemTemplate for the ListView, which will show the User and Message for the PhiMessage. We&#8217;ll also create a HeaderTemplate that will be data bound to a SystemMessage. For this, we&#8217;ll update the MainViewModel to include the SytemMessage property, which will be combined with the message history in forming the Phi Silica prompt.</p>



<pre class="hljs" style="display: block; overflow-x: auto; padding: 0.5em; background: rgb(255, 255, 255); color: rgb(0, 0, 0);">[ObservableProperty]
<span class="hljs-keyword" style="color: rgb(0, 0, 255);">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">string</span> _systemMessage = <span class="hljs-string" style="color: rgb(163, 21, 21);">"You are an assistant for a 5 year old child"</span>;

<span class="hljs-keyword" style="color: rgb(0, 0, 255);">public</span> ObservableCollection&lt;PhiMessage&gt; Messages { <span class="hljs-keyword" style="color: rgb(0, 0, 255);">get</span>; } = <span class="hljs-keyword" style="color: rgb(0, 0, 255);">new</span>();

[ObservableProperty]
<span class="hljs-keyword" style="color: rgb(0, 0, 255);">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">string</span> _response = <span class="hljs-keyword" style="color: rgb(0, 0, 255);">string</span>.Empty;

[RelayCommand]
<span class="hljs-function"><span class="hljs-keyword" style="color: rgb(0, 0, 255);">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">async</span> Task <span class="hljs-title" style="color: rgb(163, 21, 21);">SendMessage</span>(<span class="hljs-params"><span class="hljs-keyword" style="color: rgb(0, 0, 255);">string</span> message</span>)
</span>{
    Messages.Add(<span class="hljs-keyword" style="color: rgb(0, 0, 255);">new</span> PhiMessage(<span class="hljs-string" style="color: rgb(163, 21, 21);">"User"</span>, message));
<span class="hljs-meta" style="color: rgb(43, 145, 175);">#<span class="hljs-meta-keyword">if</span> WINDOWS</span>

    <span class="hljs-keyword" style="color: rgb(0, 0, 255);">if</span> (!LanguageModel.IsAvailable())
    {
        <span class="hljs-keyword" style="color: rgb(0, 0, 255);">var</span> op = <span class="hljs-keyword" style="color: rgb(0, 0, 255);">await</span> LanguageModel.MakeAvailableAsync();
    }

    <span class="hljs-keyword" style="color: rgb(0, 0, 255);">var</span> sysMessage = <span class="hljs-keyword" style="color: rgb(0, 0, 255);">new</span> PhiMessage(<span class="hljs-string" style="color: rgb(163, 21, 21);">"System"</span>, SystemMessage);

    <span class="hljs-keyword" style="color: rgb(0, 0, 255);">var</span> prompt = <span class="hljs-keyword" style="color: rgb(0, 0, 255);">string</span>.Join(Environment.NewLine, [sysMessage.ToString(), ..(<span class="hljs-keyword" style="color: rgb(0, 0, 255);">from</span> m <span class="hljs-keyword" style="color: rgb(0, 0, 255);">in</span> Messages
                                                    <span class="hljs-keyword" style="color: rgb(0, 0, 255);">select</span> m.ToString())]);


    <span class="hljs-keyword" style="color: rgb(0, 0, 255);">using</span> LanguageModel languageModel = <span class="hljs-keyword" style="color: rgb(0, 0, 255);">await</span> LanguageModel.CreateAsync();
    <span class="hljs-keyword" style="color: rgb(0, 0, 255);">var</span> progressTask = languageModel.GenerateResponseWithProgressAsync(prompt);
    progressTask.Progress +=
        (s, progress) =&gt; Dispatch(() =&gt; Response += progress);

    <span class="hljs-keyword" style="color: rgb(0, 0, 255);">var</span> result = <span class="hljs-keyword" style="color: rgb(0, 0, 255);">await</span> progressTask;
    Response = result.Response;
<span class="hljs-meta" style="color: rgb(43, 145, 175);">#<span class="hljs-meta-keyword">else</span></span>
    Response = <span class="hljs-string" style="color: rgb(163, 21, 21);">"Design-time response...."</span>;
    <span class="hljs-keyword" style="color: rgb(0, 0, 255);">await</span> Task.Delay(<span class="hljs-number">1000</span>);
    Response = <span class="hljs-string" style="color: rgb(163, 21, 21);">"Design-time response....(updating)"</span>;
    <span class="hljs-keyword" style="color: rgb(0, 0, 255);">await</span> Task.Delay(<span class="hljs-number">1000</span>);
    Response = <span class="hljs-string" style="color: rgb(163, 21, 21);">"Final design-time response"</span>;
<span class="hljs-meta" style="color: rgb(43, 145, 175);">#<span class="hljs-meta-keyword">endif</span></span>
    Messages.Add(<span class="hljs-keyword" style="color: rgb(0, 0, 255);">new</span> PhiMessage(<span class="hljs-string" style="color: rgb(163, 21, 21);">"Assistant"</span>, Response));
    Response = <span class="hljs-keyword" style="color: rgb(0, 0, 255);">string</span>.Empty;
}</pre>



<p>And now the video for creating the ItemTemplate and HeaderTemplate.</p>



<figure class="wp-block-video"><video height="1080" style="aspect-ratio: 1920 / 1080;" width="1920" controls src="https://wordpressblogimages.builttoroam.com/blogimages/2025/04/headertemplate.mp4"></video></figure>



<p>Now that we have an ItemTemplate, we can duplicate the template for the User template where the text is right aligned. In order to use these templates we&#8217;ll need a template selector.</p>



<pre class="hljs" style="display: block; overflow-x: auto; padding: 0.5em; background: rgb(255, 255, 255); color: rgb(0, 0, 0);"><span class="hljs-keyword" style="color: rgb(0, 0, 255);">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">class</span> <span class="hljs-title" style="color: rgb(163, 21, 21);">MessageTypeSelector</span> : <span class="hljs-title" style="color: rgb(163, 21, 21);">DataTemplateSelector</span>
{
    <span class="hljs-keyword" style="color: rgb(0, 0, 255);">public</span> DataTemplate UserTemplate { <span class="hljs-keyword" style="color: rgb(0, 0, 255);">get</span>; <span class="hljs-keyword" style="color: rgb(0, 0, 255);">set</span>; }

    <span class="hljs-keyword" style="color: rgb(0, 0, 255);">public</span> DataTemplate AssistantTemplate { <span class="hljs-keyword" style="color: rgb(0, 0, 255);">get</span>; <span class="hljs-keyword" style="color: rgb(0, 0, 255);">set</span>; }

    <span class="hljs-keyword" style="color: rgb(0, 0, 255);">public</span> DataTemplate SystemTemplate { <span class="hljs-keyword" style="color: rgb(0, 0, 255);">get</span>; <span class="hljs-keyword" style="color: rgb(0, 0, 255);">set</span>; }

    <span class="hljs-function"><span class="hljs-keyword" style="color: rgb(0, 0, 255);">protected</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">override</span> DataTemplate <span class="hljs-title" style="color: rgb(163, 21, 21);">SelectTemplateCore</span>(<span class="hljs-params"><span class="hljs-keyword" style="color: rgb(0, 0, 255);">object</span> item, DependencyObject container</span>)
    </span>{
        <span class="hljs-keyword" style="color: rgb(0, 0, 255);">if</span> (item <span class="hljs-keyword" style="color: rgb(0, 0, 255);">is</span> PhiMessage message)
        {
            <span class="hljs-keyword" style="color: rgb(0, 0, 255);">return</span> message.User <span class="hljs-keyword" style="color: rgb(0, 0, 255);">switch</span>
            {
                <span class="hljs-string" style="color: rgb(163, 21, 21);">"System"</span> =&gt; SystemTemplate,
                <span class="hljs-string" style="color: rgb(163, 21, 21);">"Assistant"</span> =&gt; AssistantTemplate,
                _ =&gt; UserTemplate,
            };
        }
        <span class="hljs-keyword" style="color: rgb(0, 0, 255);">return</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">base</span>.SelectTemplateCore(item, container);
    }
}</pre>



<p>The two templates and an instance of the template selector, which references the two templates, need to be added to the Resources of the page.</p>



<pre class="hljs" style="display: block; overflow-x: auto; padding: 0.5em; background: rgb(255, 255, 255); color: rgb(0, 0, 0);"><span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">Page.Resources</span>&gt;</span>
    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">DataTemplate</span> <span class="hljs-attr" style="color: red;">x:Key</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"UserDataTemplate"</span>&gt;</span>
        <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">Grid</span>&gt;</span>
            <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">StackPanel</span>&gt;</span>
                <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">TextBlock</span> <span class="hljs-attr" style="color: red;">Style</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"{StaticResource CaptionTextBlockStyle}"</span>
                            <span class="hljs-attr" style="color: red;">Text</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"{Binding User}"</span>
                            <span class="hljs-attr" style="color: red;">TextAlignment</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Right"</span> /&gt;</span>
                <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">TextBlock</span> <span class="hljs-attr" style="color: red;">Style</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"{StaticResource BaseTextBlockStyle}"</span>
                            <span class="hljs-attr" style="color: red;">Text</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"{Binding Message}"</span>
                            <span class="hljs-attr" style="color: red;">TextAlignment</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Right"</span> /&gt;</span>
            <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">StackPanel</span>&gt;</span>
        <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">Grid</span>&gt;</span>
    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">DataTemplate</span>&gt;</span>

    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">DataTemplate</span> <span class="hljs-attr" style="color: red;">x:Key</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"AssistanctDataTemplate"</span>&gt;</span>
        <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">Grid</span>&gt;</span>
            <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">StackPanel</span>&gt;</span>
                <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">TextBlock</span> <span class="hljs-attr" style="color: red;">Style</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"{StaticResource CaptionTextBlockStyle}"</span>
                            <span class="hljs-attr" style="color: red;">Text</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"{Binding User}"</span> /&gt;</span>
                <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">TextBlock</span> <span class="hljs-attr" style="color: red;">Style</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"{StaticResource BaseTextBlockStyle}"</span>
                            <span class="hljs-attr" style="color: red;">Text</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"{Binding Message}"</span> /&gt;</span>
            <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">StackPanel</span>&gt;</span>
        <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">Grid</span>&gt;</span>
    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">DataTemplate</span>&gt;</span>

    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">local:MessageTypeSelector</span> <span class="hljs-attr" style="color: red;">x:Key</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"MessageTypeSelector"</span>
                                <span class="hljs-attr" style="color: red;">UserTemplate</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"{StaticResource UserDataTemplate}"</span>
                                <span class="hljs-attr" style="color: red;">AssistantTemplate</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"{StaticResource AssistanctDataTemplate}"</span> /&gt;</span>
<span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">Page.Resources</span>&gt;</span></pre>



<p>Using Hot Design, we can update the ListView to remove the locally defined ItemTemplate and select the MessageTypeSelector resource.</p>



<figure class="wp-block-video"><video height="1080" style="aspect-ratio: 1440 / 1080;" width="1440" controls src="https://wordpressblogimages.builttoroam.com/blogimages/2025/04/selector.mp4"></video></figure>



<p>Now when we run the application on Window, we can customize the system message in order to change how Phi Silica responds. </p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="600" src="https://wordpressblogimages.builttoroam.com/blogimages/2025/04/image-67f2b7898ab71-1024x600.png" alt="" class="wp-image-3424" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2025/04/image-67f2b7898ab71-1024x600.png 1024w, https://wordpressblogimages.builttoroam.com/blogimages/2025/04/image-67f2b7898ab71-300x176.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2025/04/image-67f2b7898ab71-768x450.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2025/04/image-67f2b7898ab71.png 1235w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>
<p>The post <a href="https://nicksnettravels.builttoroam.com/ai-on-windows-chat-styling/">AI on Windows: Chat Styling</a> appeared first on <a href="https://nicksnettravels.builttoroam.com">Nick&#039;s .NET Travels</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://nicksnettravels.builttoroam.com/ai-on-windows-chat-styling/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		<enclosure length="5647791" type="video/mp4" url="https://wordpressblogimages.builttoroam.com/blogimages/2025/04/headertemplate.mp4"/>
<enclosure length="1684509" type="video/mp4" url="https://wordpressblogimages.builttoroam.com/blogimages/2025/04/selector.mp4"/>

			</item>
		<item>
		<title>AI on Windows: Chat with Phi Silica</title>
		<link>https://nicksnettravels.builttoroam.com/ai-on-windows-chat-with-phi-silica/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=ai-on-windows-chat-with-phi-silica</link>
					<comments>https://nicksnettravels.builttoroam.com/ai-on-windows-chat-with-phi-silica/#respond</comments>
		
		<dc:creator><![CDATA[Nick]]></dc:creator>
		<pubDate>Sun, 06 Apr 2025 02:07:01 +0000</pubDate>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[Hot Design]]></category>
		<category><![CDATA[Phi Silica]]></category>
		<category><![CDATA[Uno]]></category>
		<category><![CDATA[Uno Platform]]></category>
		<category><![CDATA[Windows]]></category>
		<guid isPermaLink="false">https://nicksnettravels.builttoroam.com/?p=3415</guid>

					<description><![CDATA[<p>In the past two posts we covered connecting to Phi Silica and then getting progress response to provide a more real time experience. The next step is to improve the layout of the application to display the prior message history. In this post we&#8217;ll cover updating the UI to include a list of prior messages. ... <a title="AI on Windows: Chat with Phi Silica" class="read-more" href="https://nicksnettravels.builttoroam.com/ai-on-windows-chat-with-phi-silica/" aria-label="Read more about AI on Windows: Chat with Phi Silica">Read more</a></p>
<p>The post <a href="https://nicksnettravels.builttoroam.com/ai-on-windows-chat-with-phi-silica/">AI on Windows: Chat with Phi Silica</a> appeared first on <a href="https://nicksnettravels.builttoroam.com">Nick&#039;s .NET Travels</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>In the past two posts we covered <a href="https://nicksnettravels.builttoroam.com/ai-on-windows-phi-silica/">connecting to Phi Silica</a> and then getting <a href="https://nicksnettravels.builttoroam.com/ai-on-windows-progress-responses-phi-silica/">progress response</a> to provide a more real time experience. The next step is to improve the layout of the application to display the prior message history. In this post we&#8217;ll cover updating the UI to include a list of prior messages. We&#8217;ll also cover extending the Phi Silica prompt to include the prior history, providing more context to the model.</p>



<p>We&#8217;ll start by amending the MainViewModel to include a collection of the prior messages. In addition, the prior messages are concatenated with the message entered by the user to build the prompt that&#8217;s sent to Phi Silica.</p>



<pre class="hljs" style="display: block; overflow-x: auto; padding: 0.5em; background: rgb(255, 255, 255); color: rgb(0, 0, 0);">    <span class="hljs-keyword" style="color: rgb(0, 0, 255);">public</span> ObservableCollection&lt;PhiMessage&gt; Messages { <span class="hljs-keyword" style="color: rgb(0, 0, 255);">get</span>; } = <span class="hljs-keyword" style="color: rgb(0, 0, 255);">new</span>();

    [ObservableProperty]
    <span class="hljs-keyword" style="color: rgb(0, 0, 255);">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">string</span> _response = <span class="hljs-keyword" style="color: rgb(0, 0, 255);">string</span>.Empty;

    [RelayCommand]
    <span class="hljs-function"><span class="hljs-keyword" style="color: rgb(0, 0, 255);">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">async</span> Task <span class="hljs-title" style="color: rgb(163, 21, 21);">SendMessage</span>(<span class="hljs-params"><span class="hljs-keyword" style="color: rgb(0, 0, 255);">string</span> message</span>)
    </span>{
        Messages.Add(<span class="hljs-keyword" style="color: rgb(0, 0, 255);">new</span> PhiMessage(<span class="hljs-string" style="color: rgb(163, 21, 21);">"User"</span>,message));
<span class="hljs-meta" style="color: rgb(43, 145, 175);">#<span class="hljs-meta-keyword">if</span> WINDOWS</span>

        <span class="hljs-keyword" style="color: rgb(0, 0, 255);">if</span> (!LanguageModel.IsAvailable())
        {
            <span class="hljs-keyword" style="color: rgb(0, 0, 255);">var</span> op = <span class="hljs-keyword" style="color: rgb(0, 0, 255);">await</span> LanguageModel.MakeAvailableAsync();
        }

        <span class="hljs-keyword" style="color: rgb(0, 0, 255);">var</span> prompt = <span class="hljs-keyword" style="color: rgb(0, 0, 255);">string</span>.Join(Environment.NewLine, (<span class="hljs-keyword" style="color: rgb(0, 0, 255);">from</span> m <span class="hljs-keyword" style="color: rgb(0, 0, 255);">in</span> Messages
                                                       <span class="hljs-keyword" style="color: rgb(0, 0, 255);">select</span> m.ToString()));


        <span class="hljs-keyword" style="color: rgb(0, 0, 255);">using</span> LanguageModel languageModel = <span class="hljs-keyword" style="color: rgb(0, 0, 255);">await</span> LanguageModel.CreateAsync();
        <span class="hljs-keyword" style="color: rgb(0, 0, 255);">var</span> progressTask = languageModel.GenerateResponseWithProgressAsync(prompt);
        progressTask.Progress +=
            (s, progress) =&gt; Dispatch(() =&gt; Response += progress);

        <span class="hljs-keyword" style="color: rgb(0, 0, 255);">var</span> result = <span class="hljs-keyword" style="color: rgb(0, 0, 255);">await</span> progressTask;
        Response = result.Response;
<span class="hljs-meta" style="color: rgb(43, 145, 175);">#<span class="hljs-meta-keyword">else</span></span>
        Response = <span class="hljs-string" style="color: rgb(163, 21, 21);">"Design-time response...."</span>;
        <span class="hljs-keyword" style="color: rgb(0, 0, 255);">await</span> Task.Delay(<span class="hljs-number">1000</span>);
        Response = <span class="hljs-string" style="color: rgb(163, 21, 21);">"Design-time response....(updating)"</span>;
        <span class="hljs-keyword" style="color: rgb(0, 0, 255);">await</span> Task.Delay(<span class="hljs-number">1000</span>);
        Response = <span class="hljs-string" style="color: rgb(163, 21, 21);">"Final design-time response"</span>;
<span class="hljs-meta" style="color: rgb(43, 145, 175);">#<span class="hljs-meta-keyword">endif</span></span>
        Messages.Add(<span class="hljs-keyword" style="color: rgb(0, 0, 255);">new</span> PhiMessage(<span class="hljs-string" style="color: rgb(163, 21, 21);">"Assistant"</span>,Response));
        Response = <span class="hljs-keyword" style="color: rgb(0, 0, 255);">string</span>.Empty;
    }

    <span class="hljs-function"><span class="hljs-keyword" style="color: rgb(0, 0, 255);">public</span> class <span class="hljs-title" style="color: rgb(163, 21, 21);">PhiMessage</span>(<span class="hljs-params"><span class="hljs-keyword" style="color: rgb(0, 0, 255);">string</span> user, <span class="hljs-keyword" style="color: rgb(0, 0, 255);">string</span> message</span>)
    </span>{
        <span class="hljs-keyword" style="color: rgb(0, 0, 255);">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">string</span> User { <span class="hljs-keyword" style="color: rgb(0, 0, 255);">get</span>; } = user;
        <span class="hljs-keyword" style="color: rgb(0, 0, 255);">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">string</span> Message { <span class="hljs-keyword" style="color: rgb(0, 0, 255);">get</span>; } = message;

        <span class="hljs-function"><span class="hljs-keyword" style="color: rgb(0, 0, 255);">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">override</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">string</span> <span class="hljs-title" style="color: rgb(163, 21, 21);">ToString</span>(<span class="hljs-params"></span>)
            </span>=&gt; <span class="hljs-string" style="color: rgb(163, 21, 21);">$"<span class="hljs-subst">{User}</span>:\r\n<span class="hljs-subst">{Message}</span>"</span>;
    }</pre>



<p>Here&#8217;s a quick video of how to update the UI using the Uno Platform Hot Design tool.</p>



<figure class="wp-block-video"><video height="1080" style="aspect-ratio: 1440 / 1080;" width="1440" controls src="https://wordpressblogimages.builttoroam.com/blogimages/2025/04/chatapp.mp4"></video></figure>



<p>In summary we started with a basic Grid and added:</p>



<ul class="wp-block-list">
<li>ListView &#8211; bound to the Messages property, to show the history of messages</li>



<li>TextBlock &#8211; bound to the Response property, to show the current progressive response</li>



<li>TextBox &#8211; the InputText textbox for user input</li>



<li>Button &#8211; the Send button bound to the SendMessageCommand, passing the InputText.Text in as a parameter</li>
</ul>



<p>Here&#8217;s the app running:</p>



<figure class="wp-block-video"><video height="1080" style="aspect-ratio: 1440 / 1080;" width="1440" controls src="https://wordpressblogimages.builttoroam.com/blogimages/2025/04/runningchatapp.mp4"></video></figure>



<p>And there you have it, we&#8217;ve stepped up our simple Phi Silica app to be a chat app capable of a multi-step interaction with Phi Silica.</p>
<p>The post <a href="https://nicksnettravels.builttoroam.com/ai-on-windows-chat-with-phi-silica/">AI on Windows: Chat with Phi Silica</a> appeared first on <a href="https://nicksnettravels.builttoroam.com">Nick&#039;s .NET Travels</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://nicksnettravels.builttoroam.com/ai-on-windows-chat-with-phi-silica/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		<enclosure length="8727882" type="video/mp4" url="https://wordpressblogimages.builttoroam.com/blogimages/2025/04/chatapp.mp4"/>
<enclosure length="3387916" type="video/mp4" url="https://wordpressblogimages.builttoroam.com/blogimages/2025/04/runningchatapp.mp4"/>

			</item>
		<item>
		<title>AI on Windows: Progress Responses with Phi Silica</title>
		<link>https://nicksnettravels.builttoroam.com/ai-on-windows-progress-responses-phi-silica/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=ai-on-windows-progress-responses-phi-silica</link>
					<comments>https://nicksnettravels.builttoroam.com/ai-on-windows-progress-responses-phi-silica/#respond</comments>
		
		<dc:creator><![CDATA[Nick]]></dc:creator>
		<pubDate>Tue, 01 Apr 2025 17:44:45 +0000</pubDate>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[AI]]></category>
		<category><![CDATA[Phi Silica]]></category>
		<category><![CDATA[Uno]]></category>
		<category><![CDATA[Uno Platform]]></category>
		<category><![CDATA[Windows]]></category>
		<guid isPermaLink="false">https://nicksnettravels.builttoroam.com/?p=3410</guid>

					<description><![CDATA[<p>In my previous post I covered the basics of creating an Uno Platform application that consumes Phi Silica in order to build a very basic prompt-response based user interface. When the application was run there was a very evident latency when the button was clicked before the response was presented. In this post we&#8217;re going ... <a title="AI on Windows: Progress Responses with Phi Silica" class="read-more" href="https://nicksnettravels.builttoroam.com/ai-on-windows-progress-responses-phi-silica/" aria-label="Read more about AI on Windows: Progress Responses with Phi Silica">Read more</a></p>
<p>The post <a href="https://nicksnettravels.builttoroam.com/ai-on-windows-progress-responses-phi-silica/">AI on Windows: Progress Responses with Phi Silica</a> appeared first on <a href="https://nicksnettravels.builttoroam.com">Nick&#039;s .NET Travels</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>In my <a href="https://nicksnettravels.builttoroam.com/ai-on-windows-phi-silica/">previous post</a> I covered the basics of creating an Uno Platform application that consumes Phi Silica in order to build a very basic prompt-response based user interface. When the application was run there was a very evident latency when the button was clicked before the response was presented. In this post we&#8217;re going to make some minor changes to the calls to Phi Silica to get progress responses in order to make the user experience more responsive.</p>



<p>The existing code called <code>GenerateResponseAsync</code> in order to get a response to the prompt provided as a parameter. This method needs to be awaited and simply returns a Response that is a string, which can be displayed to the user. If we change the code to use the <code>GenerateResponseWithProgressAsync</code>, we can attach an event handler to the Progress event.</p>



<p>The following code shows the <code>MainViewModel</code> which has been updated to use the <code>GenerateResponseWithProgressAsync</code> method. There is a new constructor parameter, a DispatcherQueue, and rather than just updating the Response property, the DispatcherQueue is used to ensure the update is done on the correct thread (the Progress event currently triggers on a different thread).</p>



<pre class="hljs" style="display: block; overflow-x: auto; padding: 0.5em; background: rgb(255, 255, 255); color: rgb(0, 0, 0);"><span class="hljs-keyword" style="color: rgb(0, 0, 255);">using</span> Microsoft.UI.Dispatching;
<span class="hljs-keyword" style="color: rgb(0, 0, 255);">using</span> Microsoft.UI.Xaml.Data;
<span class="hljs-meta" style="color: rgb(43, 145, 175);">#<span class="hljs-meta-keyword">if</span> WINDOWS</span>
<span class="hljs-keyword" style="color: rgb(0, 0, 255);">using</span> Microsoft.Windows.AI.Generative;
<span class="hljs-meta" style="color: rgb(43, 145, 175);">#<span class="hljs-meta-keyword">endif</span></span>

<span class="hljs-keyword" style="color: rgb(0, 0, 255);">namespace</span> <span class="hljs-title" style="color: rgb(163, 21, 21);">PhiMessagingApp</span>;

[Bindable]
<span class="hljs-function"><span class="hljs-keyword" style="color: rgb(0, 0, 255);">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">partial</span> class <span class="hljs-title" style="color: rgb(163, 21, 21);">MainViewModel</span>(<span class="hljs-params">DispatcherQueue dispatcher</span>) : ObservableObject
</span>{
    [ObservableProperty]
    <span class="hljs-keyword" style="color: rgb(0, 0, 255);">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">string</span> _response = <span class="hljs-keyword" style="color: rgb(0, 0, 255);">string</span>.Empty;

    [RelayCommand]
    <span class="hljs-function"><span class="hljs-keyword" style="color: rgb(0, 0, 255);">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">async</span> Task <span class="hljs-title" style="color: rgb(163, 21, 21);">SendMessage</span>(<span class="hljs-params"><span class="hljs-keyword" style="color: rgb(0, 0, 255);">string</span> message</span>)
    </span>{
<span class="hljs-meta" style="color: rgb(43, 145, 175);">#<span class="hljs-meta-keyword">if</span> WINDOWS</span>

        <span class="hljs-keyword" style="color: rgb(0, 0, 255);">if</span> (!LanguageModel.IsAvailable())
        {
            <span class="hljs-keyword" style="color: rgb(0, 0, 255);">var</span> op = <span class="hljs-keyword" style="color: rgb(0, 0, 255);">await</span> LanguageModel.MakeAvailableAsync();
        }

        <span class="hljs-keyword" style="color: rgb(0, 0, 255);">using</span> LanguageModel languageModel = <span class="hljs-keyword" style="color: rgb(0, 0, 255);">await</span> LanguageModel.CreateAsync();
        <span class="hljs-keyword" style="color: rgb(0, 0, 255);">var</span> progressTask = languageModel.GenerateResponseWithProgressAsync(message);
        progressTask.Progress += 
            (s, progress) =&gt; Dispatch(() =&gt; Response += progress);

        <span class="hljs-keyword" style="color: rgb(0, 0, 255);">var</span> result = <span class="hljs-keyword" style="color: rgb(0, 0, 255);">await</span> progressTask;
        Response = result.Response;
<span class="hljs-meta" style="color: rgb(43, 145, 175);">#<span class="hljs-meta-keyword">else</span></span>
        Response = <span class="hljs-string" style="color: rgb(163, 21, 21);">"Design-time response...."</span>;
<span class="hljs-meta" style="color: rgb(43, 145, 175);">#<span class="hljs-meta-keyword">endif</span></span>
    }

    <span class="hljs-function"><span class="hljs-keyword" style="color: rgb(0, 0, 255);">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">void</span> <span class="hljs-title" style="color: rgb(163, 21, 21);">Dispatch</span>(<span class="hljs-params">Action action</span>)
    </span>{
        <span class="hljs-keyword" style="color: rgb(0, 0, 255);">if</span> (dispatcher.HasThreadAccess)
        {
            action();
        }
        <span class="hljs-keyword" style="color: rgb(0, 0, 255);">else</span>
        {
            dispatcher.TryEnqueue(() =&gt; action());
        }
    }
}
</pre>



<p>When we run this, we can see that after clicking the Button we get a progressive response.</p>



<figure class="wp-block-video"><video height="1080" style="aspect-ratio: 1920 / 1080;" width="1920" controls src="https://wordpressblogimages.builttoroam.com/blogimages/2025/04/Untitled-video-Made-with-Clipchamp.mp4"></video></figure>



<p>There are a couple of questions/suggestions I would make:</p>



<ul class="wp-block-list">
<li>I think it would make sense for the Progress event to be triggered on the same thread that the <code>GenerateResponseWithProgressAsync</code> is called on.</li>



<li>I&#8217;m not quite sure why the API has both GenerateResponseWithProgressAsync and GenerateResponseAsync. If you await either of them you get a response that you can use. There&#8217;s no requirement to attach a Progress event handler, so I don&#8217;t understand why we need to have two methods.</li>
</ul>
<p>The post <a href="https://nicksnettravels.builttoroam.com/ai-on-windows-progress-responses-phi-silica/">AI on Windows: Progress Responses with Phi Silica</a> appeared first on <a href="https://nicksnettravels.builttoroam.com">Nick&#039;s .NET Travels</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://nicksnettravels.builttoroam.com/ai-on-windows-progress-responses-phi-silica/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		<enclosure length="1845214" type="video/mp4" url="https://wordpressblogimages.builttoroam.com/blogimages/2025/04/Untitled-video-Made-with-Clipchamp.mp4"/>

			</item>
		<item>
		<title>AI on Windows: Chatting with Phi Silica</title>
		<link>https://nicksnettravels.builttoroam.com/ai-on-windows-phi-silica/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=ai-on-windows-phi-silica</link>
					<comments>https://nicksnettravels.builttoroam.com/ai-on-windows-phi-silica/#respond</comments>
		
		<dc:creator><![CDATA[Nick]]></dc:creator>
		<pubDate>Sun, 30 Mar 2025 14:47:51 +0000</pubDate>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[AI]]></category>
		<category><![CDATA[Phi Silica]]></category>
		<category><![CDATA[Uno]]></category>
		<category><![CDATA[Uno Platform]]></category>
		<category><![CDATA[Windows]]></category>
		<guid isPermaLink="false">https://nicksnettravels.builttoroam.com/?p=3393</guid>

					<description><![CDATA[<p>Last year Microsoft introduced Phi Silica and recently made an experimental release of the Windows App Sdk that can be used by Windows application to interact with Phi Silica. In this post we&#8217;ll connect an Uno Platform application to Phi Silica. We&#8217;ll keep things simple and start with the Blank preset in the Uno Platform ... <a title="AI on Windows: Chatting with Phi Silica" class="read-more" href="https://nicksnettravels.builttoroam.com/ai-on-windows-phi-silica/" aria-label="Read more about AI on Windows: Chatting with Phi Silica">Read more</a></p>
<p>The post <a href="https://nicksnettravels.builttoroam.com/ai-on-windows-phi-silica/">AI on Windows: Chatting with Phi Silica</a> appeared first on <a href="https://nicksnettravels.builttoroam.com">Nick&#039;s .NET Travels</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>Last year Microsoft <a href="https://blogs.windows.com/windowsexperience/2024/12/06/phi-silica-small-but-mighty-on-device-slm/">introduced Phi Silica</a> and recently made an <a href="https://learn.microsoft.com/en-us/windows/ai/apis/phi-silica">experimental release of the Windows App Sdk</a> that can be used by Windows application to interact with Phi Silica. In this post we&#8217;ll connect an Uno Platform application to Phi Silica.</p>



<p>We&#8217;ll keep things simple and start with the Blank preset in the Uno Platform template wizard and add Mvvm support under the Presentation section.</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2025/03/image-67e82804eceb3.png"><img loading="lazy" decoding="async" width="300" height="214" src="https://wordpressblogimages.builttoroam.com/blogimages/2025/03/image-67e82804eceb3-300x214.png" alt="" class="wp-image-3396" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2025/03/image-67e82804eceb3-300x214.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2025/03/image-67e82804eceb3-1024x731.png 1024w, https://wordpressblogimages.builttoroam.com/blogimages/2025/03/image-67e82804eceb3-768x548.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2025/03/image-67e82804eceb3.png 1518w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>In order to access the Phi Silica apis we&#8217;ll first need to update to the experimental release of the Windows App Sdk. With Uno, this is done by setting the <code>WinAppSdkVersion</code> property to the experimental version, 1.7.250127003-experimental3.</p>



<pre class="hljs" style="display: block; overflow-x: auto; padding: 0.5em; background: rgb(255, 255, 255); color: rgb(0, 0, 0);"><span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">PropertyGroup</span> <span class="hljs-attr" style="color: red;">Condition</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"'$(TargetFramework)'=='net9.0-windows10.0.26100'"</span>&gt;</span>
    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">WinAppSdkVersion</span>&gt;</span>1.7.250127003-experimental3<span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">WinAppSdkVersion</span>&gt;</span>
<span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">PropertyGroup</span>&gt;</span>
</pre>



<p>The Phi Silica apis won&#8217;t appear whilst the Platform of the project is set to AnyCPU. To resolve this, we need to set both the Platforms and RuntimeIdentifiers properties, when the application is targeting Windows.</p>



<pre class="hljs" style="display: block; overflow-x: auto; padding: 0.5em; background: rgb(255, 255, 255); color: rgb(0, 0, 0);"><span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">PropertyGroup</span> <span class="hljs-attr" style="color: red;">Condition</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"'$(TargetFramework)'=='net9.0-windows10.0.26100'"</span>&gt;</span>
    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">Platforms</span>&gt;</span>x86;x64;ARM64<span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">Platforms</span>&gt;</span>
    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">RuntimeIdentifiers</span>&gt;</span>win-x86;win-x64;win-arm64<span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">RuntimeIdentifiers</span>&gt;</span>
    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">WinAppSdkVersion</span>&gt;</span>1.7.250127003-experimental3<span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">WinAppSdkVersion</span>&gt;</span>
<span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">PropertyGroup</span>&gt;</span>
</pre>



<p>After making this adjustment, open Configuration Manager and make sure the Platform value is set to the correct architecture.</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2025/03/image-67e829349e6d5.png"><img loading="lazy" decoding="async" width="300" height="218" src="https://wordpressblogimages.builttoroam.com/blogimages/2025/03/image-67e829349e6d5-300x218.png" alt="" class="wp-image-3397" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2025/03/image-67e829349e6d5-300x218.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2025/03/image-67e829349e6d5-768x559.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2025/03/image-67e829349e6d5.png 1004w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>Let&#8217;s add a MainViewModel that will be used to send a message to Phi Silica and get a response.</p>



<pre class="hljs" style="display: block; overflow-x: auto; padding: 0.5em; background: rgb(255, 255, 255); color: rgb(0, 0, 0);"><span class="hljs-keyword" style="color: rgb(0, 0, 255);">using</span> Microsoft.UI.Xaml.Data;
<span class="hljs-meta" style="color: rgb(43, 145, 175);">#<span class="hljs-meta-keyword">if</span> WINDOWS</span>
<span class="hljs-keyword" style="color: rgb(0, 0, 255);">using</span> Microsoft.Windows.AI.Generative;
<span class="hljs-meta" style="color: rgb(43, 145, 175);">#<span class="hljs-meta-keyword">endif</span></span>

<span class="hljs-keyword" style="color: rgb(0, 0, 255);">namespace</span> <span class="hljs-title" style="color: rgb(163, 21, 21);">PhiMessagingApp</span>;

[Bindable]
<span class="hljs-keyword" style="color: rgb(0, 0, 255);">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">partial</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">class</span> <span class="hljs-title" style="color: rgb(163, 21, 21);">MainViewModel</span> : <span class="hljs-title" style="color: rgb(163, 21, 21);">ObservableObject</span>
{
    [ObservableProperty]
    <span class="hljs-keyword" style="color: rgb(0, 0, 255);">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">string</span> _response = <span class="hljs-keyword" style="color: rgb(0, 0, 255);">string</span>.Empty;

    [RelayCommand]
    <span class="hljs-function"><span class="hljs-keyword" style="color: rgb(0, 0, 255);">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">async</span> Task <span class="hljs-title" style="color: rgb(163, 21, 21);">SendMessage</span>(<span class="hljs-params"><span class="hljs-keyword" style="color: rgb(0, 0, 255);">string</span> message</span>)
    </span>{
<span class="hljs-meta" style="color: rgb(43, 145, 175);">#<span class="hljs-meta-keyword">if</span> WINDOWS</span>

        <span class="hljs-keyword" style="color: rgb(0, 0, 255);">if</span> (!LanguageModel.IsAvailable())
        {
            <span class="hljs-keyword" style="color: rgb(0, 0, 255);">var</span> op = <span class="hljs-keyword" style="color: rgb(0, 0, 255);">await</span> LanguageModel.MakeAvailableAsync();
        }

        <span class="hljs-keyword" style="color: rgb(0, 0, 255);">using</span> LanguageModel languageModel = <span class="hljs-keyword" style="color: rgb(0, 0, 255);">await</span> LanguageModel.CreateAsync();
        <span class="hljs-keyword" style="color: rgb(0, 0, 255);">var</span> result = <span class="hljs-keyword" style="color: rgb(0, 0, 255);">await</span> languageModel.GenerateResponseAsync(message);
        Response = result.Response;
<span class="hljs-meta" style="color: rgb(43, 145, 175);">#<span class="hljs-meta-keyword">else</span></span>
        Response = <span class="hljs-string" style="color: rgb(163, 21, 21);">"Design-time response...."</span>;
<span class="hljs-meta" style="color: rgb(43, 145, 175);">#<span class="hljs-meta-keyword">endif</span></span>
    }
}
</pre>



<p>Next we&#8217;ll set an instance of the <code>MainViewModel</code> as the DataContext on the MainPage.</p>



<pre class="hljs" style="display: block; overflow-x: auto; padding: 0.5em; background: rgb(255, 255, 255); color: rgb(0, 0, 0);"><span class="hljs-function"><span class="hljs-keyword" style="color: rgb(0, 0, 255);">public</span> <span class="hljs-title" style="color: rgb(163, 21, 21);">MainPage</span>(<span class="hljs-params"></span>)
</span>{
    <span class="hljs-keyword" style="color: rgb(0, 0, 255);">this</span>.InitializeComponent();
    DataContext = <span class="hljs-keyword" style="color: rgb(0, 0, 255);">new</span> MainViewModel();
}</pre>



<p>Whilst the Phi Silica APIs only work on Windows, for the purpose of designing the interface we&#8217;ll switch target to Desktop.</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2025/03/image-67e829830f6bc.png"><img loading="lazy" decoding="async" width="300" height="224" src="https://wordpressblogimages.builttoroam.com/blogimages/2025/03/image-67e829830f6bc-300x224.png" alt="" class="wp-image-3398" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2025/03/image-67e829830f6bc-300x224.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2025/03/image-67e829830f6bc.png 586w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>We&#8217;ll run the application and should see both Hot Design and Hot Reload buttons in the floating toolbar.</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2025/03/image-67e829f481cc2.png"><img loading="lazy" decoding="async" width="300" height="193" src="https://wordpressblogimages.builttoroam.com/blogimages/2025/03/image-67e829f481cc2-300x193.png" alt="" class="wp-image-3399" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2025/03/image-67e829f481cc2-300x193.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2025/03/image-67e829f481cc2-768x493.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2025/03/image-67e829f481cc2.png 938w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>Clicking the Hot Design (left) button will enter the design experience. We&#8217;ll keep things simple by adding a TextBox (message input), Button (to invoke the SendMessage method) and TextBlock (response output). The following video shows adding these elements along with databinding the elements.</p>



<figure class="wp-block-video"><video height="1080" style="aspect-ratio: 1920 / 1080;" width="1920" controls src="https://wordpressblogimages.builttoroam.com/blogimages/2025/03/Basic-Input-Made-with-Clipchamp.mp4"></video></figure>



<p>Now, with everything wired up we can switch back to the <code>PhiMessagingApp (WinAppSDK Packaged)</code> target. </p>



<p>Unfortunately, at this point you&#8217;ll likely run into the following exception:</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2025/03/image-67e8b14ec00ca.png"><img loading="lazy" decoding="async" width="300" height="132" src="https://wordpressblogimages.builttoroam.com/blogimages/2025/03/image-67e8b14ec00ca-300x132.png" alt="" class="wp-image-3400" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2025/03/image-67e8b14ec00ca-300x132.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2025/03/image-67e8b14ec00ca-1024x450.png 1024w, https://wordpressblogimages.builttoroam.com/blogimages/2025/03/image-67e8b14ec00ca-768x337.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2025/03/image-67e8b14ec00ca.png 1334w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p><code>System.Runtime.InteropServices.COMException: 'Interface not registered<br>Failed to find proxy registration for IID: {EBF3748D-1EF9-4B89-BA13-65D2B9EC04F0}.'</code></p>



<p>This exception is a result of the application running as self-contained, which is not supported by the experimental release, <a href="https://learn.microsoft.com/en-us/windows/ai/apis/phi-silica">as noted in the docs</a>.</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="414" src="https://wordpressblogimages.builttoroam.com/blogimages/2025/03/image-67e958cf87895-1024x414.png" alt="" class="wp-image-3406" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2025/03/image-67e958cf87895-1024x414.png 1024w, https://wordpressblogimages.builttoroam.com/blogimages/2025/03/image-67e958cf87895-300x121.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2025/03/image-67e958cf87895-768x311.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2025/03/image-67e958cf87895.png 1207w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p>Luckily, there&#8217;s a quick fix. We can adjust the <code>WindowsAppSDKSelfContained</code> property to false, which will resolve this issue.</p>



<pre class="hljs" style="display: block; overflow-x: auto; padding: 0.5em; background: rgb(255, 255, 255); color: rgb(0, 0, 0);"><span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">PropertyGroup</span> <span class="hljs-attr" style="color: red;">Condition</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"'$(TargetFramework)'=='net9.0-windows10.0.26100'"</span>&gt;</span>
    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">Platforms</span>&gt;</span>x86;x64;ARM64<span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">Platforms</span>&gt;</span>
    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">RuntimeIdentifiers</span>&gt;</span>win-x86;win-x64;win-arm64<span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">RuntimeIdentifiers</span>&gt;</span>
    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">WinAppSdkVersion</span>&gt;</span>1.7.250127003-experimental3<span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">WinAppSdkVersion</span>&gt;</span>
    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">WindowsAppSDKSelfContained</span>&gt;</span>false<span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">WindowsAppSDKSelfContained</span>&gt;</span>
<span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">PropertyGroup</span>&gt;</span>
</pre>



<p>Let&#8217;s go ahead and run the application and enter a prompt, &#8220;Why is the sky blue&#8221;, and see the response.</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2025/03/image-67e95807a2ea9.png"><img loading="lazy" decoding="async" width="300" height="274" src="https://wordpressblogimages.builttoroam.com/blogimages/2025/03/image-67e95807a2ea9-300x274.png" alt="" class="wp-image-3405" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2025/03/image-67e95807a2ea9-300x274.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2025/03/image-67e95807a2ea9-1024x934.png 1024w, https://wordpressblogimages.builttoroam.com/blogimages/2025/03/image-67e95807a2ea9-768x700.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2025/03/image-67e95807a2ea9.png 1327w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>As you can see from this post, it&#8217;s easy to reference Phi Silca from an Uno Platform application. Whilst the APIs are for Windows only, this can be used to light up your cross platform application with locally executing AI when running on Windows.</p>



<p></p>



<p></p>



<p></p>



<p></p>



<p></p>



<p></p>



<p></p>



<p></p>



<p></p>



<p></p>



<p></p>



<p></p>



<p></p>



<p></p>



<p></p>
<p>The post <a href="https://nicksnettravels.builttoroam.com/ai-on-windows-phi-silica/">AI on Windows: Chatting with Phi Silica</a> appeared first on <a href="https://nicksnettravels.builttoroam.com">Nick&#039;s .NET Travels</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://nicksnettravels.builttoroam.com/ai-on-windows-phi-silica/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		<enclosure length="3652314" type="video/mp4" url="https://wordpressblogimages.builttoroam.com/blogimages/2025/03/Basic-Input-Made-with-Clipchamp.mp4"/>

			</item>
		<item>
		<title>AI on Windows: Detecting NPU</title>
		<link>https://nicksnettravels.builttoroam.com/detecting-npu/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=detecting-npu</link>
					<comments>https://nicksnettravels.builttoroam.com/detecting-npu/#respond</comments>
		
		<dc:creator><![CDATA[Nick]]></dc:creator>
		<pubDate>Sun, 16 Mar 2025 03:18:18 +0000</pubDate>
				<category><![CDATA[Announcements]]></category>
		<category><![CDATA[AI]]></category>
		<category><![CDATA[Copilot]]></category>
		<category><![CDATA[Copilot Runtime]]></category>
		<category><![CDATA[Npu]]></category>
		<category><![CDATA[Windows]]></category>
		<guid isPermaLink="false">https://nicksnettravels.builttoroam.com/?p=3390</guid>

					<description><![CDATA[<p>Recently Microsoft has been promoting Copilot+ PCs as the next wave of tablets, laptops and PCs capable of handling your AI requirements. Other than having a Copilot button, what does this actually mean? In this post we&#8217;ll take a look at what makes these PCs different, how you can detect that your application is running ... <a title="AI on Windows: Detecting NPU" class="read-more" href="https://nicksnettravels.builttoroam.com/detecting-npu/" aria-label="Read more about AI on Windows: Detecting NPU">Read more</a></p>
<p>The post <a href="https://nicksnettravels.builttoroam.com/detecting-npu/">AI on Windows: Detecting NPU</a> appeared first on <a href="https://nicksnettravels.builttoroam.com">Nick&#039;s .NET Travels</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>Recently Microsoft has been promoting Copilot+ PCs as the next wave of tablets, laptops and PCs capable of handling your AI requirements. Other than having a Copilot button, what does this actually mean? In this post we&#8217;ll take a look at what makes these PCs different, how you can detect that your application is running on one of these PCs and what you might want to do with this knowledge.</p>



<p>If we ask Copilot what a Copilot+ PC is, the answer is somewhat vague, pointing out that the devices are &#8220;powered by high-performance processors&#8221; but falls short of defining them as a device that has a separate NPU. The Microsoft developer <a href="https://learn.microsoft.com/en-us/windows/ai/npu-devices/">documentation site</a> provides a more detailed explanation:</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>Copilot+ PCs are a new class of Windows 11 hardware powered by a high-performance Neural Processing Unit (NPU) — a specialized computer chip for AI-intensive processes like real-time translations and image generation—that can perform more than 40 trillion operations per second (TOPS). Copilot+ PCs provide all–day battery life and access to the most advanced AI features and models</p>
</blockquote>



<p>In addition to the consumer features that having an NPU enables (eg <a href="https://support.microsoft.com/en-au/windows/windows-studio-effects-273c1fa8-2b3f-41b1-a587-7cc7a24b62d8">Windows Studio Effects</a> and <a href="https://support.microsoft.com/en-au/windows/retrace-your-steps-with-recall-aa03f8a0-a78b-4b3e-b0a1-2eb8ac48701c">Recall</a>), it also enables developer capabilities via the <a href="https://learn.microsoft.com/en-us/windows/ai/overview">Windows Copilot Runtime</a> and associated <a href="https://learn.microsoft.com/en-us/windows/ai/apis/">APIs</a>. Of course, if you&#8217;re going to start adding features to your application that leverage the Copilot runtime, you&#8217;re going to need a way to detect if the device you&#8217;re running on supports them. </p>



<p>Currently the APIs are all in the experimental release of the Windows App Sdk, and require your device to be on the developer branch of the Windows Insider program. As the APIs are still in active development, there are some limitations. Being able to detect whether a specific feature is supported on the current devices is one such limitation. Each of the feature APIs offer an IsAvailable method (eg <code>TextRecognizer.IsAvailable()</code>) that can be used to detect if the corresponding model is ready and available. If not, you then have to call the MakeAvailableAsync method (eg <code>TextRecognizer.MakeAvailableAsync()</code>). This will fail with an exception on devices where the model isn&#8217;t supported.</p>



<p>Detecting support by attempting to invoke MakeAvailableAsync (and having to wait for the model to be downloaded) is a pretty average experience. Luckily the team behind the AI Dev Gallery have <a href="https://github.com/microsoft/ai-dev-gallery/blob/965e1c13d6a737dbd5dc874c3f773073547f831d/AIDevGallery/Utils/AppUtils.cs#L208-L304">some code</a> that can be used to detect if there&#8217;s an NPU present on the device. Here&#8217;s a snippet of the code:</p>



<pre class="hljs" style="display: block; overflow-x: auto; padding: 0.5em; background: rgb(255, 255, 255); color: rgb(0, 0, 0);"><span class="hljs-keyword" style="color: rgb(0, 0, 255);">using</span> Windows.Win32;
<span class="hljs-keyword" style="color: rgb(0, 0, 255);">using</span> Windows.Win32.Foundation;
<span class="hljs-keyword" style="color: rgb(0, 0, 255);">using</span> Windows.Win32.Graphics.DXCore;

    <span class="hljs-keyword" style="color: rgb(0, 0, 255);">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">static</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">readonly</span> Guid DXCORE_ADAPTER_ATTRIBUTE_D3D12_GENERIC_ML = <span class="hljs-keyword" style="color: rgb(0, 0, 255);">new</span>(<span class="hljs-number">0xb71b0d41</span>, <span class="hljs-number">0x1088</span>, <span class="hljs-number">0x422f</span>, <span class="hljs-number">0xa2</span>, <span class="hljs-number">0x7c</span>, <span class="hljs-number">0x2</span>, <span class="hljs-number">0x50</span>, <span class="hljs-number">0xb7</span>, <span class="hljs-number">0xd3</span>, <span class="hljs-number">0xa9</span>, <span class="hljs-number">0x88</span>);
    <span class="hljs-keyword" style="color: rgb(0, 0, 255);">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">static</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">bool</span>? _hasNpu;
    <span class="hljs-function"><span class="hljs-keyword" style="color: rgb(0, 0, 255);">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">static</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">bool</span> <span class="hljs-title" style="color: rgb(163, 21, 21);">HasNpu</span>(<span class="hljs-params"></span>)
    </span>{
        <span class="hljs-keyword" style="color: rgb(0, 0, 255);">if</span> (_hasNpu.HasValue)
        {
            <span class="hljs-keyword" style="color: rgb(0, 0, 255);">return</span> _hasNpu.Value;
        }

        IDXCoreAdapterFactory adapterFactory;
        <span class="hljs-keyword" style="color: rgb(0, 0, 255);">if</span> (PInvoke.DXCoreCreateAdapterFactory(<span class="hljs-keyword" style="color: rgb(0, 0, 255);">typeof</span>(IDXCoreAdapterFactory).GUID, <span class="hljs-keyword" style="color: rgb(0, 0, 255);">out</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">var</span> adapterFactoryObj) != HRESULT.S_OK)
        {
            <span class="hljs-keyword" style="color: rgb(0, 0, 255);">throw</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">new</span> InvalidOperationException(<span class="hljs-string" style="color: rgb(163, 21, 21);">"Failed to create adapter factory"</span>);
        }

        adapterFactory = (IDXCoreAdapterFactory)adapterFactoryObj;

        <span class="hljs-comment" style="color: green;">// First try getting all GENERIC_ML devices, which is the broadest set of adapters</span>
        <span class="hljs-comment" style="color: green;">// and includes both GPUs and NPUs; however, running this sample on an older build of</span>
        <span class="hljs-comment" style="color: green;">// Windows may not have drivers that report GENERIC_ML.</span>
        IDXCoreAdapterList adapterList;

        adapterFactory.CreateAdapterList([DXCORE_ADAPTER_ATTRIBUTE_D3D12_GENERIC_ML], <span class="hljs-keyword" style="color: rgb(0, 0, 255);">typeof</span>(IDXCoreAdapterList).GUID, <span class="hljs-keyword" style="color: rgb(0, 0, 255);">out</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">var</span> adapterListObj);
        adapterList = (IDXCoreAdapterList)adapterListObj;

        <span class="hljs-comment" style="color: green;">// Fall back to CORE_COMPUTE if GENERIC_ML devices are not available. This is a more restricted</span>
        <span class="hljs-comment" style="color: green;">// set of adapters and may filter out some NPUs.</span>
        <span class="hljs-keyword" style="color: rgb(0, 0, 255);">if</span> (adapterList.GetAdapterCount() == <span class="hljs-number">0</span>)
        {
            adapterFactory.CreateAdapterList(
                [PInvoke.DXCORE_ADAPTER_ATTRIBUTE_D3D12_CORE_COMPUTE],
                <span class="hljs-keyword" style="color: rgb(0, 0, 255);">typeof</span>(IDXCoreAdapterList).GUID,
                <span class="hljs-keyword" style="color: rgb(0, 0, 255);">out</span> adapterListObj);
            adapterList = (IDXCoreAdapterList)adapterListObj;
        }

        <span class="hljs-keyword" style="color: rgb(0, 0, 255);">if</span> (adapterList.GetAdapterCount() == <span class="hljs-number">0</span>)
        {
            <span class="hljs-keyword" style="color: rgb(0, 0, 255);">throw</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">new</span> InvalidOperationException(<span class="hljs-string" style="color: rgb(163, 21, 21);">"No compatible adapters found."</span>);
        }

        <span class="hljs-comment" style="color: green;">// Sort the adapters by preference, with hardware and high-performance adapters first.</span>
        ReadOnlySpan&lt;DXCoreAdapterPreference&gt; preferences =
        [
            DXCoreAdapterPreference.Hardware,
                DXCoreAdapterPreference.HighPerformance
        ];

        adapterList.Sort(preferences);

        List&lt;IDXCoreAdapter&gt; adapters = [];

        <span class="hljs-keyword" style="color: rgb(0, 0, 255);">for</span> (<span class="hljs-keyword" style="color: rgb(0, 0, 255);">uint</span> i = <span class="hljs-number">0</span>; i &lt; adapterList.GetAdapterCount(); i++)
        {
            IDXCoreAdapter adapter;
            adapterList.GetAdapter(i, <span class="hljs-keyword" style="color: rgb(0, 0, 255);">typeof</span>(IDXCoreAdapter).GUID, <span class="hljs-keyword" style="color: rgb(0, 0, 255);">out</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">var</span> adapterObj);
            adapter = (IDXCoreAdapter)adapterObj;

            adapter.GetPropertySize(
                DXCoreAdapterProperty.DriverDescription,
                <span class="hljs-keyword" style="color: rgb(0, 0, 255);">out</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">var</span> descriptionSize);

            <span class="hljs-keyword" style="color: rgb(0, 0, 255);">string</span> adapterDescription;
            IntPtr buffer = IntPtr.Zero;
            <span class="hljs-keyword" style="color: rgb(0, 0, 255);">try</span>
            {
                buffer = Marshal.AllocHGlobal((<span class="hljs-keyword" style="color: rgb(0, 0, 255);">int</span>)descriptionSize);
                <span class="hljs-keyword" style="color: rgb(0, 0, 255);">unsafe</span>
                {
                    adapter.GetProperty(
                        DXCoreAdapterProperty.DriverDescription,
                        descriptionSize,
                        buffer.ToPointer());
                }

                adapterDescription = Marshal.PtrToStringAnsi(buffer) ?? <span class="hljs-keyword" style="color: rgb(0, 0, 255);">string</span>.Empty;
            }
            <span class="hljs-keyword" style="color: rgb(0, 0, 255);">finally</span>
            {
                Marshal.FreeHGlobal(buffer);
            }

            <span class="hljs-comment" style="color: green;">// Remove trailing null terminator written by DXCore.</span>
            <span class="hljs-keyword" style="color: rgb(0, 0, 255);">while</span> (!<span class="hljs-keyword" style="color: rgb(0, 0, 255);">string</span>.IsNullOrEmpty(adapterDescription) &amp;&amp; adapterDescription[^<span class="hljs-number">1</span>] == <span class="hljs-string" style="color: rgb(163, 21, 21);">'\0'</span>)
            {
                adapterDescription = adapterDescription[..^<span class="hljs-number">1</span>];
            }

            adapters.Add(adapter);
            <span class="hljs-keyword" style="color: rgb(0, 0, 255);">if</span> (adapterDescription.Contains(<span class="hljs-string" style="color: rgb(163, 21, 21);">"NPU"</span>))
            {
                _hasNpu = <span class="hljs-literal" style="color: rgb(163, 21, 21);">true</span>;
                <span class="hljs-keyword" style="color: rgb(0, 0, 255);">return</span> <span class="hljs-literal" style="color: rgb(163, 21, 21);">true</span>;
            }
        }

        _hasNpu = <span class="hljs-literal" style="color: rgb(163, 21, 21);">false</span>;
        <span class="hljs-keyword" style="color: rgb(0, 0, 255);">return</span> <span class="hljs-literal" style="color: rgb(163, 21, 21);">false</span>;
    }</pre>



<p>You&#8217;ll need to add a package reference to <a href="https://github.com/microsoft/ai-dev-gallery/blob/965e1c13d6a737dbd5dc874c3f773073547f831d/AIDevGallery/AIDevGallery.csproj#L75">Microsoft.Windows.CsWin32</a> and include a <a href="https://github.com/microsoft/ai-dev-gallery/blob/main/AIDevGallery/Utils/NativeMethods.txt">NativeMethods.txt</a> file to tailor the code generator to include the required methods.</p>



<p>Once you&#8217;ve added this code, you can call the <code>HasNpu</code> method and be able to detect, without relying on exceptions being thrown, whether the device you&#8217;re running on has an Npu and thus whether it supports the Copilot Runtime. Note that you should always include exception handling around the calls to MakeAvailableAsync, as there are other reasons that this might fail and you want to ensure your application handles these scenarios gracefully.</p>



<p></p>
<p>The post <a href="https://nicksnettravels.builttoroam.com/detecting-npu/">AI on Windows: Detecting NPU</a> appeared first on <a href="https://nicksnettravels.builttoroam.com">Nick&#039;s .NET Travels</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://nicksnettravels.builttoroam.com/detecting-npu/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>AI App Builders – Re-take – TempoLabs</title>
		<link>https://nicksnettravels.builttoroam.com/ai-app-builders-re-take-tempolabs/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=ai-app-builders-re-take-tempolabs</link>
					<comments>https://nicksnettravels.builttoroam.com/ai-app-builders-re-take-tempolabs/#respond</comments>
		
		<dc:creator><![CDATA[Nick]]></dc:creator>
		<pubDate>Wed, 12 Mar 2025 08:39:28 +0000</pubDate>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[AI]]></category>
		<guid isPermaLink="false">https://nicksnettravels.builttoroam.com/?p=3382</guid>

					<description><![CDATA[<p>In my previous attempt with TempoLabs I was able to successfully build the ABN lookup scenario that I&#8217;d been testing with other app builders. I was prompted to take another look and I was even more impressed this time around. In order to do a comparison with my experience from my last attempt I started ... <a title="AI App Builders – Re-take – TempoLabs" class="read-more" href="https://nicksnettravels.builttoroam.com/ai-app-builders-re-take-tempolabs/" aria-label="Read more about AI App Builders – Re-take – TempoLabs">Read more</a></p>
<p>The post <a href="https://nicksnettravels.builttoroam.com/ai-app-builders-re-take-tempolabs/">AI App Builders – Re-take – TempoLabs</a> appeared first on <a href="https://nicksnettravels.builttoroam.com">Nick&#039;s .NET Travels</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>In my <a href="https://nicksnettravels.builttoroam.com/ai-app-builders-take-3-tempolabs/">previous attempt</a> with TempoLabs I was able to successfully build the ABN lookup scenario that I&#8217;d been testing with other app builders. I was prompted to take another look and I was even more impressed this time around. </p>



<p>In order to do a comparison with my experience from my last attempt I started from scratch again. This reset the number of prompt that I could use &#8211; last time I mentioned the number of tokens used but it would appear that they&#8217;ve changed this to list the number of prompts I&#8217;ve used.</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="270" height="109" src="https://wordpressblogimages.builttoroam.com/blogimages/2025/03/image.png" alt="" class="wp-image-3383"/></figure>



<p>As you can see from this image I&#8217;ve only used 4 out of my 10 prompts. Within this, I was able to ask it to build a cross platform application capable of returning the ABN information for a business. The workflow went pretty much the same as last time:</p>



<ul class="wp-block-list">
<li>Created a basic app that had an input page, a search results page and an error page. All working but not connected to anything real</li>



<li>Connected app to real ABN lookup service, it only returned the first result</li>



<li>Updated app to show multiple results</li>
</ul>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2025/03/image-67d17f26cbfbd.png"><img loading="lazy" decoding="async" width="300" height="233" src="https://wordpressblogimages.builttoroam.com/blogimages/2025/03/image-67d17f26cbfbd-300x233.png" alt="" class="wp-image-3385" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2025/03/image-67d17f26cbfbd-300x233.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2025/03/image-67d17f26cbfbd-768x597.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2025/03/image-67d17f26cbfbd.png 908w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2025/03/image-67d17f4c455e6.png"><img loading="lazy" decoding="async" width="300" height="255" src="https://wordpressblogimages.builttoroam.com/blogimages/2025/03/image-67d17f4c455e6-300x255.png" alt="" class="wp-image-3387" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2025/03/image-67d17f4c455e6-300x255.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2025/03/image-67d17f4c455e6-768x654.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2025/03/image-67d17f4c455e6.png 906w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>At this point, I couldn&#8217;t click on the search results to get further information, so I asked it to create a details page that included web results.</p>



<ul class="wp-block-list">
<li>Created a details page that had some placeholder/fake information about the business </li>



<li>Updated the details page to include real web search results (using <a href="https://serper.de">Serper</a>).</li>
</ul>



<figure class="wp-block-image size-medium"><img loading="lazy" decoding="async" width="300" height="255" src="https://wordpressblogimages.builttoroam.com/blogimages/2025/03/image-67d17f72c9ab9-300x255.png" alt="" class="wp-image-3388" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2025/03/image-67d17f72c9ab9-300x255.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2025/03/image-67d17f72c9ab9-768x654.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2025/03/image-67d17f72c9ab9.png 906w" sizes="auto, (max-width: 300px) 100vw, 300px" /></figure>



<p>What was particularly interesting is that it was no longer necessary for me to connect my application so Superbase in order to store the API keys (ABN lookup and Serper). Of course, this meant I (and anyone else using the tool) needed to enter them on first run but it was nice to not automatically take on the Superbase dependency just to mock something out.</p>



<p>Given how far I was able to get in just over 10minutes, it&#8217;s staggering how far these AI tools have come. Comments like &#8220;<a href="https://www.tomshardware.com/tech-industry/artificial-intelligence/linus-torvalds-reckons-ai-is-90-percent-marketing-and-10-percent-reality">90% marketing and 10% reality</a>&#8221; from industry greats like Linus Torvalds indicate how some in the industy are going to be caught flat footed if they&#8217;re not already experimenting with AI tools.</p>
<p>The post <a href="https://nicksnettravels.builttoroam.com/ai-app-builders-re-take-tempolabs/">AI App Builders – Re-take – TempoLabs</a> appeared first on <a href="https://nicksnettravels.builttoroam.com">Nick&#039;s .NET Travels</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://nicksnettravels.builttoroam.com/ai-app-builders-re-take-tempolabs/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Building Cross Platform Applications using Hot Design and Codespaces with Uno Platform and No IDE</title>
		<link>https://nicksnettravels.builttoroam.com/uno-platform-codespaces/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=uno-platform-codespaces</link>
					<comments>https://nicksnettravels.builttoroam.com/uno-platform-codespaces/#comments</comments>
		
		<dc:creator><![CDATA[Nick]]></dc:creator>
		<pubDate>Wed, 26 Feb 2025 06:53:13 +0000</pubDate>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[Codespaces]]></category>
		<category><![CDATA[Hot Design]]></category>
		<category><![CDATA[Uno]]></category>
		<category><![CDATA[Uno Platform]]></category>
		<category><![CDATA[WASM]]></category>
		<category><![CDATA[WebAssembly]]></category>
		<guid isPermaLink="false">https://nicksnettravels.builttoroam.com/?p=3357</guid>

					<description><![CDATA[<p>Ok, so the title is a bit of a mouthful but here&#8217;s the scenario &#8211; you want to quickly spin up an application but you don&#8217;t want to mess around downloading and installing any of the usual development tools required to build an Uno Platform application. In this post we&#8217;re going to walk through creating ... <a title="Building Cross Platform Applications using Hot Design and Codespaces with Uno Platform and No IDE" class="read-more" href="https://nicksnettravels.builttoroam.com/uno-platform-codespaces/" aria-label="Read more about Building Cross Platform Applications using Hot Design and Codespaces with Uno Platform and No IDE">Read more</a></p>
<p>The post <a href="https://nicksnettravels.builttoroam.com/uno-platform-codespaces/">Building Cross Platform Applications using Hot Design and Codespaces with Uno Platform and No IDE</a> appeared first on <a href="https://nicksnettravels.builttoroam.com">Nick&#039;s .NET Travels</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>Ok, so the title is a bit of a mouthful but here&#8217;s the scenario &#8211; you want to quickly spin up an application but you don&#8217;t want to mess around downloading and installing any of the usual development tools required to build an <a href="https://platform.uno/dotnettravels-uno">Uno Platform</a> application. In this post we&#8217;re going to walk through creating an Uno Platform application directly in GitHub using GitHub Codespaces and of course using Hot Design to build out the user interface.</p>



<p>Let&#8217;s get started by creating a new repository in GitHub. This will be an empty repository, except for a default .gitignore file. Since we&#8217;re building a .NET application, it makes sense to go with the Visual Studio .gitignore template.</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67bea6d8df3c4.png"><img loading="lazy" decoding="async" width="300" height="240" src="https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67bea6d8df3c4-300x240.png" alt="" class="wp-image-3358" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67bea6d8df3c4-300x240.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67bea6d8df3c4-1024x818.png 1024w, https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67bea6d8df3c4-768x613.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67bea6d8df3c4.png 1210w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>Next step is to open the repository in Codespaces. This can be done from the dropdown on the Code button.</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67bea7485f04b.png"><img loading="lazy" decoding="async" width="300" height="138" src="https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67bea7485f04b-300x138.png" alt="" class="wp-image-3359" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67bea7485f04b-300x138.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67bea7485f04b-768x353.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67bea7485f04b.png 965w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>When Codespaces opens it looks and feels very similar to VS Code, just running within the bounds of the browser</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67bea79c68658.png"><img loading="lazy" decoding="async" width="300" height="240" src="https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67bea79c68658-300x240.png" alt="" class="wp-image-3360" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67bea79c68658-300x240.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67bea79c68658-1024x818.png 1024w, https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67bea79c68658-768x613.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67bea79c68658.png 1210w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>Since we&#8217;re going to be creating an Uno Platform application, let&#8217;s go ahead and install the Uno Platform extensions</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67bea7d3a929f.png"><img loading="lazy" decoding="async" width="300" height="240" src="https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67bea7d3a929f-300x240.png" alt="" class="wp-image-3361" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67bea7d3a929f-300x240.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67bea7d3a929f-1024x818.png 1024w, https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67bea7d3a929f-768x613.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67bea7d3a929f.png 1210w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>This will take a minute or two as it needs to install not only the Uno Platform extension but also the C# and C# Dev Kit extensions.</p>



<p>The next thing we need to do is to make sure that we have .NET 9 installed &#8211; by default Codespaces currently has version 8.0.404 of the .NET SDK installed. Follow <a href="https://learn.microsoft.com/en-us/dotnet/core/install/linux-scripted-manual#scripted-install">the instructions</a> to install .NET 9.</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67bea9673f85d.png"><img loading="lazy" decoding="async" width="300" height="270" src="https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67bea9673f85d-300x270.png" alt="" class="wp-image-3362" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67bea9673f85d-300x270.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67bea9673f85d-768x690.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67bea9673f85d.png 849w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>Next up, is to run uno-check. This is available via the command palette. </p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67bea9a18e53c.png"><img loading="lazy" decoding="async" width="300" height="136" src="https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67bea9a18e53c-300x136.png" alt="" class="wp-image-3363" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67bea9a18e53c-300x136.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67bea9a18e53c-768x348.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67bea9a18e53c.png 946w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>As uno-check runs, you can follow along in the Terminal and enter &#8220;y&#8221; when prompted to install the latest uno.sdk and the uno.templates.</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67beaa0367c1e.png"><img loading="lazy" decoding="async" width="300" height="234" src="https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67beaa0367c1e-300x234.png" alt="" class="wp-image-3364" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67beaa0367c1e-300x234.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67beaa0367c1e.png 723w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>Once uno-check completes, we&#8217;re setup and ready to create the application. We&#8217;re going to use the <code>dotnet new unoapp</code> command to create a new application. The full command is</p>



<p><code>dotnet new unoapp -o MyCodeSpaceApp -vscode</code></p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67beae661f6ec.png"><img loading="lazy" decoding="async" width="300" height="64" src="https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67beae661f6ec-300x64.png" alt="" class="wp-image-3365" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67beae661f6ec-300x64.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67beae661f6ec.png 723w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>If you want assistance with the various options available for the unoapp template, go to <a href="https://new.platform.uno/">https://new.platform.uno/</a> and select the options you want. At the end of the process, you&#8217;ll have a <code>dotnet new</code> command you can simply paste into the Terminal.</p>



<p>In order for the Uno Platform tooling to work we need to open the newly created application by invoking Open Folder from the File menu, and then selecting the newly created application folder.</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67beaeb96828d.png"><img loading="lazy" decoding="async" width="300" height="137" src="https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67beaeb96828d-300x137.png" alt="" class="wp-image-3366" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67beaeb96828d-300x137.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67beaeb96828d-768x350.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67beaeb96828d.png 913w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>At the bottom of the screen you should now see the solution file highlighed in red &#8211; you need to click this in order to select the project file from the dropdown at the top of the screen.</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67beaf15ca160.png"><img loading="lazy" decoding="async" width="300" height="262" src="https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67beaf15ca160-300x262.png" alt="" class="wp-image-3367" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67beaf15ca160-300x262.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67beaf15ca160-1024x894.png 1024w, https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67beaf15ca160-768x670.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67beaf15ca160.png 1203w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>At this point you may notice a prompt requesting that you register/sign-in &#8211; this won&#8217;t currently work as it will attempt to launch a skia desktop application (the team is aware of this limitation). For now to work around this, you can register and sign in via Visual Studio, VS Code or Rider, and then copy the license files into your codespace. The license files are located at <code>C:\Users\{User}\AppData\Local\Uno Platform</code>. Copy the whole folder into a folde in Codespaces by creating a Licensing folder, and dragging the files from File Explorer into the Licensing folder in Codespaces. </p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67beb134e2963.png"><img loading="lazy" decoding="async" width="226" height="300" src="https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67beb134e2963-226x300.png" alt="" class="wp-image-3369" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67beb134e2963-226x300.png 226w, https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67beb134e2963.png 354w" sizes="auto, (max-width: 226px) 100vw, 226px" /></a></figure>



<p>These file then need to be copied to the location where Uno Platform is expecting the license: <code>~/.local/share/'Uno Platform'</code>. In the Terminal navigate to the Licensing folder than then invoke:</p>



<p><code>cp <em>.</em> -R ~/.local/share/'Uno Platform'</code></p>



<p>With the copied licensing files in place, they should auto-matically renew without a prompt. However, if the license does expire, you may need to repeat this process (at least until Uno Platform is updated to support signing in via a browser based app).</p>



<p>Before you can run the application, you need to change the target to .net9-browserwasm.</p>



<figure class="wp-block-image size-medium is-resized"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67beaf604fcec.png"><img loading="lazy" decoding="async" width="300" height="258" src="https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67beaf604fcec-300x258.png" alt="" class="wp-image-3368" style="width:301px;height:auto" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67beaf604fcec-300x258.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67beaf604fcec-1024x881.png 1024w, https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67beaf604fcec-768x661.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67beaf604fcec.png 1209w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>At this point, if you switch to the Output tab and select the Uno Platform &#8211; Hot Reload option from the dropdown, you should see that the license has been successfully refreshed.</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="541" src="https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67beb3955cc9b-1024x541.png" alt="" class="wp-image-3371" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67beb3955cc9b-1024x541.png 1024w, https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67beb3955cc9b-300x158.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67beb3955cc9b-768x406.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67beb3955cc9b.png 1140w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p>Now we can go ahead and run the application by invoking</p>



<p><code>dotnet run -f net9.0-browserwasm</code> </p>



<p>This will build and run the wasm target. Once it&#8217;s ready, a prompt will appear giving you the option to Open in Browser. Before doing this, you should click the Make Public button.</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="138" src="https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67beb4c1f27df-1024x138.png" alt="" class="wp-image-3372" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67beb4c1f27df-1024x138.png 1024w, https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67beb4c1f27df-300x41.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67beb4c1f27df-768x104.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67beb4c1f27df.png 1148w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p>When you click the Make Public button, the notification will go away but you can still open the application in the browser by ctrl-clicking on the App url. This will successfully launch the application.</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67beb5584c4cb.png"><img loading="lazy" decoding="async" width="300" height="205" src="https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67beb5584c4cb-300x205.png" alt="" class="wp-image-3373" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67beb5584c4cb-300x205.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67beb5584c4cb-1024x699.png 1024w, https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67beb5584c4cb-768x524.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67beb5584c4cb.png 1113w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>However, you&#8217;ll notice that both the Hot Reload and Hot Design buttons are red, indicating that they&#8217;re not connected correctly. To fix this we need to do two things back in our Codespace.</p>



<p>From the Ports tab, make sure that the Visibility of all ports is set to Public</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67beb5d281ac9.png"><img loading="lazy" decoding="async" width="300" height="115" src="https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67beb5d281ac9-300x115.png" alt="" class="wp-image-3374" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67beb5d281ac9-300x115.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67beb5d281ac9-1024x391.png 1024w, https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67beb5d281ac9-768x294.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67beb5d281ac9.png 1112w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>Not that you should only have two ports but if you happen to have an additional port (like in the above image) you need to return to the Output tab and confirm what port number DevServer is running on. In my case it&#8217;s 39681, so you want to make sure this port, along with the port for the web application (5000 in my case) are set to Public.</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67beb635705f0.png"><img loading="lazy" decoding="async" width="300" height="126" src="https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67beb635705f0-300x126.png" alt="" class="wp-image-3375" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67beb635705f0-300x126.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67beb635705f0-768x323.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67beb635705f0.png 791w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>Ok, so the last thing we need to do is to compensate for an issue where the Uno Platform isn&#8217;t assigning the correct hostname during the compilation, meaning that Hot Reload isn&#8217;t connecting correctly. To fix this we need to add a couple of properties to our csproj file.</p>



<pre class="wp-block-code"><code>&lt;UnoRemoteControlHost>symmetrical-space-orbit-x5jgp5qpgjcqp7-39681.app.github.dev&lt;/UnoRemoteControlHost>
&lt;UnoRemoteControlPort>443&lt;/UnoRemoteControlPort></code></pre>



<p>Importantly, the UnoRemoteControlPort should always be 443. The UnoRemoteControlHost should be the Fowarded Address that correlates to the Port that DevServer is listening on. The port was 39681 in my case, so the UnoRemoteControlHost is <code>symmetrical-space-orbit-x5jgp5qpgjcqp7-39681.app.github.dev</code>.</p>



<p>Return to the Terminal and restart the web by rerunning the <code>dotnet run</code> command. In some cases, Codespaces will revert the web application port to private, so you may need to set that back to public.</p>



<p>If, after restarting the web application, the Hot Reload icon is still appearing red, you may need to remove the UnoRemoteControlPort from the csproj.user file.</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67beb7cf7cf8f.png"><img loading="lazy" decoding="async" width="300" height="136" src="https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67beb7cf7cf8f-300x136.png" alt="" class="wp-image-3376" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67beb7cf7cf8f-300x136.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67beb7cf7cf8f-1024x464.png 1024w, https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67beb7cf7cf8f-768x348.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67beb7cf7cf8f.png 1219w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>Remove this line and save the file. Then restart the web application.</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67beb867dcf98.png"><img loading="lazy" decoding="async" width="300" height="205" src="https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67beb867dcf98-300x205.png" alt="" class="wp-image-3377" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67beb867dcf98-300x205.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67beb867dcf98-1024x699.png 1024w, https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67beb867dcf98-768x524.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67beb867dcf98.png 1113w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>Now you can go ahead and click on the Hot Design button, and enter the design mode for your application.</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67beb89e9cf25.png"><img loading="lazy" decoding="async" width="300" height="205" src="https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67beb89e9cf25-300x205.png" alt="" class="wp-image-3378" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67beb89e9cf25-300x205.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67beb89e9cf25-1024x699.png 1024w, https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67beb89e9cf25-768x524.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67beb89e9cf25.png 1113w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>As you make changes in Hot Design, these are going to be reflected back into the XAML file(s) of your application.</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67beb8f56ae7a.png"><img loading="lazy" decoding="async" width="300" height="205" src="https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67beb8f56ae7a-300x205.png" alt="" class="wp-image-3379" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67beb8f56ae7a-300x205.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67beb8f56ae7a-1024x699.png 1024w, https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67beb8f56ae7a-768x524.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67beb8f56ae7a.png 1112w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>As you can see, you can get from an empty repository through to a running application in Codespaces in a few minutes. There are a couple of rough corners right now, but expect that this process will get easier as we continue to roll out new and improved tooling for the Uno Platform. Also, don&#8217;t forget that in addition to creating a web application (WASM), you&#8217;ve also created an application that will work on Windows (WinUI and/or Skia), iOS, Android, Mac (MacCatalyst and/or Skia) and Linux.</p>
<p>The post <a href="https://nicksnettravels.builttoroam.com/uno-platform-codespaces/">Building Cross Platform Applications using Hot Design and Codespaces with Uno Platform and No IDE</a> appeared first on <a href="https://nicksnettravels.builttoroam.com">Nick&#039;s .NET Travels</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://nicksnettravels.builttoroam.com/uno-platform-codespaces/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title>AI App Builders – Take 3 – TempoLabs</title>
		<link>https://nicksnettravels.builttoroam.com/ai-app-builders-take-3-tempolabs/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=ai-app-builders-take-3-tempolabs</link>
					<comments>https://nicksnettravels.builttoroam.com/ai-app-builders-take-3-tempolabs/#respond</comments>
		
		<dc:creator><![CDATA[Nick]]></dc:creator>
		<pubDate>Sun, 23 Feb 2025 04:10:48 +0000</pubDate>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[AI]]></category>
		<category><![CDATA[Tools]]></category>
		<guid isPermaLink="false">https://nicksnettravels.builttoroam.com/?p=3347</guid>

					<description><![CDATA[<p>I was watching overview of TempoLabs and my initial impression was &#8220;wow, that&#8217;s a lot of stuff&#8221; as they not only have AI generation but it seems they understand at least the basics of a software devlelopment process. When you invoke the AI generation, it firstly parrots back its understanding of what you&#8217;ve asked for. ... <a title="AI App Builders – Take 3 – TempoLabs" class="read-more" href="https://nicksnettravels.builttoroam.com/ai-app-builders-take-3-tempolabs/" aria-label="Read more about AI App Builders – Take 3 – TempoLabs">Read more</a></p>
<p>The post <a href="https://nicksnettravels.builttoroam.com/ai-app-builders-take-3-tempolabs/">AI App Builders – Take 3 – TempoLabs</a> appeared first on <a href="https://nicksnettravels.builttoroam.com">Nick&#039;s .NET Travels</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>I was watching <a href="https://www.youtube.com/watch?v=PM35mru7Ijw">overview of TempoLabs</a> and my initial impression was &#8220;wow, that&#8217;s a lot of stuff&#8221; as they not only have AI generation but it seems they understand at least the basics of a software devlelopment process. When you invoke the AI generation, it firstly parrots back its understanding of what you&#8217;ve asked for. It then proceeds to generate mermaid diagram(s) and then on to the generation of wireframes. In this post we&#8217;ll take a look at <a href="https://www.tempo.new/">TempoLabs </a>to see how far we can get with our challenge of building an ABN lookup application.</p>



<p>As with the previous attempts, my input to the AI prompt is fairly simple: Create a cross platform application that can lookup the ABN of a business using an online service.</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67ba994ccdb2c.png"><img loading="lazy" decoding="async" width="234" height="300" src="https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67ba994ccdb2c-234x300.png" alt="" class="wp-image-3348" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67ba994ccdb2c-234x300.png 234w, https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67ba994ccdb2c-800x1024.png 800w, https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67ba994ccdb2c-768x983.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67ba994ccdb2c.png 932w" sizes="auto, (max-width: 234px) 100vw, 234px" /></a></figure>



<p>As the AI starts to get going I&#8217;m suitably impressed with the interpretation of my input and the subsequent mermaid diagram it generates. However, the experience rapidly when downhill from there as the wireframe generation phase seemed to break. I tried the usual reqeusts to the AI prompt for it to fix the errors but after multiple attempts it wasn&#8217;t getting very far. I even tried deleting the partially generated UI, only for it to again fail to generate the wireframes.</p>



<p>Ironically, as I was putting this post together, I returned to the app I was creating in TempoLabs and the screen must have refreshed because there was my generated wireframes.</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67ba9a11bf146.png"><img loading="lazy" decoding="async" width="300" height="176" src="https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67ba9a11bf146-300x176.png" alt="" class="wp-image-3349" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67ba9a11bf146-300x176.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67ba9a11bf146-1024x602.png 1024w, https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67ba9a11bf146-768x452.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67ba9a11bf146-1536x903.png 1536w, https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67ba9a11bf146-2048x1204.png 2048w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>Now that we had a UI, it needed to be connected to the ABN lookup service. After a couple of simple prompts, the AI had built a service that would then connect to the ABN lookup service. I was moderately surprised that it was indeed able to call the service. Interestingly, it didn&#8217;t quite understand my initial prompt which I was looking to retrieve the ABN for a business; instead it assumed I had an ABN that I needed to lookup. This was easily rectified by a prompt that clarified that I wanted the ABN for a business name that would be entered. </p>



<p>The result was a basic UI that would indeed lookup a business name.</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="772" src="https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67ba9bd4c81ff-1024x772.png" alt="" class="wp-image-3350" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67ba9bd4c81ff-1024x772.png 1024w, https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67ba9bd4c81ff-300x226.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67ba9bd4c81ff-768x579.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67ba9bd4c81ff.png 1372w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p>The only point I would make is that during this process the AI realised that I needed to enter a API key in order to access the service. Instead of prompting me for the GUID and then putting it somewhere sensible (as other services like Lovable have done), it instead suggested I needed to create a .env file and add the GUID myself&#8230;.. I promptly asked the AI to do it for me.</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67ba9d57d5b49.png"><img loading="lazy" decoding="async" width="142" height="300" src="https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67ba9d57d5b49-142x300.png" alt="" class="wp-image-3351" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67ba9d57d5b49-142x300.png 142w, https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67ba9d57d5b49-484x1024.png 484w, https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67ba9d57d5b49.png 537w" sizes="auto, (max-width: 142px) 100vw, 142px" /></a></figure>



<p>I then requested that the UI be changed to show all results. Somehow the AI generated code that caused an error, which it detected and then prompted me as to what to do. </p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67ba9d9150fb9.png"><img loading="lazy" decoding="async" width="300" height="236" src="https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67ba9d9150fb9-300x236.png" alt="" class="wp-image-3352" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67ba9d9150fb9-300x236.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67ba9d9150fb9.png 517w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>I clicked the Fix with AI and the issue was then solved, resulting in a UI that did indeed return all the search results.</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67ba9de70be06.png"><img loading="lazy" decoding="async" width="300" height="209" src="https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67ba9de70be06-300x209.png" alt="" class="wp-image-3353" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67ba9de70be06-300x209.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67ba9de70be06-1024x714.png 1024w, https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67ba9de70be06-768x535.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67ba9de70be06.png 1306w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>The weird thing about this exchange is that I&#8217;m not in control of the changes the AI is making, so when it makes a mistake and causes an error, it should be able to automatically iterate until it&#8217;s either stuck (unable to fix the issue) or it&#8217;s fixed the error. It would seem that prompting me with the error should be a last resort.</p>



<p>Ok at this point I&#8217;m going to give TempoLabs the win as I feel it&#8217;s been able to achieve what others haven&#8217;t &#8211; a basic application that&#8217;s able to retrieve ABN numbers for a business. Not withstanding the rough edges in places, this was a surprisingly good experience. </p>



<p>Could you continue building a real application with this tool? I think you could. However, you would probably have to sign up to one of their paid tiers because just this small set of experimentation used up over half (350K of 500K) of the daily tokens you get on the free tier. </p>



<p>Anyhow, here&#8217;s an update on the current scoreboard.</p>



<p><strong>Human Developers: 2 AI Code Builders: 2</strong></p>



<p>Also for reference here&#8217;s the current ordering of the services I&#8217;ve tried to date:</p>



<ul class="wp-block-list">
<li>TempoLabs</li>



<li><a href="https://nicksnettravels.builttoroam.com/ai-app-builders-take-2-lovable/">Lovable</a></li>



<li><a href="https://nicksnettravels.builttoroam.com/ai-app-builders-take-1/">Co.dev</a></li>
</ul>
<p>The post <a href="https://nicksnettravels.builttoroam.com/ai-app-builders-take-3-tempolabs/">AI App Builders – Take 3 – TempoLabs</a> appeared first on <a href="https://nicksnettravels.builttoroam.com">Nick&#039;s .NET Travels</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://nicksnettravels.builttoroam.com/ai-app-builders-take-3-tempolabs/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>AI App Builders – Take 2 – Lovable</title>
		<link>https://nicksnettravels.builttoroam.com/ai-app-builders-take-2-lovable/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=ai-app-builders-take-2-lovable</link>
					<comments>https://nicksnettravels.builttoroam.com/ai-app-builders-take-2-lovable/#respond</comments>
		
		<dc:creator><![CDATA[Nick]]></dc:creator>
		<pubDate>Wed, 19 Feb 2025 12:53:33 +0000</pubDate>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[AI]]></category>
		<category><![CDATA[Tools]]></category>
		<guid isPermaLink="false">https://nicksnettravels.builttoroam.com/?p=3342</guid>

					<description><![CDATA[<p>Following from my previous attempt at building a simple app to retrieve the ABN for a business, I figured I&#8217;d give lovable.dev a go. This will be a quick post to cover some of the likes/dislikes from this process. Firstly I have to hand it to Lovable, they&#8217;ve done a great job with the user ... <a title="AI App Builders &#8211; Take 2 &#8211; Lovable" class="read-more" href="https://nicksnettravels.builttoroam.com/ai-app-builders-take-2-lovable/" aria-label="Read more about AI App Builders &#8211; Take 2 &#8211; Lovable">Read more</a></p>
<p>The post <a href="https://nicksnettravels.builttoroam.com/ai-app-builders-take-2-lovable/">AI App Builders &#8211; Take 2 &#8211; Lovable</a> appeared first on <a href="https://nicksnettravels.builttoroam.com">Nick&#039;s .NET Travels</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>Following from my <a href="https://nicksnettravels.builttoroam.com/ai-app-builders-take-1">previous attempt</a> at building a simple app to retrieve the ABN for a business, I figured I&#8217;d give <a href="https://lovable.dev/">lovable.dev</a> a go. This will be a quick post to cover some of the likes/dislikes from this process.</p>



<p>Firstly I have to hand it to Lovable, they&#8217;ve done a great job with the user experience of the site. It&#8217;s really easy to get started, all from an initial prompt, and when you need things along the way (eg supabase) it&#8217;s always there to guide you &#8211; it&#8217;s like they&#8217;ve run this process a thousand times and have ironed out all the kinks.</p>



<p>I also loved that out of the box, the application that was created was simple, yet stylish, and overall worked even in the context of a mobile/desktop application.</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67b5d2261e96f.png"><img loading="lazy" decoding="async" width="300" height="278" src="https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67b5d2261e96f-300x278.png" alt="" class="wp-image-3345" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67b5d2261e96f-300x278.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67b5d2261e96f.png 626w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>I followed a similar process to my previous attempt, however I was a little more vague when it came to the webservice I wanted to call. At the prompt I entered &#8220;connect this to an abn lookup service available online&#8221;. I was totally blown away that it was able to find the correct service with it&#8217;s response being &#8220;I&#8217;ll help you connect the application to a real ABN lookup service. The Australian Business Register (ABR) provides a web API for looking up ABN details. To use it, we&#8217;ll need to register for an ABR GUID (authentication key).&#8221; </p>



<p>I was then prompted to enter the ABR GUID (which I have from previously requesting access to the service), connect to Supabase and approve changes to the database schema to store historical searches (all pretty cool stuff).</p>



<p>Ok, so this is where the wheels fell of the bus. Despite it&#8217;s best attempt, Lovable wasn&#8217;t able to call the service with any success. Furthermore, it actually made a number of changes to the app that actually broke it, or raised an error when calling the ABN lookup service. Each time, I was required to prompt Lovable to fix the issue&#8230;&#8230; surely the AI should be able to run the site, test it and then iterate until it works.</p>



<p>Unfortunately it was at this point that I ran out of my free prompts. To continue I had to sign up to one of the planes&#8230;. despite not having anything that resembles a working app.</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="507" src="https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67b54fc9f21cc-1024x507.png" alt="" class="wp-image-3343" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67b54fc9f21cc-1024x507.png 1024w, https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67b54fc9f21cc-300x149.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67b54fc9f21cc-768x380.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67b54fc9f21cc-1536x760.png 1536w, https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67b54fc9f21cc.png 1903w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p>I&#8217;m not at the point where I&#8217;m going to be spending money on these services, so I&#8217;ll wrap up the test drive of Lovable. I was quite impressed, so I suspect that AI should both get a point (for being quite proactive) and drop a point (for not being able to get the service calling working). If you&#8217;re keeping score:</p>



<p><strong>Human Developers: 2 AI Code Builders: 1</strong></p>
<p>The post <a href="https://nicksnettravels.builttoroam.com/ai-app-builders-take-2-lovable/">AI App Builders &#8211; Take 2 &#8211; Lovable</a> appeared first on <a href="https://nicksnettravels.builttoroam.com">Nick&#039;s .NET Travels</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://nicksnettravels.builttoroam.com/ai-app-builders-take-2-lovable/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>AI App Builders – Take 1 – co.dev</title>
		<link>https://nicksnettravels.builttoroam.com/ai-app-builders-take-1/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=ai-app-builders-take-1</link>
					<comments>https://nicksnettravels.builttoroam.com/ai-app-builders-take-1/#respond</comments>
		
		<dc:creator><![CDATA[Nick]]></dc:creator>
		<pubDate>Sun, 09 Feb 2025 05:48:47 +0000</pubDate>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[AI]]></category>
		<category><![CDATA[Tools]]></category>
		<guid isPermaLink="false">https://nicksnettravels.builttoroam.com/?p=3336</guid>

					<description><![CDATA[<p>I figured I&#8217;d take some of these AI app builders for a run to see how capable they are. To date I&#8217;ve mainly just been taking advantage of the AI capabilities that are progressively being added to VS Code and Visual Studio though tooling such as Copilot but I&#8217;m hoping that these AI app builders, ... <a title="AI App Builders &#8211; Take 1 &#8211; co.dev" class="read-more" href="https://nicksnettravels.builttoroam.com/ai-app-builders-take-1/" aria-label="Read more about AI App Builders &#8211; Take 1 &#8211; co.dev">Read more</a></p>
<p>The post <a href="https://nicksnettravels.builttoroam.com/ai-app-builders-take-1/">AI App Builders &#8211; Take 1 &#8211; co.dev</a> appeared first on <a href="https://nicksnettravels.builttoroam.com">Nick&#039;s .NET Travels</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>I figured I&#8217;d take some of these AI app builders for a run to see how capable they are. To date I&#8217;ve mainly just been taking advantage of the AI capabilities that are progressively being added to VS Code and Visual Studio though tooling such as Copilot but I&#8217;m hoping that these AI app builders, at least for basic applications, can cut hours, days maybe months off the typical app development cycle. In this post I&#8217;ll cover what I see as the pros and cons of the app building experience.</p>



<p>In this first post we&#8217;re going to pick on <a href="https://www.co.dev/">co.dev</a> that claims to be able to convert &#8220;text to app in minutes&#8221;. </p>



<p>First up, as you can imagine, there&#8217;s a mandatory sign-up/login flow &#8211; AI isn&#8217;t cheap and they want to ensure you&#8217;re not a bot or some other AI service. As I&#8217;ll be testing out their services, I don&#8217;t mind this requirement but it does make me wonder whether organisations will be open to their devs having to sign into this online service, effectively giving over access to some of their enterprise data. Data security is definitely going to be an interesting space and it&#8217;ll be a challenge for organisations to find the balance between locking down their data versus providing access to enable the generation of data driven applications by these AI tools.</p>



<p>I figured I&#8217;d try out building a relatively simple application that accepts a single user input, the name of a business, and calls a web api to retrieve the Australian Business Number (publically available <a href="https://abr.business.gov.au/Documentation/WebServiceMethods">here</a>). Already I know there are a couple of wrinkles here, such as the web api requiring an API key and there are two different formats, SOAP and JSON, and a couple of different endpoint methods to select from. However, the web api is by no means complex, and a typical developer, using tooling built into VS (eg Add Web Service), could get an API call going in say 10-15mins.</p>



<p>The overall experience of starting a new project was quite good as it stepped me through a number of prompts, including setting up Supabase. Only minor quirk was that after opening a different tab to setup Supabase I had to convince co.dev to refresh in order to see my new Supabase project). </p>



<p>I was prompted as to what I wanted to create, so I entered &#8220;A cross-platform application that can be used to look up the ABN for an organisation&#8221;. After a few minutes a skeleton application was created. I liked the fact that it had wired up authentication, which is oftern a challenging aspect, and I was able to create an account and login. I didn&#8217;t like that despite saying I wanted a cross-platform application, it just built me a web application. I wasn&#8217;t in any illusion that I was going to get an actual cross platform application but it would have been nice for it to create something that didn&#8217;t look like a generic web portal.</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67a83f0c1d490.png"><img loading="lazy" decoding="async" width="300" height="207" src="https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67a83f0c1d490-300x207.png" alt="" class="wp-image-3337" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67a83f0c1d490-300x207.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67a83f0c1d490-1024x705.png 1024w, https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67a83f0c1d490-768x529.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67a83f0c1d490-1536x1058.png 1536w, https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67a83f0c1d490.png 1811w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>I also liked that in the Chat pane it was describing what was going on, giving some insight into how the AI was thinking about/changing the application. </p>



<p>The current Dashboard page was blank, so I entered a prompt to build out the functionality: &#8220;On the dashboard page add an input box where the user can type the name of the business they want to search for and a submit button. When the user clicks the submit button, use the input to call the search api at https://abr.business.gov.au/Documentation/WebServiceMethods&#8221;. Again, the AI went off an processed for a few minutes before it came back and updated the dashboard page.</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67a83fda65fe1.png"><img loading="lazy" decoding="async" width="300" height="185" src="https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67a83fda65fe1-300x185.png" alt="" class="wp-image-3338" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67a83fda65fe1-300x185.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67a83fda65fe1-1024x631.png 1024w, https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67a83fda65fe1-768x473.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67a83fda65fe1.png 1188w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>Despite again feeling that this was more of a web portal than an actual application, I realised that the AI was indeed adding value. I&#8217;d created the basics on this application in under 5 minutes, so who was I to complain about the way it looked.</p>



<p>Ok, so the real test was when I entered the name of a business and clicked the Search button. </p>



<p><strong>FAIL</strong> </p>



<p>It raised an error &#8211; I figured this was likely to happen, so I asked AI to investigate the error (you can click on the error in the UI and add it as context to the chat, which was nice). The AI went off, churned for a bit, made some changes (switched from JSON to SOAP services) and came back claiming it had fixed the issue. I entered a name and clicked Search. </p>



<p><strong>FAIL</strong></p>



<p>I repeatedly tried to convince the AI to make changes to fix the issue calling the web api. This included one prompt where I told it to continue working until it could successfully call the web api.</p>



<p><strong>FAIL,</strong></p>



<p><strong>FAIL,</strong></p>



<p><strong>FAIL,</strong></p>



<p><strong>FAIL,</strong></p>



<p>At this point my experiment was over, and given I wasn&#8217;t paying for the premium offering, I didn&#8217;t see a way to take a look at the code to see what the issue was. The way I see it is that there are definitely some time savings to be had but as soon as AI has to go do something of even moderate complexity, it gets stuck.</p>



<p><strong>Human Developers: 1      AI Code Builders: 0</strong></p>



<p>Let&#8217;s try out another AI builder and see how we get on.</p>
<p>The post <a href="https://nicksnettravels.builttoroam.com/ai-app-builders-take-1/">AI App Builders &#8211; Take 1 &#8211; co.dev</a> appeared first on <a href="https://nicksnettravels.builttoroam.com">Nick&#039;s .NET Travels</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://nicksnettravels.builttoroam.com/ai-app-builders-take-1/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Logging with Azure Application Insights in a Windows Application</title>
		<link>https://nicksnettravels.builttoroam.com/logging-with-azure-application-insights-in-a-windows-application/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=logging-with-azure-application-insights-in-a-windows-application</link>
					<comments>https://nicksnettravels.builttoroam.com/logging-with-azure-application-insights-in-a-windows-application/#respond</comments>
		
		<dc:creator><![CDATA[Nick]]></dc:creator>
		<pubDate>Sat, 08 Feb 2025 12:45:44 +0000</pubDate>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[ApplicationInsights]]></category>
		<category><![CDATA[Azure]]></category>
		<category><![CDATA[Uno]]></category>
		<category><![CDATA[Uno Platform]]></category>
		<category><![CDATA[Windows]]></category>
		<guid isPermaLink="false">https://nicksnettravels.builttoroam.com/?p=3326</guid>

					<description><![CDATA[<p>The default template for a Windows application comes with almost no guidance for how developers should do even basic things like logging. Luckily, the Uno Platform wizard provides a simple way to create an application that configures the Microsoft.Extensions for each of the supported platforms. This includes the ability to setup Microsoft.Extensions.Logging with the ability ... <a title="Logging with Azure Application Insights in a Windows Application" class="read-more" href="https://nicksnettravels.builttoroam.com/logging-with-azure-application-insights-in-a-windows-application/" aria-label="Read more about Logging with Azure Application Insights in a Windows Application">Read more</a></p>
<p>The post <a href="https://nicksnettravels.builttoroam.com/logging-with-azure-application-insights-in-a-windows-application/">Logging with Azure Application Insights in a Windows Application</a> appeared first on <a href="https://nicksnettravels.builttoroam.com">Nick&#039;s .NET Travels</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>The default template for a Windows application comes with almost no guidance for how developers should do even basic things like logging. Luckily, the <a href="https://platform.uno/">Uno Platform</a> wizard provides a simple way to create an application that configures the Microsoft.Extensions for each of the supported platforms. This includes the ability to setup Microsoft.Extensions.Logging with the ability to set minimum logging level and add filters for classes and namespaces. In this post we&#8217;re going to configure logging to write to Azure Application Insights.</p>



<p>Let&#8217;s create a new application using the Uno Platform Template Wizard &#8211; by default this will create a cross platform application that includes all the supported Uno Platform targets but if you only want to target Windows (or a different subset of the platforms) you can adjust this from the Platforms tab.</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image.png"><img loading="lazy" decoding="async" width="300" height="170" src="https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-300x170.png" alt="" class="wp-image-3327" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-300x170.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-1024x581.png 1024w, https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-768x436.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-1536x871.png 1536w, https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image.png 1601w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>We&#8217;re going to go with the Recommended preset, which includes support for Microsoft.Extensions. In the Logging section, we&#8217;ll stick with Default for now, but it&#8217;s useful to know that you can select the Serilog option if you want to write log information to files.</p>



<p>Ok, next up we need to add a reference to the <a href="https://www.nuget.org/packages/Microsoft.Extensions.Logging.ApplicationInsights">Microsoft.Extensions.Logging.ApplicationInsights</a> nuget package.</p>



<figure class="wp-block-image size-medium"><img loading="lazy" decoding="async" width="300" height="157" src="https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67a74bc343eb6-300x157.png" alt="" class="wp-image-3328" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67a74bc343eb6-300x157.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67a74bc343eb6-1024x535.png 1024w, https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67a74bc343eb6-768x401.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67a74bc343eb6-1536x803.png 1536w, https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67a74bc343eb6.png 1634w" sizes="auto, (max-width: 300px) 100vw, 300px" /></figure>



<p>If you don&#8217;t already have an Azure Application Insights resource, take the opportunity to create one now via the <a href="https://portal.azure.com">Azure Portal</a>. Once you&#8217;ve created the Application Insights resource, copy the Connection String value for use in the next step.</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67a74cc8dd817.png"><img loading="lazy" decoding="async" width="300" height="208" src="https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67a74cc8dd817-300x208.png" alt="" class="wp-image-3330" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67a74cc8dd817-300x208.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67a74cc8dd817-1024x711.png 1024w, https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67a74cc8dd817-768x533.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67a74cc8dd817.png 1241w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>In Solution Explorer, locate the appsettings.json file (or if you only want to set different values for development than for production, locate the appsettings.development.json file) and add a new section, TelemetryConfiguration, with a single node, ConnectionString, which contains the Connection String copied from the Azure portal.</p>



<pre class="hljs" style="display: block; overflow-x: auto; padding: 0.5em; background: rgb(255, 255, 255); color: rgb(0, 0, 0);">{
  ... ,
  <span class="hljs-attr" style="color: red;">"TelemetryConfiguration"</span>: {
    <span class="hljs-attr" style="color: red;">"ConnectionString"</span>: <span class="hljs-string" style="color: rgb(163, 21, 21);">"InstrumentationKey=XXXXXXXX"</span>
  }
}
</pre>



<p>Next we need to call <code>logBuilder.AddApplicationInsights()</code>, as part of configuring the application Host. This will setup logging to output to Application Insights.</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67a74e3f97973.png"><img loading="lazy" decoding="async" width="300" height="143" src="https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67a74e3f97973-300x143.png" alt="" class="wp-image-3331" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67a74e3f97973-300x143.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67a74e3f97973-1024x489.png 1024w, https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67a74e3f97973-768x367.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67a74e3f97973.png 1129w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>We&#8217;ll also configure an instance of the TelemetryClient as a service that can be used to track events.</p>



<p><code>services.AddSingleton(sp => new TelemetryClient(sp.GetRequiredService>().Value));</code></p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67a74e883aab1.png"><img loading="lazy" decoding="async" width="300" height="37" src="https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67a74e883aab1-300x37.png" alt="" class="wp-image-3332" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67a74e883aab1-300x37.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67a74e883aab1-1024x126.png 1024w, https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67a74e883aab1-768x94.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67a74e883aab1.png 1475w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>And that&#8217;s all we need to do to install and configure support for Azure Application Insights in our application.</p>



<p>We can make use of this in two ways. Firstly, when the application calls any of the log methods on ILogger, a trace is added to Application Insights. Alternatively, the application can access the TelemetryClient and use it to track events.</p>



<pre class="hljs" style="display: block; overflow-x: auto; padding: 0.5em; background: rgb(255, 255, 255); color: rgb(0, 0, 0);"><span class="hljs-keyword" style="color: rgb(0, 0, 255);">var</span> logger = Host.Services.GetRequiredService&lt;ILogger&lt;App&gt;&gt;();
logger.LogError(<span class="hljs-string" style="color: rgb(163, 21, 21);">"Nicks Error - AppInsights!"</span>);

<span class="hljs-keyword" style="color: rgb(0, 0, 255);">var</span> telemetryClient = Host.Services.GetRequiredService&lt;TelemetryClient&gt;();
telemetryClient.TrackEvent(<span class="hljs-string" style="color: rgb(163, 21, 21);">"Test event"</span>);</pre>



<p>Here I make the distinction between a trace and an event because Application Insights sees these as different things. If you click on the Events node under Usage, you can see information about entries made by calling TrackEvent.</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67a750f3b0868.png"><img loading="lazy" decoding="async" width="300" height="257" src="https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67a750f3b0868-300x257.png" alt="" class="wp-image-3333" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67a750f3b0868-300x257.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67a750f3b0868-1024x876.png 1024w, https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67a750f3b0868-768x657.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67a750f3b0868.png 1463w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>Alternatively, if you click on the Logs node under Monitoring, you can invoke a query to see all the traces. This includes entries made using logging in the application &#8211; be aware that any filtering specified in the logBuilder configuration is done in the application before entries are sent to Application Insights.</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67a7513e5a0e4.png"><img loading="lazy" decoding="async" width="300" height="256" src="https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67a7513e5a0e4-300x256.png" alt="" class="wp-image-3334" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67a7513e5a0e4-300x256.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67a7513e5a0e4-1024x874.png 1024w, https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67a7513e5a0e4-768x655.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2025/02/image-67a7513e5a0e4.png 1467w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>Ok, there you have it, a quick summary of how you can extend logging in your Windows and cross platform application using Azure Application Insights.</p>
<p>The post <a href="https://nicksnettravels.builttoroam.com/logging-with-azure-application-insights-in-a-windows-application/">Logging with Azure Application Insights in a Windows Application</a> appeared first on <a href="https://nicksnettravels.builttoroam.com">Nick&#039;s .NET Travels</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://nicksnettravels.builttoroam.com/logging-with-azure-application-insights-in-a-windows-application/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Taking AI Dev Gallery Code Cross Platform with Uno Platform – iOS</title>
		<link>https://nicksnettravels.builttoroam.com/ai-dev-gallery-uno-platform-ios/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=ai-dev-gallery-uno-platform-ios</link>
					<comments>https://nicksnettravels.builttoroam.com/ai-dev-gallery-uno-platform-ios/#comments</comments>
		
		<dc:creator><![CDATA[Nick]]></dc:creator>
		<pubDate>Sun, 05 Jan 2025 18:17:29 +0000</pubDate>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[AI]]></category>
		<category><![CDATA[iOS]]></category>
		<category><![CDATA[Uno Platform]]></category>
		<category><![CDATA[Windows]]></category>
		<guid isPermaLink="false">https://nicksnettravels.builttoroam.com/?p=3318</guid>

					<description><![CDATA[<p>Following my previous posts that introduced the AI Dev Gallery, added AI code to an Uno Platform application and adjusting the AI code to work with Android, in this post we&#8217;re going to look at the adjustments required to get the AI code to work on iOS. The issues with iOS aren&#8217;t apparent until you ... <a title="Taking AI Dev Gallery Code Cross Platform with Uno Platform &#8211; iOS" class="read-more" href="https://nicksnettravels.builttoroam.com/ai-dev-gallery-uno-platform-ios/" aria-label="Read more about Taking AI Dev Gallery Code Cross Platform with Uno Platform &#8211; iOS">Read more</a></p>
<p>The post <a href="https://nicksnettravels.builttoroam.com/ai-dev-gallery-uno-platform-ios/">Taking AI Dev Gallery Code Cross Platform with Uno Platform &#8211; iOS</a> appeared first on <a href="https://nicksnettravels.builttoroam.com">Nick&#039;s .NET Travels</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>Following my previous posts that <a href="https://nicksnettravels.builttoroam.com/ai-dev-gallery/">introduced the AI Dev Gallery</a>, <a href="https://nicksnettravels.builttoroam.com/ai-dev-gallery-meets-uno-platform/">added AI code to an Uno Platform application</a> and adjusting the <a href="https://nicksnettravels.builttoroam.com/ai-dev-gallery-uno-platform-android/">AI code to work with Android</a>, in this post we&#8217;re going to look at the adjustments required to get the AI code to work on iOS. The issues with iOS aren&#8217;t apparent until you go to run the application, in my case on the iOS simulator (from Windows). The application builds successfully if you right-click the project and select Build or Rebuild. However, when you click Run, the build will fail with the following error:</p>



<pre class="wp-block-preformatted">1&gt;Tool xcrun execution finished (exit code = 1).<br>1&gt;C:\Program Files\dotnet\packs\Microsoft.iOS.Sdk.net8.0_18.0\18.0.8314\targets\Xamarin.Shared.Sdk.targets(1648,3): error : clang++ exited with code 1:<br>1&gt;C:\Program Files\dotnet\packs\Microsoft.iOS.Sdk.net8.0_18.0\18.0.8314\targets\Xamarin.Shared.Sdk.targets(1648,3): error : ld: library 'f:/packages/microsoft.ml.onnxruntime.extensions/0.13.0/buildTransitive/net6.0-ios15.4/../../runtimes/ios/native/onnxruntime_extensions.xcframework.zip' not found<br>1&gt;C:\Program Files\dotnet\packs\Microsoft.iOS.Sdk.net8.0_18.0\18.0.8314\targets\Xamarin.Shared.Sdk.targets(1648,3): error : clang++: error: linker command failed with exit code 1 (use -v to see invocation)</pre>



<p>This appears to be a <a href="https://github.com/microsoft/onnxruntime/issues/22661">known issue </a>tracked on the onnx runtime github repository in relation to building an .NET MAUI application. In the issue there is a workaround that suggests manually extracting the zip file that contains the native reference. However, if you do this, you&#8217;ll need to manually do it on each computer you want to run the application on. </p>



<p>Let&#8217;s walk through how we can apply the <a href="https://github.com/microsoft/onnxruntime/issues/22661#issuecomment-2458325812">workaround</a> suggest in the issue in a way that will work on any computer that wants to run the application, without having to apply a bunch of manual steps. The first thing to do is to extract the two native references from the NuGet packages Microsoft.ML.OnnxRuntime and Microsoft.ML.OnnxRuntime.Extensions: </p>



<ul class="wp-block-list">
<li>packages\microsoft.ml.onnxruntime.extensions\0.13.0\runtimes\ios\native\onnxruntime_extensions.xcframework.zip</li>



<li>packages\microsoft.ml.onnxruntime\1.20.1\runtimes\ios\native\onnxruntime.xcframework.zip  </li>
</ul>



<p>Each of these zip files was extracted into a Library folder at the solution level, resulting in the following folder structure.</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2025/01/image-677ab8e18fdf3.png"><img loading="lazy" decoding="async" width="258" height="300" src="https://wordpressblogimages.builttoroam.com/blogimages/2025/01/image-677ab8e18fdf3-258x300.png" alt="" class="wp-image-3322" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2025/01/image-677ab8e18fdf3-258x300.png 258w, https://wordpressblogimages.builttoroam.com/blogimages/2025/01/image-677ab8e18fdf3.png 657w" sizes="auto, (max-width: 258px) 100vw, 258px" /></a></figure>



<p>Each of the NuGet packages, Microsoft.ML.OnnxRuntime and Microsoft.ML.OnnxRuntime.Extensions, includes a targets file that contains a single NativeReference  item, for example.</p>



<pre class="hljs" style="display: block; overflow-x: auto; padding: 0.5em; background: rgb(255, 255, 255); color: rgb(0, 0, 0);"><span class="php"><span class="hljs-meta" style="color: rgb(43, 145, 175);">&lt;?</span>xml version=<span class="hljs-string" style="color: rgb(163, 21, 21);">"1.0"</span> encoding=<span class="hljs-string" style="color: rgb(163, 21, 21);">"utf-8"</span><span class="hljs-meta" style="color: rgb(43, 145, 175);">?&gt;</span></span>
<span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">Project</span> <span class="hljs-attr" style="color: red;">ToolsVersion</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"4.0"</span> <span class="hljs-attr" style="color: red;">xmlns</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"http://schemas.microsoft.com/developer/msbuild/2003"</span>&gt;</span>
  <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">ItemGroup</span> <span class="hljs-attr" style="color: red;">Condition</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"('$(OutputType)'!='Library' OR '$(IsAppExtension)'=='True')"</span>&gt;</span>
    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">NativeReference</span> <span class="hljs-attr" style="color: red;">Include</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"$(MSBuildThisFileDirectory)..\..\runtimes\ios\native\onnxruntime.xcframework.zip"</span>&gt;</span>
      <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">Kind</span>&gt;</span>Static<span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">Kind</span>&gt;</span>
      <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">IsCxx</span>&gt;</span>True<span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">IsCxx</span>&gt;</span>
      <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">SmartLink</span>&gt;</span>True<span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">SmartLink</span>&gt;</span>
      <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">ForceLoad</span>&gt;</span>True<span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">ForceLoad</span>&gt;</span>
      <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">LinkerFlags</span>&gt;</span>-lc++<span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">LinkerFlags</span>&gt;</span>
      <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">WeakFrameworks</span>&gt;</span>CoreML<span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">WeakFrameworks</span>&gt;</span>
    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">NativeReference</span>&gt;</span>
  <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">ItemGroup</span>&gt;</span>
<span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">Project</span>&gt;</span>
</pre>



<p>Unfortunately, it appears that the MSBuild task that is responsible for extracting the zip file and resolving the native reference, doesn&#8217;t appear to be working correctly. Since we&#8217;ve manually extracted the zip files into a location where they can be checked in, alongside the application, we just need to update the NativeReference by changing the Directory.Build.targets to the following:</p>



<pre class="hljs" style="display: block; overflow-x: auto; padding: 0.5em; background: rgb(255, 255, 255); color: rgb(0, 0, 0);"><span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">Project</span>&gt;</span>
    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">ItemGroup</span> <span class="hljs-attr" style="color: red;">Condition</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"(('$(OutputType)'!='Library' OR '$(IsAppExtension)'=='True') AND '$(TargetFramework)'=='net8.0-ios')"</span>&gt;</span>
        <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">NativeReference</span> <span class="hljs-attr" style="color: red;">Remove</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"@(NativeReference)"</span> /&gt;</span>

        <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">NativeReference</span> <span class="hljs-attr" style="color: red;">Include</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"$(MSBuildThisFileDirectory)..\Library\onnxruntime.xcframework"</span>&gt;</span>
            <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">Kind</span>&gt;</span>Static<span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">Kind</span>&gt;</span>
            <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">IsCxx</span>&gt;</span>True<span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">IsCxx</span>&gt;</span>
            <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">SmartLink</span>&gt;</span>True<span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">SmartLink</span>&gt;</span>
            <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">ForceLoad</span>&gt;</span>True<span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">ForceLoad</span>&gt;</span>
            <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">LinkerFlags</span>&gt;</span>-lc++<span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">LinkerFlags</span>&gt;</span>
            <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">WeakFrameworks</span>&gt;</span>CoreML<span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">WeakFrameworks</span>&gt;</span>
        <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">NativeReference</span>&gt;</span>
        <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">NativeReference</span> <span class="hljs-attr" style="color: red;">Include</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"$(MSBuildThisFileDirectory)..\Library\onnxruntime_extensions.xcframework"</span>&gt;</span>
            <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">Kind</span>&gt;</span>Static<span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">Kind</span>&gt;</span>
            <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">IsCxx</span>&gt;</span>True<span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">IsCxx</span>&gt;</span>
            <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">SmartLink</span>&gt;</span>True<span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">SmartLink</span>&gt;</span>
            <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">ForceLoad</span>&gt;</span>True<span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">ForceLoad</span>&gt;</span>
            <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">LinkerFlags</span>&gt;</span>-lc++<span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">LinkerFlags</span>&gt;</span>
            <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">WeakFrameworks</span>&gt;</span>CoreML<span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">WeakFrameworks</span>&gt;</span>
        <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">NativeReference</span>&gt;</span>
    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">ItemGroup</span>&gt;</span>
<span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">Project</span>&gt;</span>
</pre>



<p>With this change, the ObjectDetection application will now run on iOS. Here&#8217;s it running in on the iOS simulator via the Remote Simulator.</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2025/01/image-677acc72138cd.png"><img loading="lazy" decoding="async" width="161" height="300" src="https://wordpressblogimages.builttoroam.com/blogimages/2025/01/image-677acc72138cd-161x300.png" alt="" class="wp-image-3323" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2025/01/image-677acc72138cd-161x300.png 161w, https://wordpressblogimages.builttoroam.com/blogimages/2025/01/image-677acc72138cd-549x1024.png 549w, https://wordpressblogimages.builttoroam.com/blogimages/2025/01/image-677acc72138cd.png 653w" sizes="auto, (max-width: 161px) 100vw, 161px" /></a></figure>



<p></p>
<p>The post <a href="https://nicksnettravels.builttoroam.com/ai-dev-gallery-uno-platform-ios/">Taking AI Dev Gallery Code Cross Platform with Uno Platform &#8211; iOS</a> appeared first on <a href="https://nicksnettravels.builttoroam.com">Nick&#039;s .NET Travels</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://nicksnettravels.builttoroam.com/ai-dev-gallery-uno-platform-ios/feed/</wfw:commentRss>
			<slash:comments>2</slash:comments>
		
		
			</item>
		<item>
		<title>Taking AI Dev Gallery Code Cross Platform with Uno Platform – Android</title>
		<link>https://nicksnettravels.builttoroam.com/ai-dev-gallery-uno-platform-android/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=ai-dev-gallery-uno-platform-android</link>
					<comments>https://nicksnettravels.builttoroam.com/ai-dev-gallery-uno-platform-android/#comments</comments>
		
		<dc:creator><![CDATA[Nick]]></dc:creator>
		<pubDate>Wed, 01 Jan 2025 16:27:02 +0000</pubDate>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[AI]]></category>
		<category><![CDATA[Android]]></category>
		<category><![CDATA[Uno Platform]]></category>
		<category><![CDATA[Windows]]></category>
		<guid isPermaLink="false">https://nicksnettravels.builttoroam.com/?p=3312</guid>

					<description><![CDATA[<p>In the last two posts I introduced the AI Dev Gallery that Microsoft has been working on, and then demonstrated how code exported from the AI Dev Gallery can be added to an Uno Platform application. Unfortunately, whilst the code compiles on all the target platforms of the Uno Platform, the application fails to operate ... <a title="Taking AI Dev Gallery Code Cross Platform with Uno Platform &#8211; Android" class="read-more" href="https://nicksnettravels.builttoroam.com/ai-dev-gallery-uno-platform-android/" aria-label="Read more about Taking AI Dev Gallery Code Cross Platform with Uno Platform &#8211; Android">Read more</a></p>
<p>The post <a href="https://nicksnettravels.builttoroam.com/ai-dev-gallery-uno-platform-android/">Taking AI Dev Gallery Code Cross Platform with Uno Platform &#8211; Android</a> appeared first on <a href="https://nicksnettravels.builttoroam.com">Nick&#039;s .NET Travels</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>In the last two posts I <a href="https://nicksnettravels.builttoroam.com/ai-dev-gallery/">introduced the AI Dev Gallery</a> that Microsoft has been working on, and then demonstrated how code exported from the AI Dev Gallery can be <a href="https://nicksnettravels.builttoroam.com/ai-dev-gallery-meets-uno-platform/">added to an Uno Platform application</a>. Unfortunately, whilst the code compiles on all the target platforms of the <a href="https://platform.uno/dotnettravels-uno">Uno Platform</a>, the application fails to operate correctly on non-Windows platforms. In this post we&#8217;ll look at the reason why the application fails and how we can fix it.</p>



<p>Let&#8217;s start by trying to run the application on Android. The first issue we see is that the path to the Faster RCNN 10 model isn&#8217;t being resolved correctly; we can&#8217;t just assume a path relative to the InstalledLocation of the application. The OnNavigatedTo and InitModel methods can be updated as follows:</p>



<pre class="hljs" style="display: block; overflow-x: auto; padding: 0.5em; background: rgb(255, 255, 255); color: rgb(0, 0, 0);"><span class="hljs-function"><span class="hljs-keyword" style="color: rgb(0, 0, 255);">protected</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">override</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">async</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">void</span> <span class="hljs-title" style="color: rgb(163, 21, 21);">OnNavigatedTo</span>(<span class="hljs-params">Microsoft.UI.Xaml.Navigation.NavigationEventArgs e</span>)
</span>{
    <span class="hljs-comment" style="color: green;">//await InitModel(System.IO.Path.Join(Windows.ApplicationModel.Package.Current.InstalledLocation.Path, "Models", @"FasterRCNN-10.onnx"));</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 255);">await</span> InitModel(<span class="hljs-string" style="color: rgb(163, 21, 21);">"Models/FasterRCNN-10.onnx"</span>);
}

<span class="hljs-function"><span class="hljs-keyword" style="color: rgb(0, 0, 255);">private</span> Task <span class="hljs-title" style="color: rgb(163, 21, 21);">InitModel</span>(<span class="hljs-params"><span class="hljs-keyword" style="color: rgb(0, 0, 255);">string</span> modelPath</span>)
</span>{
    <span class="hljs-keyword" style="color: rgb(0, 0, 255);">return</span> Task.Run(<span class="hljs-keyword" style="color: rgb(0, 0, 255);">async</span> () =&gt;
    {
        <span class="hljs-keyword" style="color: rgb(0, 0, 255);">if</span> (_inferenceSession != <span class="hljs-literal" style="color: rgb(163, 21, 21);">null</span>)
        {
            <span class="hljs-keyword" style="color: rgb(0, 0, 255);">return</span>;
        }

        <span class="hljs-keyword" style="color: rgb(0, 0, 255);">var</span> file = <span class="hljs-keyword" style="color: rgb(0, 0, 255);">await</span> Windows.Storage.StorageFile.GetFileFromApplicationUriAsync(<span class="hljs-keyword" style="color: rgb(0, 0, 255);">new</span> Uri(<span class="hljs-string" style="color: rgb(163, 21, 21);">$"ms-appx:///<span class="hljs-subst">{modelPath}</span>"</span>));

        SessionOptions sessionOptions = <span class="hljs-keyword" style="color: rgb(0, 0, 255);">new</span>();
        sessionOptions.RegisterOrtExtensions();

        _inferenceSession = <span class="hljs-keyword" style="color: rgb(0, 0, 255);">new</span> InferenceSession(file.Path, sessionOptions);
    });
}</pre>



<p>Now that we have the correct path to the model being passed into the InferenceSession constructor, we see a different issue emerge. A TypeInitializationException is raised when trying to initialize the NativeMethods type. </p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="553" height="333" src="https://wordpressblogimages.builttoroam.com/blogimages/2025/01/image.png" alt="" class="wp-image-3313" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2025/01/image.png 553w, https://wordpressblogimages.builttoroam.com/blogimages/2025/01/image-300x181.png 300w" sizes="auto, (max-width: 553px) 100vw, 553px" /></figure>



<p>I realised that this was related to the current set of PackageReferences which includes Microsoft.ML.OnnxRuntime.DirectML. This package is an optimization of the OnnxRuntime that leverages DirectX 12, which would explain why it&#8217;s not compatible with Android (and other non-DirectX platforms). Let&#8217;s update the package references.</p>



<pre class="hljs" style="display: block; overflow-x: auto; padding: 0.5em; background: rgb(255, 255, 255); color: rgb(0, 0, 0);"><span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">ItemGroup</span>&gt;</span>
    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">PackageReference</span> <span class="hljs-attr" style="color: red;">Include</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Microsoft.ML.OnnxRuntime"</span> <span class="hljs-attr" style="color: red;">Condition</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"'$(TargetFramework)' != 'net8.0-windows10.0.26100'"</span> /&gt;</span>
    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">PackageReference</span> <span class="hljs-attr" style="color: red;">Include</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Microsoft.ML.OnnxRuntime.DirectML"</span> <span class="hljs-attr" style="color: red;">Condition</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"'$(TargetFramework)' == 'net8.0-windows10.0.26100'"</span> /&gt;</span>
    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">PackageReference</span> <span class="hljs-attr" style="color: red;">Include</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Microsoft.ML.OnnxRuntime.Extensions"</span> /&gt;</span>
    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">PackageReference</span> <span class="hljs-attr" style="color: red;">Include</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"System.Drawing.Common"</span> /&gt;</span>
<span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">ItemGroup</span>&gt;</span>
</pre>



<p>The Microsoft.ML.OnnxRuntime PackageReference will include a managed implementation of the OnnxRuntime. We&#8217;re conditionally including the DirectML implementation for Windows and the Microsoft.ML.OnnxRuntime package when not on Windows.</p>



<p>With these changes, the application starts up correctly. However, when we go to select an image, we experience further issues with any code that uses the System.Drawing.Common package. </p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="382" src="https://wordpressblogimages.builttoroam.com/blogimages/2025/01/image-67743e21afcaf-1024x382.png" alt="" class="wp-image-3314" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2025/01/image-67743e21afcaf-1024x382.png 1024w, https://wordpressblogimages.builttoroam.com/blogimages/2025/01/image-67743e21afcaf-300x112.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2025/01/image-67743e21afcaf-768x287.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2025/01/image-67743e21afcaf.png 1350w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p>I&#8217;m going to rant a little here because it&#8217;s annoying that Microsoft publishes a netstandard2.0 library that is only designed to work on Windows. This library should only include Windows tfms. Alternatively, if the intent is to allow the library to compile for all targets, the methods should be marked as NotImplemented for all targets except Windows.</p>



<p>Ok, so that ends my rant but the question remains, how do we replace System.Drawing.Common. A while ago I posted on using <a href="https://nicksnettravels.builttoroam.com/imagesharp-windows-uno-platform/">ImageSharp with the Uno Platform</a>, so it makes sense to use this library. Let&#8217;s update the PackageReferences:</p>



<pre class="hljs" style="display: block; overflow-x: auto; padding: 0.5em; background: rgb(255, 255, 255); color: rgb(0, 0, 0);"><span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">ItemGroup</span>&gt;</span>
    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">PackageReference</span> <span class="hljs-attr" style="color: red;">Include</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Microsoft.ML.OnnxRuntime"</span> <span class="hljs-attr" style="color: red;">Condition</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"'$(TargetFramework)' != 'net8.0-windows10.0.26100'"</span> /&gt;</span>
    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">PackageReference</span> <span class="hljs-attr" style="color: red;">Include</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Microsoft.ML.OnnxRuntime.DirectML"</span> <span class="hljs-attr" style="color: red;">Condition</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"'$(TargetFramework)' == 'net8.0-windows10.0.26100'"</span> /&gt;</span>
    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">PackageReference</span> <span class="hljs-attr" style="color: red;">Include</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Microsoft.ML.OnnxRuntime.Extensions"</span> /&gt;</span>
    <span class="hljs-comment" style="color: green;">&lt;!--&lt;PackageReference Include="System.Drawing.Common" /&gt;--&gt;</span>
    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">PackageReference</span> <span class="hljs-attr" style="color: red;">Include</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"SixLabors.ImageSharp"</span> /&gt;</span>
    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">PackageReference</span> <span class="hljs-attr" style="color: red;">Include</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"SixLabors.ImageSharp.Drawing"</span> /&gt;</span>
<span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">ItemGroup</span>&gt;</span>
</pre>



<p>And now we need to replace the methods in BitmapFunctions.cs, which use methods in System.Drawing.Common, with equivalent methods that use ImageSharp. Not all methods in BitmapFunctions.cs are used by this application, so I&#8217;ve only migrated the two methods required into a static class, ImageFunctions.</p>



<pre class="hljs" style="display: block; overflow-x: auto; padding: 0.5em; background: rgb(255, 255, 255); color: rgb(0, 0, 0);"><span class="hljs-keyword" style="color: rgb(0, 0, 255);">using</span> Microsoft.ML.OnnxRuntime.Tensors;
<span class="hljs-keyword" style="color: rgb(0, 0, 255);">using</span> Microsoft.UI.Xaml.Media.Imaging;
<span class="hljs-keyword" style="color: rgb(0, 0, 255);">using</span> SixLabors.Fonts;
<span class="hljs-keyword" style="color: rgb(0, 0, 255);">using</span> SixLabors.ImageSharp;
<span class="hljs-keyword" style="color: rgb(0, 0, 255);">using</span> SixLabors.ImageSharp.Drawing.Processing;
<span class="hljs-keyword" style="color: rgb(0, 0, 255);">using</span> SixLabors.ImageSharp.PixelFormats;
<span class="hljs-keyword" style="color: rgb(0, 0, 255);">using</span> SixLabors.ImageSharp.Processing;

<span class="hljs-keyword" style="color: rgb(0, 0, 255);">namespace</span> <span class="hljs-title" style="color: rgb(163, 21, 21);">ObjectDetection</span>;

<span class="hljs-keyword" style="color: rgb(0, 0, 255);">internal</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">static</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">class</span> <span class="hljs-title" style="color: rgb(163, 21, 21);">ImageFunctions</span>
{
    <span class="hljs-keyword" style="color: rgb(0, 0, 255);">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">static</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">readonly</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">float</span>[] Mean = [<span class="hljs-number">0.485</span>f, <span class="hljs-number">0.456</span>f, <span class="hljs-number">0.406</span>f];
    <span class="hljs-keyword" style="color: rgb(0, 0, 255);">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">static</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">readonly</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">float</span>[] StdDev = [<span class="hljs-number">0.229</span>f, <span class="hljs-number">0.224</span>f, <span class="hljs-number">0.225</span>f];

    <span class="hljs-keyword" style="color: rgb(0, 0, 255);">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">static</span> Uri FontUri = <span class="hljs-keyword" style="color: rgb(0, 0, 255);">new</span> Uri(<span class="hljs-string" style="color: rgb(163, 21, 21);">"ms-appx:///Uno.Fonts.OpenSans/Fonts/OpenSans.ttf"</span>);

    <span class="hljs-function"><span class="hljs-keyword" style="color: rgb(0, 0, 255);">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">static</span> DenseTensor&lt;<span class="hljs-keyword" style="color: rgb(0, 0, 255);">float</span>&gt; <span class="hljs-title" style="color: rgb(163, 21, 21);">PreprocessBitmapForObjectDetection</span>(<span class="hljs-params">Image&lt;Rgb24&gt; bitmap, <span class="hljs-keyword" style="color: rgb(0, 0, 255);">int</span> paddedHeight, <span class="hljs-keyword" style="color: rgb(0, 0, 255);">int</span> paddedWidth</span>)
    </span>{
        <span class="hljs-keyword" style="color: rgb(0, 0, 255);">int</span> width = bitmap.Width;
        <span class="hljs-keyword" style="color: rgb(0, 0, 255);">int</span> height = bitmap.Height;
        DenseTensor&lt;<span class="hljs-keyword" style="color: rgb(0, 0, 255);">float</span>&gt; input = <span class="hljs-keyword" style="color: rgb(0, 0, 255);">new</span>([<span class="hljs-number">3</span>, paddedHeight, paddedWidth]);

        bitmap.ProcessPixelRows(pixelAccessor =&gt;
        {
            <span class="hljs-keyword" style="color: rgb(0, 0, 255);">for</span> (<span class="hljs-keyword" style="color: rgb(0, 0, 255);">int</span> y = <span class="hljs-number">0</span>; y &lt; pixelAccessor.Height; y++)
            {
                Span&lt;Rgb24&gt; row = pixelAccessor.GetRowSpan(y);

                <span class="hljs-comment" style="color: green;">// Using row.Length helps JIT to eliminate bounds checks when accessing row[x].</span>
                <span class="hljs-keyword" style="color: rgb(0, 0, 255);">for</span> (<span class="hljs-keyword" style="color: rgb(0, 0, 255);">int</span> x = <span class="hljs-number">0</span>; x &lt; row.Length; x++)
                {
                    input[<span class="hljs-number">0</span>, y, x] = row[x].B - Mean[<span class="hljs-number">0</span>];
                    input[<span class="hljs-number">1</span>, y, x] = row[x].G - Mean[<span class="hljs-number">1</span>];
                    input[<span class="hljs-number">2</span>, y, x] = row[x].R - Mean[<span class="hljs-number">2</span>];
                }
            }
        });

        <span class="hljs-keyword" style="color: rgb(0, 0, 255);">return</span> input;
    }


    <span class="hljs-function"><span class="hljs-keyword" style="color: rgb(0, 0, 255);">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">static</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">async</span> Task&lt;BitmapImage&gt; <span class="hljs-title" style="color: rgb(163, 21, 21);">RenderPredictions</span>(<span class="hljs-params">Image&lt;Rgb24&gt; image, List&lt;Prediction&gt; predictions</span>)
    </span>{
        FontCollection collection = <span class="hljs-keyword" style="color: rgb(0, 0, 255);">new</span>();

<span class="hljs-meta" style="color: rgb(43, 145, 175);">#<span class="hljs-meta-keyword">if</span> WINDOWS</span>
        collection.AddSystemFonts();
        collection.TryGet(<span class="hljs-string" style="color: rgb(163, 21, 21);">"Arial"</span>, <span class="hljs-keyword" style="color: rgb(0, 0, 255);">out</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">var</span> family);
<span class="hljs-meta" style="color: rgb(43, 145, 175);">#<span class="hljs-meta-keyword">else</span></span>
        <span class="hljs-keyword" style="color: rgb(0, 0, 255);">var</span> fontFile = <span class="hljs-keyword" style="color: rgb(0, 0, 255);">await</span> Windows.Storage.StorageFile.GetFileFromApplicationUriAsync(FontUri);
        collection.Add(fontFile.Path);
        collection.TryGet(<span class="hljs-string" style="color: rgb(163, 21, 21);">"Open Sans"</span>, <span class="hljs-keyword" style="color: rgb(0, 0, 255);">out</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">var</span> family);
<span class="hljs-meta" style="color: rgb(43, 145, 175);">#<span class="hljs-meta-keyword">endif</span></span>

        image.Mutate(g =&gt;
        {
            <span class="hljs-comment" style="color: green;">// Draw prediciton</span>
            <span class="hljs-keyword" style="color: rgb(0, 0, 255);">int</span> markerSize = (<span class="hljs-keyword" style="color: rgb(0, 0, 255);">int</span>)((image.Width + image.Height) * <span class="hljs-number">0.04</span> / <span class="hljs-number">2</span>);
            <span class="hljs-keyword" style="color: rgb(0, 0, 255);">int</span> fontSize = (<span class="hljs-keyword" style="color: rgb(0, 0, 255);">int</span>)((image.Width + image.Height) * <span class="hljs-number">.04</span> / <span class="hljs-number">2</span>);
            fontSize = Math.Max(fontSize, <span class="hljs-number">1</span>);

            Pen pen = <span class="hljs-keyword" style="color: rgb(0, 0, 255);">new</span> SolidPen(Color.Red, markerSize / <span class="hljs-number">10</span>);

            <span class="hljs-keyword" style="color: rgb(0, 0, 255);">var</span> brush = <span class="hljs-keyword" style="color: rgb(0, 0, 255);">new</span> SolidBrush(Color.White);



            Font font = family.CreateFont(fontSize);


            <span class="hljs-keyword" style="color: rgb(0, 0, 255);">foreach</span> (<span class="hljs-keyword" style="color: rgb(0, 0, 255);">var</span> p <span class="hljs-keyword" style="color: rgb(0, 0, 255);">in</span> predictions)
            {
                <span class="hljs-keyword" style="color: rgb(0, 0, 255);">if</span> (p == <span class="hljs-literal" style="color: rgb(163, 21, 21);">null</span> || p.Box == <span class="hljs-literal" style="color: rgb(163, 21, 21);">null</span>)
                {
                    <span class="hljs-keyword" style="color: rgb(0, 0, 255);">continue</span>;
                }

                <span class="hljs-comment" style="color: green;">// Draw the box</span>
                g.DrawLine(pen, <span class="hljs-keyword" style="color: rgb(0, 0, 255);">new</span> PointF(p.Box.Xmin, p.Box.Ymin), <span class="hljs-keyword" style="color: rgb(0, 0, 255);">new</span> PointF(p.Box.Xmax, p.Box.Ymin));
                g.DrawLine(pen, <span class="hljs-keyword" style="color: rgb(0, 0, 255);">new</span> PointF(p.Box.Xmax, p.Box.Ymin), <span class="hljs-keyword" style="color: rgb(0, 0, 255);">new</span> PointF(p.Box.Xmax, p.Box.Ymax));
                g.DrawLine(pen, <span class="hljs-keyword" style="color: rgb(0, 0, 255);">new</span> PointF(p.Box.Xmax, p.Box.Ymax), <span class="hljs-keyword" style="color: rgb(0, 0, 255);">new</span> PointF(p.Box.Xmin, p.Box.Ymax));
                g.DrawLine(pen, <span class="hljs-keyword" style="color: rgb(0, 0, 255);">new</span> PointF(p.Box.Xmin, p.Box.Ymax), <span class="hljs-keyword" style="color: rgb(0, 0, 255);">new</span> PointF(p.Box.Xmin, p.Box.Ymin));

                <span class="hljs-comment" style="color: green;">// Draw the label and confidence</span>
                <span class="hljs-keyword" style="color: rgb(0, 0, 255);">string</span> labelText = <span class="hljs-string" style="color: rgb(163, 21, 21);">$"<span class="hljs-subst">{p.Label}</span>, <span class="hljs-subst">{p.Confidence:<span class="hljs-number">0.00</span>}</span>"</span>;
                g.DrawText(labelText, font, brush, <span class="hljs-keyword" style="color: rgb(0, 0, 255);">new</span> PointF(p.Box.Xmin, p.Box.Ymin));
            }

        });

        <span class="hljs-comment" style="color: green;">// returns bitmap image</span>
        BitmapImage bitmapImage = <span class="hljs-keyword" style="color: rgb(0, 0, 255);">new</span>();
        <span class="hljs-keyword" style="color: rgb(0, 0, 255);">using</span> (MemoryStream memoryStream = <span class="hljs-keyword" style="color: rgb(0, 0, 255);">new</span>())
        {
            image.Save(memoryStream, SixLabors.ImageSharp.Formats.Png.PngFormat.Instance);

            memoryStream.Position = <span class="hljs-number">0</span>;

            bitmapImage.SetSource(memoryStream.AsRandomAccessStream());
        }

        <span class="hljs-keyword" style="color: rgb(0, 0, 255);">return</span> bitmapImage;
    }
}
</pre>



<p>Lastly, the code in MainPage.xaml.cs needs to be updated to use ImageSharp and ImageFunctions. Here I&#8217;ve included the UploadButton_Click method and the DetectObjects method which include the changes required to select an image, load an Image&lt;Rgb24> and use it to prepare the image to run the object detection, and finally to load an updated Image&lt;Rbg24> to display the results.</p>



<pre class="hljs" style="display: block; overflow-x: auto; padding: 0.5em; background: rgb(255, 255, 255); color: rgb(0, 0, 0);"><span class="hljs-function"><span class="hljs-keyword" style="color: rgb(0, 0, 255);">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">async</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">void</span> <span class="hljs-title" style="color: rgb(163, 21, 21);">UploadButton_Click</span>(<span class="hljs-params"><span class="hljs-keyword" style="color: rgb(0, 0, 255);">object</span> sender, RoutedEventArgs e</span>)
</span>{
    <span class="hljs-keyword" style="color: rgb(0, 0, 255);">var</span> window = App.MainWindow ?? <span class="hljs-keyword" style="color: rgb(0, 0, 255);">new</span> Window();
    <span class="hljs-keyword" style="color: rgb(0, 0, 255);">var</span> hwnd = WinRT.Interop.WindowNative.GetWindowHandle(window);

    <span class="hljs-keyword" style="color: rgb(0, 0, 255);">var</span> picker = <span class="hljs-keyword" style="color: rgb(0, 0, 255);">new</span> FileOpenPicker();

    WinRT.Interop.InitializeWithWindow.Initialize(picker, hwnd);

    picker.FileTypeFilter.Add(<span class="hljs-string" style="color: rgb(163, 21, 21);">".png"</span>);
    picker.FileTypeFilter.Add(<span class="hljs-string" style="color: rgb(163, 21, 21);">".jpeg"</span>);
    picker.FileTypeFilter.Add(<span class="hljs-string" style="color: rgb(163, 21, 21);">".jpg"</span>);

    picker.ViewMode = PickerViewMode.Thumbnail;

    <span class="hljs-keyword" style="color: rgb(0, 0, 255);">var</span> file = <span class="hljs-keyword" style="color: rgb(0, 0, 255);">await</span> picker.PickSingleFileAsync();
    <span class="hljs-keyword" style="color: rgb(0, 0, 255);">if</span> (file != <span class="hljs-literal" style="color: rgb(163, 21, 21);">null</span>)
    {
        UploadButton.Focus(FocusState.Programmatic);
        <span class="hljs-keyword" style="color: rgb(0, 0, 255);">await</span> DetectObjects(file);
    }
}

<span class="hljs-function"><span class="hljs-keyword" style="color: rgb(0, 0, 255);">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">async</span> Task <span class="hljs-title" style="color: rgb(163, 21, 21);">DetectObjects</span>(<span class="hljs-params">StorageFile file</span>)
</span>{
    Loader.IsActive = <span class="hljs-literal" style="color: rgb(163, 21, 21);">true</span>;
    Loader.Visibility = Visibility.Visible;
    UploadButton.Visibility = Visibility.Collapsed;

    DefaultImage.Source = <span class="hljs-keyword" style="color: rgb(0, 0, 255);">new</span> BitmapImage(<span class="hljs-keyword" style="color: rgb(0, 0, 255);">new</span> Uri(file.Path));

    Image&lt;Rgb24&gt;? image = <span class="hljs-keyword" style="color: rgb(0, 0, 255);">default</span>;

    <span class="hljs-keyword" style="color: rgb(0, 0, 255);">var</span> predictions = <span class="hljs-keyword" style="color: rgb(0, 0, 255);">await</span> Task.Run(<span class="hljs-keyword" style="color: rgb(0, 0, 255);">async</span> () =&gt;
    {
        <span class="hljs-keyword" style="color: rgb(0, 0, 255);">using</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">var</span> strm = <span class="hljs-keyword" style="color: rgb(0, 0, 255);">await</span> file.OpenStreamForReadAsync();
        image = Image&lt;Rgb24&gt;.Load&lt;Rgb24&gt;(strm);


        <span class="hljs-comment" style="color: green;">// Resizing image ==&gt; Suggested that height and width are in range of [800, 1333].</span>
        <span class="hljs-keyword" style="color: rgb(0, 0, 255);">float</span> ratio = <span class="hljs-number">800</span>f / Math.Max(image.Width, image.Height);
        <span class="hljs-keyword" style="color: rgb(0, 0, 255);">int</span> width = (<span class="hljs-keyword" style="color: rgb(0, 0, 255);">int</span>)(ratio * image.Width);
        <span class="hljs-keyword" style="color: rgb(0, 0, 255);">int</span> height = (<span class="hljs-keyword" style="color: rgb(0, 0, 255);">int</span>)(ratio * image.Height);

        <span class="hljs-keyword" style="color: rgb(0, 0, 255);">var</span> paddedHeight = (<span class="hljs-keyword" style="color: rgb(0, 0, 255);">int</span>)(Math.Ceiling(image.Height / <span class="hljs-number">32</span>f) * <span class="hljs-number">32</span>f);
        <span class="hljs-keyword" style="color: rgb(0, 0, 255);">var</span> paddedWidth = (<span class="hljs-keyword" style="color: rgb(0, 0, 255);">int</span>)(Math.Ceiling(image.Width / <span class="hljs-number">32</span>f) * <span class="hljs-number">32</span>f);

        <span class="hljs-keyword" style="color: rgb(0, 0, 255);">var</span> resizedImage = image.Clone(ctx =&gt;
        {
            ctx.Resize(<span class="hljs-keyword" style="color: rgb(0, 0, 255);">new</span> ResizeOptions
            {
                Size = <span class="hljs-keyword" style="color: rgb(0, 0, 255);">new</span> Size(paddedWidth, paddedHeight),
                Mode = ResizeMode.Pad
            });
        });
        image.Dispose();
        image = resizedImage;


        <span class="hljs-comment" style="color: green;">// Preprocessing</span>
        Tensor&lt;<span class="hljs-keyword" style="color: rgb(0, 0, 255);">float</span>&gt; input = <span class="hljs-keyword" style="color: rgb(0, 0, 255);">new</span> DenseTensor&lt;<span class="hljs-keyword" style="color: rgb(0, 0, 255);">float</span>&gt;([<span class="hljs-number">3</span>, paddedHeight, paddedWidth]);
        input = ImageFunctions.PreprocessBitmapForObjectDetection(image, paddedHeight, paddedWidth);


        <span class="hljs-comment" style="color: green;">// Setup inputs and outputs</span>
        <span class="hljs-keyword" style="color: rgb(0, 0, 255);">var</span> inputMetadataName = _inferenceSession!.InputNames[<span class="hljs-number">0</span>];
        <span class="hljs-keyword" style="color: rgb(0, 0, 255);">var</span> inputs = <span class="hljs-keyword" style="color: rgb(0, 0, 255);">new</span> List&lt;NamedOnnxValue&gt;
        {
            NamedOnnxValue.CreateFromTensor(inputMetadataName, input)
        };

        <span class="hljs-comment" style="color: green;">// Run inference</span>
        <span class="hljs-keyword" style="color: rgb(0, 0, 255);">using</span> IDisposableReadOnlyCollection&lt;DisposableNamedOnnxValue&gt; results = _inferenceSession!.Run(inputs);

        <span class="hljs-comment" style="color: green;">// Postprocess to get predictions</span>
        <span class="hljs-keyword" style="color: rgb(0, 0, 255);">var</span> resultsArray = results.ToArray();
        <span class="hljs-keyword" style="color: rgb(0, 0, 255);">float</span>[] boxes = resultsArray[<span class="hljs-number">0</span>].AsEnumerable&lt;<span class="hljs-keyword" style="color: rgb(0, 0, 255);">float</span>&gt;().ToArray();
        <span class="hljs-keyword" style="color: rgb(0, 0, 255);">long</span>[] labels = resultsArray[<span class="hljs-number">1</span>].AsEnumerable&lt;<span class="hljs-keyword" style="color: rgb(0, 0, 255);">long</span>&gt;().ToArray();
        <span class="hljs-keyword" style="color: rgb(0, 0, 255);">float</span>[] confidences = resultsArray[<span class="hljs-number">2</span>].AsEnumerable&lt;<span class="hljs-keyword" style="color: rgb(0, 0, 255);">float</span>&gt;().ToArray();
        <span class="hljs-keyword" style="color: rgb(0, 0, 255);">var</span> predictions = <span class="hljs-keyword" style="color: rgb(0, 0, 255);">new</span> List&lt;Prediction&gt;();
        <span class="hljs-keyword" style="color: rgb(0, 0, 255);">var</span> minConfidence = <span class="hljs-number">0.7</span>f;
        <span class="hljs-keyword" style="color: rgb(0, 0, 255);">for</span> (<span class="hljs-keyword" style="color: rgb(0, 0, 255);">int</span> i = <span class="hljs-number">0</span>; i &lt; boxes.Length - <span class="hljs-number">4</span>; i += <span class="hljs-number">4</span>)
        {
            <span class="hljs-keyword" style="color: rgb(0, 0, 255);">var</span> index = i / <span class="hljs-number">4</span>;
            <span class="hljs-keyword" style="color: rgb(0, 0, 255);">if</span> (confidences[index] &gt;= minConfidence)
            {
                predictions.Add(<span class="hljs-keyword" style="color: rgb(0, 0, 255);">new</span> Prediction
                {
                    Box = <span class="hljs-keyword" style="color: rgb(0, 0, 255);">new</span> Box(boxes[i], boxes[i + <span class="hljs-number">1</span>], boxes[i + <span class="hljs-number">2</span>], boxes[i + <span class="hljs-number">3</span>]),
                    Label = RCNNLabelMap.Labels[labels[index]],
                    Confidence = confidences[index]
                });
            }
        }

        <span class="hljs-keyword" style="color: rgb(0, 0, 255);">return</span> predictions;
    });

    BitmapImage outputImage = <span class="hljs-keyword" style="color: rgb(0, 0, 255);">await</span> ImageFunctions.RenderPredictions(image!, predictions);

    DispatcherQueue.TryEnqueue(() =&gt;
    {
        DefaultImage.Source = outputImage;
        Loader.IsActive = <span class="hljs-literal" style="color: rgb(163, 21, 21);">false</span>;
        Loader.Visibility = Visibility.Collapsed;
        UploadButton.Visibility = Visibility.Visible;
    });

    image.Dispose();
}</pre>



<p>Our application is good to go for Android. For some reason, I didn&#8217;t have much luck running this code on an Android emulator but it runs fine on an actual Android device. However, I will comment that the object detection isn&#8217;t particularly fast &#8211; there might be some room to optimize the image manipulation code.</p>
<p>The post <a href="https://nicksnettravels.builttoroam.com/ai-dev-gallery-uno-platform-android/">Taking AI Dev Gallery Code Cross Platform with Uno Platform &#8211; Android</a> appeared first on <a href="https://nicksnettravels.builttoroam.com">Nick&#039;s .NET Travels</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://nicksnettravels.builttoroam.com/ai-dev-gallery-uno-platform-android/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title>Adding AI to an Uno Platform Application using AI Dev Gallery</title>
		<link>https://nicksnettravels.builttoroam.com/ai-dev-gallery-meets-uno-platform/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=ai-dev-gallery-meets-uno-platform</link>
					<comments>https://nicksnettravels.builttoroam.com/ai-dev-gallery-meets-uno-platform/#comments</comments>
		
		<dc:creator><![CDATA[Nick]]></dc:creator>
		<pubDate>Tue, 31 Dec 2024 07:13:55 +0000</pubDate>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[AI]]></category>
		<category><![CDATA[Uno Platform]]></category>
		<category><![CDATA[Windows]]></category>
		<guid isPermaLink="false">https://nicksnettravels.builttoroam.com/?p=3305</guid>

					<description><![CDATA[<p>In my previous post I introduced the AI Dev Gallery that Microsoft has been working on, as a way of creating a Windows application that can use AI. In my post I exported the code for object detection, which uses the Faster RCNN 10 model. In this post, we&#8217;re going to take this code and ... <a title="Adding AI to an Uno Platform Application using AI Dev Gallery" class="read-more" href="https://nicksnettravels.builttoroam.com/ai-dev-gallery-meets-uno-platform/" aria-label="Read more about Adding AI to an Uno Platform Application using AI Dev Gallery">Read more</a></p>
<p>The post <a href="https://nicksnettravels.builttoroam.com/ai-dev-gallery-meets-uno-platform/">Adding AI to an Uno Platform Application using AI Dev Gallery</a> appeared first on <a href="https://nicksnettravels.builttoroam.com">Nick&#039;s .NET Travels</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>In my <a href="https://nicksnettravels.builttoroam.com/ai-dev-gallery/">previous post</a> I introduced the <a href="https://techcommunity.microsoft.com/blog/azuredevcommunityblog/getting-started-with-the-ai-dev-gallery/4354803">AI Dev Gallery</a> that Microsoft has been working on, as a way of creating a Windows application that can use AI. In my post I exported the code for object detection, which uses the Faster RCNN 10 model. In this post, we&#8217;re going to take this code and add it into an Uno Platform application, with a view of being able to take the code cross platform.</p>



<p>We&#8217;ll start by creating a new Uno Platform application, called ObjectDetection. From the Uno Platform Template Wizard, select the Blank preset on the left side of the window, and then click Create. </p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2024/12/image-6771948b6c299.png"><img loading="lazy" decoding="async" width="300" height="245" src="https://wordpressblogimages.builttoroam.com/blogimages/2024/12/image-6771948b6c299-300x245.png" alt="" class="wp-image-3306" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2024/12/image-6771948b6c299-300x245.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2024/12/image-6771948b6c299-1024x836.png 1024w, https://wordpressblogimages.builttoroam.com/blogimages/2024/12/image-6771948b6c299-768x627.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2024/12/image-6771948b6c299.png 1398w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>Before we start adding the code for object detection, we first need to add some project references and of course the Faster RCNN model file. In the ObjectDetection project file, add the following PackageReference elements.</p>



<pre class="hljs" style="display: block; overflow-x: auto; padding: 0.5em; background: rgb(255, 255, 255); color: rgb(0, 0, 0);"><span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">ItemGroup</span>&gt;</span>
    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">PackageReference</span> <span class="hljs-attr" style="color: red;">Include</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Microsoft.ML.OnnxRuntime.DirectML"</span> /&gt;</span>
    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">PackageReference</span> <span class="hljs-attr" style="color: red;">Include</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Microsoft.ML.OnnxRuntime.Extensions"</span> /&gt;</span>
    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">PackageReference</span> <span class="hljs-attr" style="color: red;">Include</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"System.Drawing.Common"</span> /&gt;</span>
<span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">ItemGroup</span>&gt;</span>
</pre>



<p>The corresponding PackageVersion needs to be added to the Directory.Packages.props file.</p>



<pre class="hljs" style="display: block; overflow-x: auto; padding: 0.5em; background: rgb(255, 255, 255); color: rgb(0, 0, 0);"><span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">Project</span> <span class="hljs-attr" style="color: red;">ToolsVersion</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"15.0"</span>&gt;</span>
    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">ItemGroup</span>&gt;</span>
        <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">PackageVersion</span> <span class="hljs-attr" style="color: red;">Include</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Microsoft.ML.OnnxRuntime.DirectML"</span> <span class="hljs-attr" style="color: red;">Version</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"1.20.1"</span> /&gt;</span>
        <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">PackageVersion</span> <span class="hljs-attr" style="color: red;">Include</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Microsoft.ML.OnnxRuntime.Extensions"</span> <span class="hljs-attr" style="color: red;">Version</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"0.13.0"</span> /&gt;</span>
        <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">PackageVersion</span> <span class="hljs-attr" style="color: red;">Include</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"System.Drawing.Common"</span> <span class="hljs-attr" style="color: red;">Version</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"9.0.0"</span> /&gt;</span>
    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">ItemGroup</span>&gt;</span>
<span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">Project</span>&gt;</span>
</pre>



<p>Next, copy the Models folder, which includes the FasterRCCN-10.onnx file, from the exported project, into the ObjectDetection project folder. In Visual Studio, select the onnx file and in the Properties winodw, set the Build Action to Content.</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2024/12/image-6771983c23830.png"><img loading="lazy" decoding="async" width="132" height="300" src="https://wordpressblogimages.builttoroam.com/blogimages/2024/12/image-6771983c23830-132x300.png" alt="" class="wp-image-3307" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2024/12/image-6771983c23830-132x300.png 132w, https://wordpressblogimages.builttoroam.com/blogimages/2024/12/image-6771983c23830.png 375w" sizes="auto, (max-width: 132px) 100vw, 132px" /></a></figure>



<p>Now it&#8217;s time to copy across the bulk of the code from the exported project into the ObjectDetection project. Copy the files, BitmapFunctions.cs, HardwareAccelerator.cs, Prediction.cs and RCNNLabelMap.cs into the ObjectDetection project (Note that in BitmapFunctions.cs there&#8217;s an ambiguous type reference, which can be resolved by replacing the type &#8220;Brush&#8221; with &#8220;var&#8221;)</p>



<p>Instead of copying across the ObjectDetection.xaml and ObjectDetection.xaml.cs files, we&#8217;ll copy the contents of these files into the existing MainPage.xaml and MainPage.xaml.cs files. Here&#8217;s the MainPage.xaml:</p>



<pre class="hljs" style="display: block; overflow-x: auto; padding: 0.5em; background: rgb(255, 255, 255); color: rgb(0, 0, 0);"><span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">Page</span> <span class="hljs-attr" style="color: red;">x:Class</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"ObjectDetection.MainPage"</span>
      <span class="hljs-attr" style="color: red;">xmlns</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"http://schemas.microsoft.com/winfx/2006/xaml/presentation"</span>
      <span class="hljs-attr" style="color: red;">xmlns:x</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"http://schemas.microsoft.com/winfx/2006/xaml"</span>
      <span class="hljs-attr" style="color: red;">xmlns:local</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"using:ObjectDetection"</span>
      <span class="hljs-attr" style="color: red;">Background</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"{ThemeResource ApplicationPageBackgroundThemeBrush}"</span>&gt;</span>
    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">ScrollViewer</span>&gt;</span>
        <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">Grid</span> <span class="hljs-attr" style="color: red;">RowSpacing</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"16"</span>&gt;</span>
            <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">Grid.RowDefinitions</span>&gt;</span>
                <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">RowDefinition</span> <span class="hljs-attr" style="color: red;">Height</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Auto"</span> /&gt;</span>
                <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">RowDefinition</span> <span class="hljs-attr" style="color: red;">Height</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Auto"</span> /&gt;</span>
            <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">Grid.RowDefinitions</span>&gt;</span>
            <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">Image</span> <span class="hljs-attr" style="color: red;">x:Name</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"DefaultImage"</span>
                   <span class="hljs-attr" style="color: red;">MaxWidth</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"800"</span>
                   <span class="hljs-attr" style="color: red;">MaxHeight</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"500"</span> /&gt;</span>
            <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">ProgressRing</span> <span class="hljs-attr" style="color: red;">x:Name</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Loader"</span>
                          <span class="hljs-attr" style="color: red;">Grid.Row</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"1"</span>
                          <span class="hljs-attr" style="color: red;">IsActive</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"false"</span>
                          <span class="hljs-attr" style="color: red;">Visibility</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Collapsed"</span> /&gt;</span>
            <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">Button</span> <span class="hljs-attr" style="color: red;">x:Name</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"UploadButton"</span>
                    <span class="hljs-attr" style="color: red;">Grid.Row</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"1"</span>
                    <span class="hljs-attr" style="color: red;">HorizontalAlignment</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Center"</span>
                    <span class="hljs-attr" style="color: red;">Click</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"UploadButton_Click"</span>
                    <span class="hljs-attr" style="color: red;">Content</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Select image"</span>
                    <span class="hljs-attr" style="color: red;">Style</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"{StaticResource AccentButtonStyle}"</span> /&gt;</span>
        <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">Grid</span>&gt;</span>
    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">ScrollViewer</span>&gt;</span>
<span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">Page</span>&gt;</span></pre>



<p>And the corresponding MainPage.xaml.cs. Note that we&#8217;ve commented out the line that hides the ProgressRing in the exported project, and the initial call to DetectObject since we won&#8217;t be packaging any images with the application for now.</p>



<pre class="hljs" style="display: block; overflow-x: auto; padding: 0.5em; background: rgb(255, 255, 255); color: rgb(0, 0, 0);"><span class="hljs-keyword" style="color: rgb(0, 0, 255);">using</span> Faster_RCNN_Object_DetectionSample.SharedCode;
<span class="hljs-keyword" style="color: rgb(0, 0, 255);">using</span> Microsoft.ML.OnnxRuntime.Tensors;
<span class="hljs-keyword" style="color: rgb(0, 0, 255);">using</span> Microsoft.ML.OnnxRuntime;
<span class="hljs-keyword" style="color: rgb(0, 0, 255);">using</span> Microsoft.UI.Xaml.Media.Imaging;
<span class="hljs-keyword" style="color: rgb(0, 0, 255);">using</span> Windows.Storage.Pickers;
<span class="hljs-keyword" style="color: rgb(0, 0, 255);">using</span> System.Drawing;

<span class="hljs-keyword" style="color: rgb(0, 0, 255);">namespace</span> <span class="hljs-title" style="color: rgb(163, 21, 21);">ObjectDetection</span>;

<span class="hljs-keyword" style="color: rgb(0, 0, 255);">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">sealed</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">partial</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">class</span> <span class="hljs-title" style="color: rgb(163, 21, 21);">MainPage</span> : <span class="hljs-title" style="color: rgb(163, 21, 21);">Page</span>
{
    <span class="hljs-keyword" style="color: rgb(0, 0, 255);">private</span> InferenceSession? _inferenceSession;

    <span class="hljs-function"><span class="hljs-keyword" style="color: rgb(0, 0, 255);">public</span> <span class="hljs-title" style="color: rgb(163, 21, 21);">MainPage</span>(<span class="hljs-params"></span>)
    </span>{
        <span class="hljs-keyword" style="color: rgb(0, 0, 255);">this</span>.Unloaded += (s, e) =&gt; _inferenceSession?.Dispose();
        <span class="hljs-keyword" style="color: rgb(0, 0, 255);">this</span>.InitializeComponent();
    }

    <span class="hljs-function"><span class="hljs-keyword" style="color: rgb(0, 0, 255);">protected</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">override</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">async</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">void</span> <span class="hljs-title" style="color: rgb(163, 21, 21);">OnNavigatedTo</span>(<span class="hljs-params">Microsoft.UI.Xaml.Navigation.NavigationEventArgs e</span>)
    </span>{
        <span class="hljs-keyword" style="color: rgb(0, 0, 255);">await</span> InitModel(System.IO.Path.Join(Windows.ApplicationModel.Package.Current.InstalledLocation.Path, <span class="hljs-string" style="color: rgb(163, 21, 21);">"Models"</span>, <span class="hljs-string" style="color: rgb(163, 21, 21);">@"FasterRCNN-10.onnx"</span>));

        <span class="hljs-comment" style="color: green;">//App.Window?.ModelLoaded();</span>

        <span class="hljs-comment" style="color: green;">// Loads inference on default image</span>
        <span class="hljs-comment" style="color: green;">//await DetectObjects(Windows.ApplicationModel.Package.Current.InstalledLocation.Path + "\\Assets\\team.jpg");</span>
    }

    <span class="hljs-function"><span class="hljs-keyword" style="color: rgb(0, 0, 255);">private</span> Task <span class="hljs-title" style="color: rgb(163, 21, 21);">InitModel</span>(<span class="hljs-params"><span class="hljs-keyword" style="color: rgb(0, 0, 255);">string</span> modelPath</span>)
    </span>{
        <span class="hljs-keyword" style="color: rgb(0, 0, 255);">return</span> Task.Run(() =&gt;
        {
            <span class="hljs-keyword" style="color: rgb(0, 0, 255);">if</span> (_inferenceSession != <span class="hljs-literal" style="color: rgb(163, 21, 21);">null</span>)
            {
                <span class="hljs-keyword" style="color: rgb(0, 0, 255);">return</span>;
            }

            SessionOptions sessionOptions = <span class="hljs-keyword" style="color: rgb(0, 0, 255);">new</span>();
            sessionOptions.RegisterOrtExtensions();

            _inferenceSession = <span class="hljs-keyword" style="color: rgb(0, 0, 255);">new</span> InferenceSession(modelPath, sessionOptions);
        });
    }

    <span class="hljs-function"><span class="hljs-keyword" style="color: rgb(0, 0, 255);">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">async</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">void</span> <span class="hljs-title" style="color: rgb(163, 21, 21);">UploadButton_Click</span>(<span class="hljs-params"><span class="hljs-keyword" style="color: rgb(0, 0, 255);">object</span> sender, RoutedEventArgs e</span>)
    </span>{
        <span class="hljs-keyword" style="color: rgb(0, 0, 255);">var</span> window = <span class="hljs-keyword" style="color: rgb(0, 0, 255);">new</span> Window();
        <span class="hljs-keyword" style="color: rgb(0, 0, 255);">var</span> hwnd = WinRT.Interop.WindowNative.GetWindowHandle(window);

        <span class="hljs-keyword" style="color: rgb(0, 0, 255);">var</span> picker = <span class="hljs-keyword" style="color: rgb(0, 0, 255);">new</span> FileOpenPicker();

        WinRT.Interop.InitializeWithWindow.Initialize(picker, hwnd);

        picker.FileTypeFilter.Add(<span class="hljs-string" style="color: rgb(163, 21, 21);">".png"</span>);
        picker.FileTypeFilter.Add(<span class="hljs-string" style="color: rgb(163, 21, 21);">".jpeg"</span>);
        picker.FileTypeFilter.Add(<span class="hljs-string" style="color: rgb(163, 21, 21);">".jpg"</span>);

        picker.ViewMode = PickerViewMode.Thumbnail;

        <span class="hljs-keyword" style="color: rgb(0, 0, 255);">var</span> file = <span class="hljs-keyword" style="color: rgb(0, 0, 255);">await</span> picker.PickSingleFileAsync();
        <span class="hljs-keyword" style="color: rgb(0, 0, 255);">if</span> (file != <span class="hljs-literal" style="color: rgb(163, 21, 21);">null</span>)
        {
            UploadButton.Focus(FocusState.Programmatic);
            <span class="hljs-keyword" style="color: rgb(0, 0, 255);">await</span> DetectObjects(file.Path);
        }
    }

    <span class="hljs-function"><span class="hljs-keyword" style="color: rgb(0, 0, 255);">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">async</span> Task <span class="hljs-title" style="color: rgb(163, 21, 21);">DetectObjects</span>(<span class="hljs-params"><span class="hljs-keyword" style="color: rgb(0, 0, 255);">string</span> filePath</span>)
    </span>{
        Loader.IsActive = <span class="hljs-literal" style="color: rgb(163, 21, 21);">true</span>;
        Loader.Visibility = Visibility.Visible;
        UploadButton.Visibility = Visibility.Collapsed;

        DefaultImage.Source = <span class="hljs-keyword" style="color: rgb(0, 0, 255);">new</span> BitmapImage(<span class="hljs-keyword" style="color: rgb(0, 0, 255);">new</span> Uri(filePath));

        Bitmap image = <span class="hljs-keyword" style="color: rgb(0, 0, 255);">new</span>(filePath);

        <span class="hljs-keyword" style="color: rgb(0, 0, 255);">var</span> predictions = <span class="hljs-keyword" style="color: rgb(0, 0, 255);">await</span> Task.Run(() =&gt;
        {
            <span class="hljs-comment" style="color: green;">// Resizing image ==&gt; Suggested that height and width are in range of [800, 1333].</span>
            <span class="hljs-keyword" style="color: rgb(0, 0, 255);">float</span> ratio = <span class="hljs-number">800</span>f / Math.Max(image.Width, image.Height);
            <span class="hljs-keyword" style="color: rgb(0, 0, 255);">int</span> width = (<span class="hljs-keyword" style="color: rgb(0, 0, 255);">int</span>)(ratio * image.Width);
            <span class="hljs-keyword" style="color: rgb(0, 0, 255);">int</span> height = (<span class="hljs-keyword" style="color: rgb(0, 0, 255);">int</span>)(ratio * image.Height);

            <span class="hljs-keyword" style="color: rgb(0, 0, 255);">var</span> paddedHeight = (<span class="hljs-keyword" style="color: rgb(0, 0, 255);">int</span>)(Math.Ceiling(image.Height / <span class="hljs-number">32</span>f) * <span class="hljs-number">32</span>f);
            <span class="hljs-keyword" style="color: rgb(0, 0, 255);">var</span> paddedWidth = (<span class="hljs-keyword" style="color: rgb(0, 0, 255);">int</span>)(Math.Ceiling(image.Width / <span class="hljs-number">32</span>f) * <span class="hljs-number">32</span>f);

            <span class="hljs-keyword" style="color: rgb(0, 0, 255);">var</span> resizedImage = BitmapFunctions.ResizeBitmap(image, paddedWidth, paddedHeight);
            image.Dispose();
            image = resizedImage;

            <span class="hljs-comment" style="color: green;">// Preprocessing</span>
            Tensor&lt;<span class="hljs-keyword" style="color: rgb(0, 0, 255);">float</span>&gt; input = <span class="hljs-keyword" style="color: rgb(0, 0, 255);">new</span> DenseTensor&lt;<span class="hljs-keyword" style="color: rgb(0, 0, 255);">float</span>&gt;([<span class="hljs-number">3</span>, paddedHeight, paddedWidth]);
            input = BitmapFunctions.PreprocessBitmapForObjectDetection(image, paddedHeight, paddedWidth);

            <span class="hljs-comment" style="color: green;">// Setup inputs and outputs</span>
            <span class="hljs-keyword" style="color: rgb(0, 0, 255);">var</span> inputMetadataName = _inferenceSession!.InputNames[<span class="hljs-number">0</span>];
            <span class="hljs-keyword" style="color: rgb(0, 0, 255);">var</span> inputs = <span class="hljs-keyword" style="color: rgb(0, 0, 255);">new</span> List&lt;NamedOnnxValue&gt;
            {
                NamedOnnxValue.CreateFromTensor(inputMetadataName, input)
            };

            <span class="hljs-comment" style="color: green;">// Run inference</span>
            <span class="hljs-keyword" style="color: rgb(0, 0, 255);">using</span> IDisposableReadOnlyCollection&lt;DisposableNamedOnnxValue&gt; results = _inferenceSession!.Run(inputs);

            <span class="hljs-comment" style="color: green;">// Postprocess to get predictions</span>
            <span class="hljs-keyword" style="color: rgb(0, 0, 255);">var</span> resultsArray = results.ToArray();
            <span class="hljs-keyword" style="color: rgb(0, 0, 255);">float</span>[] boxes = resultsArray[<span class="hljs-number">0</span>].AsEnumerable&lt;<span class="hljs-keyword" style="color: rgb(0, 0, 255);">float</span>&gt;().ToArray();
            <span class="hljs-keyword" style="color: rgb(0, 0, 255);">long</span>[] labels = resultsArray[<span class="hljs-number">1</span>].AsEnumerable&lt;<span class="hljs-keyword" style="color: rgb(0, 0, 255);">long</span>&gt;().ToArray();
            <span class="hljs-keyword" style="color: rgb(0, 0, 255);">float</span>[] confidences = resultsArray[<span class="hljs-number">2</span>].AsEnumerable&lt;<span class="hljs-keyword" style="color: rgb(0, 0, 255);">float</span>&gt;().ToArray();
            <span class="hljs-keyword" style="color: rgb(0, 0, 255);">var</span> predictions = <span class="hljs-keyword" style="color: rgb(0, 0, 255);">new</span> List&lt;Prediction&gt;();
            <span class="hljs-keyword" style="color: rgb(0, 0, 255);">var</span> minConfidence = <span class="hljs-number">0.7</span>f;
            <span class="hljs-keyword" style="color: rgb(0, 0, 255);">for</span> (<span class="hljs-keyword" style="color: rgb(0, 0, 255);">int</span> i = <span class="hljs-number">0</span>; i &lt; boxes.Length - <span class="hljs-number">4</span>; i += <span class="hljs-number">4</span>)
            {
                <span class="hljs-keyword" style="color: rgb(0, 0, 255);">var</span> index = i / <span class="hljs-number">4</span>;
                <span class="hljs-keyword" style="color: rgb(0, 0, 255);">if</span> (confidences[index] &gt;= minConfidence)
                {
                    predictions.Add(<span class="hljs-keyword" style="color: rgb(0, 0, 255);">new</span> Prediction
                    {
                        Box = <span class="hljs-keyword" style="color: rgb(0, 0, 255);">new</span> Box(boxes[i], boxes[i + <span class="hljs-number">1</span>], boxes[i + <span class="hljs-number">2</span>], boxes[i + <span class="hljs-number">3</span>]),
                        Label = RCNNLabelMap.Labels[labels[index]],
                        Confidence = confidences[index]
                    });
                }
            }

            <span class="hljs-keyword" style="color: rgb(0, 0, 255);">return</span> predictions;
        });

        BitmapImage outputImage = BitmapFunctions.RenderPredictions(image, predictions);

        DispatcherQueue.TryEnqueue(() =&gt;
        {
            DefaultImage.Source = outputImage;
            Loader.IsActive = <span class="hljs-literal" style="color: rgb(163, 21, 21);">false</span>;
            Loader.Visibility = Visibility.Collapsed;
            UploadButton.Visibility = Visibility.Visible;
        });

        image.Dispose();
    }
}
</pre>



<p>As you would imagine, running this application on Windows (WinAppSdk) doesn&#8217;t look much different that the exported application.</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2024/12/image-677398b7790fc.png"><img loading="lazy" decoding="async" width="300" height="224" src="https://wordpressblogimages.builttoroam.com/blogimages/2024/12/image-677398b7790fc-300x224.png" alt="" class="wp-image-3309" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2024/12/image-677398b7790fc-300x224.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2024/12/image-677398b7790fc-1024x764.png 1024w, https://wordpressblogimages.builttoroam.com/blogimages/2024/12/image-677398b7790fc-768x573.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2024/12/image-677398b7790fc.png 1036w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2024/12/image-677398c7cfbd1.png"><img loading="lazy" decoding="async" width="300" height="224" src="https://wordpressblogimages.builttoroam.com/blogimages/2024/12/image-677398c7cfbd1-300x224.png" alt="" class="wp-image-3310" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2024/12/image-677398c7cfbd1-300x224.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2024/12/image-677398c7cfbd1-1024x764.png 1024w, https://wordpressblogimages.builttoroam.com/blogimages/2024/12/image-677398c7cfbd1-768x573.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2024/12/image-677398c7cfbd1.png 1036w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>What&#8217;s a little misleading here is that whilst all the different Uno Platform target platforms build, if we attempt to run the application on other targets, we&#8217;ll run into some issues. In the next post in this series we&#8217;ll look at what&#8217;s not compatible with cross platform targets and how we can improve this sample code to get this object detection sample to work on other platforms. </p>
<p>The post <a href="https://nicksnettravels.builttoroam.com/ai-dev-gallery-meets-uno-platform/">Adding AI to an Uno Platform Application using AI Dev Gallery</a> appeared first on <a href="https://nicksnettravels.builttoroam.com">Nick&#039;s .NET Travels</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://nicksnettravels.builttoroam.com/ai-dev-gallery-meets-uno-platform/feed/</wfw:commentRss>
			<slash:comments>3</slash:comments>
		
		
			</item>
		<item>
		<title>Using the AI Dev Gallery to Create a Windows Application with AI</title>
		<link>https://nicksnettravels.builttoroam.com/ai-dev-gallery/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=ai-dev-gallery</link>
					<comments>https://nicksnettravels.builttoroam.com/ai-dev-gallery/#comments</comments>
		
		<dc:creator><![CDATA[Nick]]></dc:creator>
		<pubDate>Sat, 28 Dec 2024 17:33:59 +0000</pubDate>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[AI]]></category>
		<category><![CDATA[Uno Platform]]></category>
		<category><![CDATA[Windows]]></category>
		<guid isPermaLink="false">https://nicksnettravels.builttoroam.com/?p=3299</guid>

					<description><![CDATA[<p>Recently, Microsoft announced an open-sourced project that they&#8217;ve been working on, AI Dev Gallery. Whilst it&#8217;s not available on the Microsoft Store as an app you can download, it&#8217;s easy enough to clone the repository and run the app. In this post we&#8217;ll use the AI Dev Gallery to build a simple Windows application that ... <a title="Using the AI Dev Gallery to Create a Windows Application with AI" class="read-more" href="https://nicksnettravels.builttoroam.com/ai-dev-gallery/" aria-label="Read more about Using the AI Dev Gallery to Create a Windows Application with AI">Read more</a></p>
<p>The post <a href="https://nicksnettravels.builttoroam.com/ai-dev-gallery/">Using the AI Dev Gallery to Create a Windows Application with AI</a> appeared first on <a href="https://nicksnettravels.builttoroam.com">Nick&#039;s .NET Travels</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p> </p>



<p>Recently, Microsoft announced an open-sourced project that they&#8217;ve been working on, <a href="https://techcommunity.microsoft.com/blog/azuredevcommunityblog/getting-started-with-the-ai-dev-gallery/4354803">AI Dev Gallery</a>. Whilst it&#8217;s not available on the Microsoft Store as an app you can download, it&#8217;s easy enough to clone the repository and run the app. In this post we&#8217;ll use the AI Dev Gallery to build a simple Windows application that can detect objects in an image.</p>



<p>Let&#8217;s get started by running the AI Dev Gallery. </p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2024/12/image-676ed26db1556.png"><img loading="lazy" decoding="async" width="300" height="213" src="https://wordpressblogimages.builttoroam.com/blogimages/2024/12/image-676ed26db1556-300x213.png" alt="" class="wp-image-3300" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2024/12/image-676ed26db1556-300x213.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2024/12/image-676ed26db1556-1024x728.png 1024w, https://wordpressblogimages.builttoroam.com/blogimages/2024/12/image-676ed26db1556-768x546.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2024/12/image-676ed26db1556-1536x1092.png 1536w, https://wordpressblogimages.builttoroam.com/blogimages/2024/12/image-676ed26db1556.png 1584w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>At the core, the application makes use of a NavigationView to switch between Home, Samples and Models. There&#8217;s also a search box in the TitleBar that can be used to search samples or models. For example searching for &#8216;object&#8217; returns &#8220;Detect Objects&#8221;, a sample that makes use of the Faster RCNN 10 model to detect objects in images.</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2024/12/image-676ed2a7596e4.png"><img loading="lazy" decoding="async" width="300" height="193" src="https://wordpressblogimages.builttoroam.com/blogimages/2024/12/image-676ed2a7596e4-300x193.png" alt="" class="wp-image-3301" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2024/12/image-676ed2a7596e4-300x193.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2024/12/image-676ed2a7596e4-1024x660.png 1024w, https://wordpressblogimages.builttoroam.com/blogimages/2024/12/image-676ed2a7596e4-768x495.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2024/12/image-676ed2a7596e4.png 1462w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>In the top right corner, there are buttons for showing the Code for the sample, and to Export a project that includes the sample code, and optionally the model.</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2024/12/image-676ed3d7812f9.png"><img loading="lazy" decoding="async" width="300" height="215" src="https://wordpressblogimages.builttoroam.com/blogimages/2024/12/image-676ed3d7812f9-300x215.png" alt="" class="wp-image-3302" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2024/12/image-676ed3d7812f9-300x215.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2024/12/image-676ed3d7812f9-1024x734.png 1024w, https://wordpressblogimages.builttoroam.com/blogimages/2024/12/image-676ed3d7812f9-768x550.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2024/12/image-676ed3d7812f9-1536x1100.png 1536w, https://wordpressblogimages.builttoroam.com/blogimages/2024/12/image-676ed3d7812f9.png 1671w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>The exported project can be opened and run in Visual Studio. You can select an image and any objects detected will be highlighted with a red box and a title showing the object type and confidence level.</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2024/12/image-6770234c066bd.png"><img loading="lazy" decoding="async" width="300" height="213" src="https://wordpressblogimages.builttoroam.com/blogimages/2024/12/image-6770234c066bd-300x213.png" alt="" class="wp-image-3303" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2024/12/image-6770234c066bd-300x213.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2024/12/image-6770234c066bd-1024x727.png 1024w, https://wordpressblogimages.builttoroam.com/blogimages/2024/12/image-6770234c066bd-768x545.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2024/12/image-6770234c066bd.png 1279w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>In the next post we&#8217;ll take the sample code and add it into an Uno Platform application so that we can take it cross platform.</p>



<p></p>
<p>The post <a href="https://nicksnettravels.builttoroam.com/ai-dev-gallery/">Using the AI Dev Gallery to Create a Windows Application with AI</a> appeared first on <a href="https://nicksnettravels.builttoroam.com">Nick&#039;s .NET Travels</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://nicksnettravels.builttoroam.com/ai-dev-gallery/feed/</wfw:commentRss>
			<slash:comments>4</slash:comments>
		
		
			</item>
		<item>
		<title>Windows UI Kit for Figma</title>
		<link>https://nicksnettravels.builttoroam.com/windows-ui-kit-for-figma/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=windows-ui-kit-for-figma</link>
					<comments>https://nicksnettravels.builttoroam.com/windows-ui-kit-for-figma/#comments</comments>
		
		<dc:creator><![CDATA[Nick]]></dc:creator>
		<pubDate>Sat, 07 Dec 2024 16:36:01 +0000</pubDate>
				<category><![CDATA[Announcements]]></category>
		<category><![CDATA[Design]]></category>
		<category><![CDATA[Figma]]></category>
		<category><![CDATA[Windows App SDK]]></category>
		<category><![CDATA[WinUI]]></category>
		<guid isPermaLink="false">https://nicksnettravels.builttoroam.com/?p=3293</guid>

					<description><![CDATA[<p>The Figma Windows UI kit file has been updated by the WinUI team. If you&#8217;re looking to design an app for Windows (or the Uno Platform), this is a great resource for working with Fluent design. Alternatively if you want to use Material, you can use the Uno Platform Material Toolkit.</p>
<p>The post <a href="https://nicksnettravels.builttoroam.com/windows-ui-kit-for-figma/">Windows UI Kit for Figma</a> appeared first on <a href="https://nicksnettravels.builttoroam.com">Nick&#039;s .NET Travels</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>The Figma <a href="https://aka.ms/WinUI/3.0-figma-toolkit">Windows UI kit </a>file has been updated by the WinUI team. If you&#8217;re looking to design an app for Windows (or the Uno Platform), this is a great resource for working with Fluent design. Alternatively if you want to use Material, you can use the <a href="https://www.figma.com/community/file/1110792522046146058/uno-platform-material-toolkit">Uno Platform Material Toolkit</a>.</p>



<p> </p>



<p></p>
<p>The post <a href="https://nicksnettravels.builttoroam.com/windows-ui-kit-for-figma/">Windows UI Kit for Figma</a> appeared first on <a href="https://nicksnettravels.builttoroam.com">Nick&#039;s .NET Travels</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://nicksnettravels.builttoroam.com/windows-ui-kit-for-figma/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title>Adding AI to a Windows and Uno Platform Application using Microsoft.Extensions.AI</title>
		<link>https://nicksnettravels.builttoroam.com/microsoft-extensions-ai/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=microsoft-extensions-ai</link>
					<comments>https://nicksnettravels.builttoroam.com/microsoft-extensions-ai/#comments</comments>
		
		<dc:creator><![CDATA[Nick]]></dc:creator>
		<pubDate>Sun, 13 Oct 2024 18:06:30 +0000</pubDate>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[AI]]></category>
		<category><![CDATA[Azure]]></category>
		<category><![CDATA[GitHub]]></category>
		<category><![CDATA[Microsoft.Extensions]]></category>
		<category><![CDATA[Uno Platform]]></category>
		<category><![CDATA[Uno.Extensions]]></category>
		<category><![CDATA[WinAppSdk]]></category>
		<category><![CDATA[Windows]]></category>
		<guid isPermaLink="false">https://nicksnettravels.builttoroam.com/?p=3277</guid>

					<description><![CDATA[<p>Earlier this month Microsoft introduced the preview of Microsoft.Extensions.AI.Abstractions and Microsoft.Extensions.AI libraries with the aim of making it easier for .NET developers to integrate AI services into their applications. The Uno Platform provides support for using Microsoft.Extensions in applications that target Windows and any other Uno Platform target (iOS, Android, MacCatalyst etc) via the Uno.Extensions ... <a title="Adding AI to a Windows and Uno Platform Application using Microsoft.Extensions.AI" class="read-more" href="https://nicksnettravels.builttoroam.com/microsoft-extensions-ai/" aria-label="Read more about Adding AI to a Windows and Uno Platform Application using Microsoft.Extensions.AI">Read more</a></p>
<p>The post <a href="https://nicksnettravels.builttoroam.com/microsoft-extensions-ai/">Adding AI to a Windows and Uno Platform Application using Microsoft.Extensions.AI</a> appeared first on <a href="https://nicksnettravels.builttoroam.com">Nick&#039;s .NET Travels</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>Earlier this month Microsoft introduced the <a href="https://devblogs.microsoft.com/dotnet/introducing-microsoft-extensions-ai-preview/">preview of Microsoft.Extensions.AI.Abstractions and Microsoft.Extensions.AI libraries</a> with the aim of making it easier for .NET developers to integrate AI services into their applications. The <a href="https://platform.uno/">Uno Platform</a> provides support for using Microsoft.Extensions in applications that target Windows and any other Uno Platform target (iOS, Android, MacCatalyst etc) via the Uno.Extensions set of packages. In this post I&#8217;ll cover adding Microsoft.Extensions.AI into an Uno Platform application using Uno.Extensions.</p>



<p>We&#8217;ll start by creating a new application using the Uno Platform Template Wizard from within Visual Studio. If you&#8217;re not using Visual Studio, you can generate the appropriate &#8220;dotnet new&#8221; commandline via the online wizard at https://new.platform.uno/. We&#8217;re going to go with the default &#8220;Recommended&#8221; preset and click the Create button.</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="831" src="https://wordpressblogimages.builttoroam.com/blogimages/2024/10/image-1024x831.png" alt="" class="wp-image-3278" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2024/10/image-1024x831.png 1024w, https://wordpressblogimages.builttoroam.com/blogimages/2024/10/image-300x244.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2024/10/image-768x623.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2024/10/image.png 1387w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p>Once the application has been created, we&#8217;re going to add a chat client to the application. The Recommended preset already sets the application up to use the Microsoft.Extensions hosting, which means we can register both the OpenAIClient and a ChatClient. Before we can do that, we need to add references to the Microsoft.Extensions.AI and Microsoft.Extensions.AI.OpenAI packages.</p>



<p>The OpenAIClient and ChatClient can be registered in the App.xaml.cs by amending the ConfigureService call to add an OpenAIClient as a singleton and a ChatClient using the AddChatClient extension method.</p>



<pre class="hljs" style="display: block; overflow-x: auto; padding: 0.5em; background: rgb(255, 255, 255); color: rgb(0, 0, 0);">.ConfigureServices((context, services) =&gt;
{
    services.AddSingleton(<span class="hljs-keyword" style="color: rgb(0, 0, 255);">new</span> OpenAIClient(context.Configuration[<span class="hljs-string" style="color: rgb(163, 21, 21);">"AI:OpenAI:Key"</span>]));
    services.AddChatClient(c =&gt; {
        <span class="hljs-keyword" style="color: rgb(0, 0, 255);">var</span> openAIClient = c.Services.GetRequiredService&lt;OpenAIClient&gt;();
        <span class="hljs-keyword" style="color: rgb(0, 0, 255);">var</span> modelId = context.Configuration[<span class="hljs-string" style="color: rgb(163, 21, 21);">"AI:OpenAI:Chat:ModelId"</span>] ?? <span class="hljs-string" style="color: rgb(163, 21, 21);">"gpt-4o-mini"</span>;
        <span class="hljs-keyword" style="color: rgb(0, 0, 255);">return</span> c.Use(openAIClient.AsChatClient(modelId));
    });
})</pre>



<p>This code relied on a couple of configuration values that define the OpenAI API Key and the OpenAI Chat Model. These can be added to the appsettings.json as follows.</p>



<pre class="hljs" style="display: block; overflow-x: auto; padding: 0.5em; background: rgb(255, 255, 255); color: rgb(0, 0, 0);">{
  <span class="hljs-attr" style="color: red;">"AppConfig"</span>: {
    <span class="hljs-attr" style="color: red;">"Environment"</span>: <span class="hljs-string" style="color: rgb(163, 21, 21);">"Production"</span>
  },
  <span class="hljs-attr" style="color: red;">"AI"</span>: {
    <span class="hljs-attr" style="color: red;">"OpenAI"</span>: {
      <span class="hljs-attr" style="color: red;">"Key"</span>: <span class="hljs-string" style="color: rgb(163, 21, 21);">"[your-openai-api-key]"</span>,
      <span class="hljs-attr" style="color: red;">"Chat"</span>: {
        <span class="hljs-attr" style="color: red;">"ModelId"</span>: <span class="hljs-string" style="color: rgb(163, 21, 21);">"gpt-4o-mini"</span>
      },
      <span class="hljs-attr" style="color: red;">"Embedding"</span>: {
        <span class="hljs-attr" style="color: red;">"ModelId"</span>: <span class="hljs-string" style="color: rgb(163, 21, 21);">"text-embedding-3-small"</span>
      }
    }
  }
}

</pre>



<p>Next up is to add some code to the MainModel that will call the CompleteAsync method on the IChatClient instance in order to get a chat response to the Message. The following code uses MVUX, which automatically routes the Message state into the message parameter on the GetChatResponse method.</p>



<pre class="hljs" style="display: block; overflow-x: auto; padding: 0.5em; background: rgb(255, 255, 255); color: rgb(0, 0, 0);"><span class="hljs-keyword" style="color: rgb(0, 0, 255);">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">partial</span> record MainModel
{
    <span class="hljs-keyword" style="color: rgb(0, 0, 255);">private</span> IChatClient _chat;
    <span class="hljs-function"><span class="hljs-keyword" style="color: rgb(0, 0, 255);">public</span> <span class="hljs-title" style="color: rgb(163, 21, 21);">MainModel</span>(<span class="hljs-params">
        IChatClient chat</span>)
    </span>{
        _chat = chat;
    }

    <span class="hljs-keyword" style="color: rgb(0, 0, 255);">public</span> IState&lt;<span class="hljs-keyword" style="color: rgb(0, 0, 255);">string</span>&gt; Message =&gt; State&lt;<span class="hljs-keyword" style="color: rgb(0, 0, 255);">string</span>&gt;.Value(<span class="hljs-keyword" style="color: rgb(0, 0, 255);">this</span>, () =&gt; <span class="hljs-keyword" style="color: rgb(0, 0, 255);">string</span>.Empty);
    <span class="hljs-keyword" style="color: rgb(0, 0, 255);">public</span> IState&lt;<span class="hljs-keyword" style="color: rgb(0, 0, 255);">string</span>&gt; Response =&gt; State&lt;<span class="hljs-keyword" style="color: rgb(0, 0, 255);">string</span>&gt;.Value(<span class="hljs-keyword" style="color: rgb(0, 0, 255);">this</span>, () =&gt; <span class="hljs-keyword" style="color: rgb(0, 0, 255);">string</span>.Empty);

    <span class="hljs-function"><span class="hljs-keyword" style="color: rgb(0, 0, 255);">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">async</span> Task <span class="hljs-title" style="color: rgb(163, 21, 21);">GetChatResponse</span>(<span class="hljs-params"><span class="hljs-keyword" style="color: rgb(0, 0, 255);">string</span> message</span>)
    </span>{
        <span class="hljs-keyword" style="color: rgb(0, 0, 255);">var</span> result = <span class="hljs-keyword" style="color: rgb(0, 0, 255);">await</span> _chat.CompleteAsync(message, cancellationToken: <span class="hljs-keyword" style="color: rgb(0, 0, 255);">default</span>);
        <span class="hljs-keyword" style="color: rgb(0, 0, 255);">await</span> Response.UpdateAsync(x =&gt; result.Message.Contents.LastOrDefault()?.ToString(), <span class="hljs-keyword" style="color: rgb(0, 0, 255);">default</span>);
    }
}</pre>



<p>Lastly, the XAML needs to be updated to accept the Message and output the Response.</p>



<pre class="hljs" style="display: block; overflow-x: auto; padding: 0.5em; background: rgb(255, 255, 255); color: rgb(0, 0, 0);"><span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">TextBox</span> <span class="hljs-attr" style="color: red;">Text</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"{Binding Message, Mode=TwoWay}"</span>
          <span class="hljs-attr" style="color: red;">PlaceholderText</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Enter your message:"</span> /&gt;</span>
<span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">Button</span> <span class="hljs-attr" style="color: red;">Content</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Get Response"</span>
        <span class="hljs-attr" style="color: red;">Command</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"{Binding GetChatResponse}"</span> /&gt;</span>
<span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">TextBlock</span> <span class="hljs-attr" style="color: red;">Text</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"{Binding Response}"</span> /&gt;</span></pre>



<p>And there we have it, adding AI into an application is as simple as registering services in the ConfigureService method and then adding IChatClient as a dependency to the MainModel. There are various <a href="https://devblogs.microsoft.com/dotnet/azure-ai-model-catalog-dotnet-inference-sdk/">Azure AI</a> and <a href="https://devblogs.microsoft.com/dotnet/using-github-models-and-dotnet-to-build-generative-ai-apps/">Github AI</a> services that can be added using a similar mechanism.</p>
<p>The post <a href="https://nicksnettravels.builttoroam.com/microsoft-extensions-ai/">Adding AI to a Windows and Uno Platform Application using Microsoft.Extensions.AI</a> appeared first on <a href="https://nicksnettravels.builttoroam.com">Nick&#039;s .NET Travels</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://nicksnettravels.builttoroam.com/microsoft-extensions-ai/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title>XAML Reuse with Templates in Applications for Windows and the Uno Platform</title>
		<link>https://nicksnettravels.builttoroam.com/xaml-reuse-data-templates/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=xaml-reuse-data-templates</link>
					<comments>https://nicksnettravels.builttoroam.com/xaml-reuse-data-templates/#comments</comments>
		
		<dc:creator><![CDATA[Nick]]></dc:creator>
		<pubDate>Sun, 25 Aug 2024 17:27:46 +0000</pubDate>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[DataTemplate]]></category>
		<category><![CDATA[Uno]]></category>
		<category><![CDATA[Uno Platform]]></category>
		<category><![CDATA[Windows]]></category>
		<category><![CDATA[Windows App SDK]]></category>
		<category><![CDATA[XAML]]></category>
		<guid isPermaLink="false">https://nicksnettravels.builttoroam.com/?p=3269</guid>

					<description><![CDATA[<p>XAML is often criticised for being verbose, hard to read and unnecessary as an additional language for defining the interface for an application. This feedback has lead to the creation of C# markup which works with both Windows UI / Windows App SDK and  Uno Platform applications. However, I find that the declarative nature and ... <a title="XAML Reuse with Templates in Applications for Windows and the Uno Platform" class="read-more" href="https://nicksnettravels.builttoroam.com/xaml-reuse-data-templates/" aria-label="Read more about XAML Reuse with Templates in Applications for Windows and the Uno Platform">Read more</a></p>
<p>The post <a href="https://nicksnettravels.builttoroam.com/xaml-reuse-data-templates/">XAML Reuse with Templates in Applications for Windows and the Uno Platform</a> appeared first on <a href="https://nicksnettravels.builttoroam.com">Nick&#039;s .NET Travels</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>XAML is often criticised for being verbose, hard to read and unnecessary as an additional language for defining the interface for an application. This feedback has lead to the creation of <a href="https://platform.uno/docs/articles/external/uno.extensions/doc/Learn/Markup/Overview.html">C# markup</a> which works with both Windows UI / Windows App SDK and  <a href="https://platform.uno/">Uno Platform</a> applications. However, I  find that the declarative nature and the separation from the application logic, helps ensure a strong application architecture where the interface is defined in XAML, and any associated logic is kept in the corresponding viewmodels. In order to do this, it&#8217;s important to understand the various ways XAML can be optimised and refactored for efficiency and ensure consistency by reusing, rather than redefining, blocks of XAML. In this post we&#8217;re going to look at DataTemplates.</p>



<p>In XMAL a DataTemplate is used in order to control the way that a piece of data is displayed. Typically the first place that a new XAML developers will come across is an ItemTemplate in a ListView, where a DataTemplate is used to define how each item in a list is displayed. However, there are other template properties where a DataTemplate can be used. Sticking with a ListView, the HeaderTemplate and FooterTemplate can be used to control how the Header and Footer data are displayed. For example:</p>



<pre class="hljs" style="display: block; overflow-x: auto; padding: 0.5em; background: rgb(255, 255, 255); color: rgb(0, 0, 0);"><span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">ListView</span> <span class="hljs-attr" style="color: red;">Header</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Products"</span>&gt;</span>
  <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">ListView.HeaderTemplate</span>&gt;</span>
    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">DataTemplate</span>&gt;</span>
      <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">TextBlock</span> <span class="hljs-attr" style="color: red;">Text</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"{Binding}"</span>
                  <span class="hljs-attr" style="color: red;">FontSize</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"42"</span> /&gt;</span>
    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">DataTemplate</span>&gt;</span>
  <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">ListView.HeaderTemplate</span>&gt;</span></pre>



<p>More often than not, the HeaderTemplate property isn&#8217;t used, with the XAML instead being added directly to the Header property.</p>



<pre class="hljs" style="display: block; overflow-x: auto; padding: 0.5em; background: rgb(255, 255, 255); color: rgb(0, 0, 0);"><span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">ListView</span> <span class="hljs-attr" style="color: red;">DataContext</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Products"</span>&gt;</span>
  <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">ListView.Header</span>&gt;</span>
      <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">TextBlock</span> <span class="hljs-attr" style="color: red;">Text</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"{Binding}"</span>
                  <span class="hljs-attr" style="color: red;">FontSize</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"42"</span> /&gt;</span>
  <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">ListView.Header</span>&gt;</span>
<span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">ListView</span>&gt;</span></pre>



<p>Another example of where a DataTemplate can be used is with a Button. Let&#8217;s start with the following XAML that defines a Button with a SymbolIcon inside a ViewBox.</p>



<pre class="hljs" style="display: block; overflow-x: auto; padding: 0.5em; background: rgb(255, 255, 255); color: rgb(0, 0, 0);"><span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">Button</span>
    <span class="hljs-attr" style="color: red;">Width</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"200"</span>
    <span class="hljs-attr" style="color: red;">Height</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"200"</span>&gt;</span>
    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">Viewbox</span>&gt;</span>
        <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">SymbolIcon</span>
            <span class="hljs-attr" style="color: red;">Margin</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"20"</span>
            <span class="hljs-attr" style="color: red;">Symbol</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Accept"</span> /&gt;</span>
    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">Viewbox</span>&gt;</span>
<span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">Button</span>&gt;</span></pre>



<p>This yields a simple icon button where the icon is scaled based on the size of the Button.</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2024/08/image-66cb65749a3b0.png"><img loading="lazy" decoding="async" width="300" height="240" src="https://wordpressblogimages.builttoroam.com/blogimages/2024/08/image-66cb65749a3b0-300x240.png" alt="" class="wp-image-3273" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2024/08/image-66cb65749a3b0-300x240.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2024/08/image-66cb65749a3b0.png 438w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>Now if we want to resuse this layout but don&#8217;t want to go all the way to overriding the Button Style/ControlTemplate, we can move the XAML into a DataTemplate and then set it via the ContentTemplate property.</p>



<pre class="hljs" style="display: block; overflow-x: auto; padding: 0.5em; background: rgb(255, 255, 255); color: rgb(0, 0, 0);"><span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">StackPanel</span>&gt;</span>
  <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">StackPanel.Resources</span>&gt;</span>
    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">DataTemplate</span> <span class="hljs-attr" style="color: red;">x:Key</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"IconButtonTemplate"</span>&gt;</span>
      <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">Viewbox</span>&gt;</span>
        <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">SymbolIcon</span> <span class="hljs-attr" style="color: red;">Margin</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"20"</span>
                    <span class="hljs-attr" style="color: red;">Symbol</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"{Binding}"</span> /&gt;</span>
      <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">Viewbox</span>&gt;</span>
    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">DataTemplate</span>&gt;</span>
  <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">StackPanel.Resources</span>&gt;</span>

  <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">Button</span> <span class="hljs-attr" style="color: red;">Width</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"200"</span>
          <span class="hljs-attr" style="color: red;">Height</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"200"</span>
          <span class="hljs-attr" style="color: red;">Content</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Accept"</span>
          <span class="hljs-attr" style="color: red;">ContentTemplate</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"{StaticResource IconButtonTemplate}"</span> /&gt;</span>
  <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">Button</span> <span class="hljs-attr" style="color: red;">Width</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"200"</span>
          <span class="hljs-attr" style="color: red;">Height</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"200"</span>
          <span class="hljs-attr" style="color: red;">Content</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Cancel"</span>
          <span class="hljs-attr" style="color: red;">ContentTemplate</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"{StaticResource IconButtonTemplate}"</span> /&gt;</span>
<span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">StackPanel</span>&gt;</span></pre>



<p>The Content set on the Button becomes the DataContext inside the DataTemplate, meaning that it will be set as the Symbol property via the Binding expression.</p>



<p>The last way that we&#8217;ll cover in this post is where you simply want to reuse blocks of XAML without wanting to attach any additional functionality (such as additional properties, or custom logic and behaviors). For this you can again define a DataTemplate, and use it anywhere in your application using a ContentPresenter.</p>



<pre class="hljs" style="display: block; overflow-x: auto; padding: 0.5em; background: rgb(255, 255, 255); color: rgb(0, 0, 0);"><span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">ContentPresenter</span>
    <span class="hljs-attr" style="color: red;">Content</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Accept"</span>
    <span class="hljs-attr" style="color: red;">ContentTemplate</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"{StaticResource IconButtonTemplate}"</span> /&gt;</span>
</pre>



<p>Alternatively you can use a ContentControl, which in this scenario delivers the same result. However, the ContentControl class is really designed to be the base class for custom controls, rather than being used explicitly in your application layout. The default ContentTemplate of a ContentControl uses a ContentPresenter in order to display the Content. As such, if all you&#8217;re doing is reusing XAML, using the ContentPresenter directly is a simpler approach.</p>



<p>In this post we&#8217;ve touched on using DataTemplate for reusing blocks of XAML in your application. If you need to associate logic or behaviour with the XAML you&#8217;re reusing, you&#8217;ll need to consider building a UserControl or custom control.  </p>



<p></p>



<p></p>
<p>The post <a href="https://nicksnettravels.builttoroam.com/xaml-reuse-data-templates/">XAML Reuse with Templates in Applications for Windows and the Uno Platform</a> appeared first on <a href="https://nicksnettravels.builttoroam.com">Nick&#039;s .NET Travels</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://nicksnettravels.builttoroam.com/xaml-reuse-data-templates/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title>Understanding Styles and Resources in Windows and Uno Platform Applications</title>
		<link>https://nicksnettravels.builttoroam.com/default-winui-styles/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=default-winui-styles</link>
					<comments>https://nicksnettravels.builttoroam.com/default-winui-styles/#comments</comments>
		
		<dc:creator><![CDATA[Nick]]></dc:creator>
		<pubDate>Sat, 10 Aug 2024 21:13:32 +0000</pubDate>
				<category><![CDATA[Design]]></category>
		<category><![CDATA[Development]]></category>
		<category><![CDATA[Style]]></category>
		<category><![CDATA[Uno]]></category>
		<category><![CDATA[Uno Platform]]></category>
		<category><![CDATA[Windows App SDK]]></category>
		<category><![CDATA[WinUI]]></category>
		<category><![CDATA[XAML]]></category>
		<guid isPermaLink="false">https://nicksnettravels.builttoroam.com/?p=3263</guid>

					<description><![CDATA[<p>In my previous post I looked how the Windows UI 3 Figma file components and variants map to styles and visual states in Windows UI but glosses over some of the details of how resources and in particular, Styles, are defined in Windows UI. To cover this in more detail, in this post we&#8217;re going to drill ... <a title="Understanding Styles and Resources in Windows and Uno Platform Applications" class="read-more" href="https://nicksnettravels.builttoroam.com/default-winui-styles/" aria-label="Read more about Understanding Styles and Resources in Windows and Uno Platform Applications">Read more</a></p>
<p>The post <a href="https://nicksnettravels.builttoroam.com/default-winui-styles/">Understanding Styles and Resources in Windows and Uno Platform Applications</a> appeared first on <a href="https://nicksnettravels.builttoroam.com">Nick&#039;s .NET Travels</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>In my <a href="https://nicksnettravels.builttoroam.com/figma-winui-xaml/">previous post</a> I looked how the <a href="https://www.figma.com/community/file/1159947337437047524/windows-ui-3">Windows UI 3</a> Figma file components and variants map to styles and visual states in Windows UI but glosses over some of the details of how resources and in particular, Styles, are defined in Windows UI. To cover this in more detail, in this post we&#8217;re going to drill into the default resources and styles that ship with both the Windows App Sdk and the Uno Platform. </p>



<p>The first thing to do is to locate the resources and styles that ship with the Windows App Sdk. These are conveniently located in the Microsoft.WindowsAppSdk package that can be found in your nuget packages folder (assuming you&#8217;ve created/loaded/restored a Windows App Sdk based application). Here&#8217;s the default location:</p>



<pre class="wp-block-preformatted">C:\Users\&lt;usrename>.nuget\packages\microsoft.windowsappsdk</pre>



<p>Side note &#8211; if you haven&#8217;t already checked it out, I would recommend setting up a <a href="https://learn.microsoft.com/en-us/windows/dev-drive/">Dev Drive</a>, which you can do via <a href="https://learn.microsoft.com/en-us/windows/dev-home/">Dev Home</a>. After setting up a Dev Drive, you can move your nuget packages folder and cache to your Dev Drive (see <a href="https://blog.maartenballiauw.be/post/2023/11/22/test-driving-windows-11-dev-drive-for-dotnet.html">instructions</a>).</p>



<p>Within the the Microsoft.WindowsAppSdk package folder, you need to drill into a version folder, and then further into the lib folder, and then keep going until you find the generic.xaml file, located  in the Themes folder. For example here&#8217;s the full path fo the 1.5.240627000 version of the Windows App Sdk.</p>



<pre class="wp-block-preformatted">1.5.240627000\lib\net6.0-windows10.0.18362.0\Microsoft.WinUI\Themes\generic.xaml</pre>



<p>This file is a standard XAML (ie XML) file, so you can open it in any code editor. I typically open it in VS Code as I find it easier to search and navigate the file, since it provides some rudimentary XML color coding and the ability to expand/collapse XML elements.</p>



<h2 class="wp-block-heading">ThemeResources</h2>



<p>The generic.xaml file contains nothing more than a dictionary of resources, that are included by default in a Windows App Sdk application that uses Windows UI. The file begins with a set of three ThemeDictionaries, Default (aka Dark), HighContrast and Light.</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="846" height="370" src="https://wordpressblogimages.builttoroam.com/blogimages/2024/08/image-66b79ce9bee94.png" alt="" class="wp-image-3264" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2024/08/image-66b79ce9bee94.png 846w, https://wordpressblogimages.builttoroam.com/blogimages/2024/08/image-66b79ce9bee94-300x131.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2024/08/image-66b79ce9bee94-768x336.png 768w" sizes="auto, (max-width: 846px) 100vw, 846px" /></figure>



<p>As you can imagine, based on the names of these theme dictionaries, they define resources that should be used when the host system is set to dark (ie the default theme) or light (for applications), or if the high contrast accessibility option is enabled. Note that within your application, you can override the system theme by setting the RequestedTheme on elements within your application. This can be useful if you want to provide users with the option to specify a particular theme for your application but don&#8217;t forget to give them the option to revert back to the system theme.</p>



<p>The other interesting thing to note about theme resources is that they can be overridden at any level using a technique called <a href="https://learn.microsoft.com/en-us/windows/apps/design/style/xaml-styles#lightweight-styling">light weight styling</a>. </p>



<p>If you expand any of the theme dictionaries, you&#8217;ll see that it defines low level resources such as FontFamily, Min/Max Width/Height, Opacity, Thickness, Color and a lot of Brushes. </p>



<p>Following the themedictionaries there are some othe constant values resources that are defined. It&#8217;s not expected that these will be altered based on the theme and it doesn&#8217;t seem possible to override the resources and have the updated value take effect within the built in templates and styles.</p>



<h2 class="wp-block-heading">Templates and Styles</h2>



<p>The next section of the file defined DataTemplate and Style elements that control the look and feel of the built in Windows UI elements. For any given control type, there may be more than on Style defined but there can only be one default Style. Let&#8217;s take the Button control for example. There are multiple named (explicit) styles that have a TargetType of Button (or ButtonBase): AccentButtonStyle, EllipsisButton, &#8230;, and DefaultButtonStyle. It&#8217;s important to note that just because a style has been named DefaultButtonStyle, doesn&#8217;t make it the default style for a Button. It&#8217;s the definition of an implicit (unnamed) style that determines the default style for a Button.</p>



<pre class="hljs" style="display: block; overflow-x: auto; padding: 0.5em; background: rgb(255, 255, 255); color: rgb(0, 0, 0);"><span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">Style</span> <span class="hljs-attr" style="color: red;">TargetType</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Button"</span> <span class="hljs-attr" style="color: red;">BasedOn</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"{StaticResource DefaultButtonStyle}"</span> /&gt;</span><span class="undefined"></span></pre>



<p>If we drill into the DefaultButtonStyle we can see that it starts with a number of property setters, that define the default property values set by the Style, and that can be overridden on an instance of the Button.</p>



<pre class="hljs" style="display: block; overflow-x: auto; padding: 0.5em; background: rgb(255, 255, 255); color: rgb(0, 0, 0);"><span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">Style</span> <span class="hljs-attr" style="color: red;">x:Key</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"DefaultButtonStyle"</span> <span class="hljs-attr" style="color: red;">TargetType</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Button"</span>&gt;</span><span class="xml">
    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">Setter</span> <span class="hljs-attr" style="color: red;">Property</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Background"</span> <span class="hljs-attr" style="color: red;">Value</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"{ThemeResource ButtonBackground}"</span> /&gt;</span>
    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">Setter</span> <span class="hljs-attr" style="color: red;">Property</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"BackgroundSizing"</span> <span class="hljs-attr" style="color: red;">Value</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"InnerBorderEdge"</span> /&gt;</span>
    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">Setter</span> <span class="hljs-attr" style="color: red;">Property</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Foreground"</span> <span class="hljs-attr" style="color: red;">Value</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"{ThemeResource ButtonForeground}"</span> /&gt;</span>
    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">Setter</span> <span class="hljs-attr" style="color: red;">Property</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"BorderBrush"</span> <span class="hljs-attr" style="color: red;">Value</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"{ThemeResource ButtonBorderBrush}"</span> /&gt;</span>
    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">Setter</span> <span class="hljs-attr" style="color: red;">Property</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"BorderThickness"</span> <span class="hljs-attr" style="color: red;">Value</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"{ThemeResource ButtonBorderThemeThickness}"</span> /&gt;</span>
</span></pre>



<p>Note that a lot of these properties are set to be a theme resource. This means that the property can either be updated by setting the property directly on the Button instance, or it be changed by redefining the theme resource.</p>



<p>One of the properties being set is the Template property, which defines a ControlTemplate.</p>



<pre class="hljs" style="display: block; overflow-x: auto; padding: 0.5em; background: rgb(255, 255, 255); color: rgb(0, 0, 0);"><span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">Style</span> <span class="hljs-attr" style="color: red;">x:Key</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"DefaultButtonStyle"</span> <span class="hljs-attr" style="color: red;">TargetType</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Button"</span>&gt;</span><span class="xml">
    ...
    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">Setter</span> <span class="hljs-attr" style="color: red;">Property</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Template"</span>&gt;</span>
        <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">Setter.Value</span>&gt;</span>
            <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">ControlTemplate</span> <span class="hljs-attr" style="color: red;">TargetType</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Button"</span>&gt;</span>
                <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">ContentPresenter</span> <span class="hljs-attr" style="color: red;">x:Name</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"ContentPresenter"</span> <span class="hljs-attr" style="color: red;">...</span> &gt;</span>
                    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">ContentPresenter.BackgroundTransition</span>&gt;</span>
                        <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">BrushTransition</span> <span class="hljs-attr" style="color: red;">Duration</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"0:0:0.083"</span> /&gt;</span>
                    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">ContentPresenter.BackgroundTransition</span>&gt;</span>
                    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">VisualStateManager.VisualStateGroups</span>&gt;</span>
                    ...
                    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">VisualStateManager.VisualStateGroups</span>&gt;</span>
                <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">ContentPresenter</span>&gt;</span>
            <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">ControlTemplate</span>&gt;</span>
        <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">Setter.Value</span>&gt;</span>
    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">Setter</span>&gt;</span>
</span><span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">Style</span>&gt;</span>
</pre>



<p>The Button ControlTemplate is relatively straightforward, being mostly made up of a ContentPresenter, essentially a host control for the Content defined on the Button instance.  What&#8217;s been cropped in the above XAML for brievity is that the ContentPresenter has properties such as BorderThickness, BorderBrush and Background, which means that the Button ControlTemplate doesn&#8217;t need to define a separate element to draw a border or set the background on the content.</p>



<p>The other block of XAML that has been cropped in the above ControlTemplate are the VisualStateGroups for the Button. In fact there is only one VisualStateGroup, CommonStates, that defines the main interaction states of the Button, Normal, PointerOver, Pressed and Disabled. If you&#8217;re familiar with other flavours of XAML you might be wondering where the visual state group is for the focus states of the Button. These states aren&#8217;t defined by default because by default the Button style sets the UseSystemFocusVisuals property to true, meaning that focus visuals are applied by the system. If you want to provide custom focus visuals, set the UseSystemFocusVisuals property to false, and define a new visual state group with states, Focused, Unfocused and PointerFocused.</p>



<p>The following XAML shows the Normal state (which represents the default/rest state of the Button) and the PointerOver (ie when the mouse hovers over the control) state. The PointerOver state defines both some Storyboard and a property Setter. The first Storyboard (the others have been cropped for brevity) changes the Background on the ContentPresenter to the ButtonBackgroundPointerOver theme resource.</p>



<pre class="hljs" style="display: block; overflow-x: auto; padding: 0.5em; background: rgb(255, 255, 255); color: rgb(0, 0, 0);"><span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">VisualStateManager.VisualStateGroups</span>&gt;</span>
    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">VisualStateGroup</span> <span class="hljs-attr" style="color: red;">x:Name</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"CommonStates"</span>&gt;</span>
        <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">VisualState</span> <span class="hljs-attr" style="color: red;">x:Name</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Normal"</span> /&gt;</span>
        <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">VisualState</span> <span class="hljs-attr" style="color: red;">x:Name</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"PointerOver"</span>&gt;</span>
            <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">Storyboard</span>&gt;</span>
                <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">ObjectAnimationUsingKeyFrames</span> <span class="hljs-attr" style="color: red;">Storyboard.TargetName</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"ContentPresenter"</span> <span class="hljs-attr" style="color: red;">Storyboard.TargetProperty</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Background"</span>&gt;</span>
                    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">DiscreteObjectKeyFrame</span> <span class="hljs-attr" style="color: red;">KeyTime</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"0"</span> <span class="hljs-attr" style="color: red;">Value</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"{ThemeResource ButtonBackgroundPointerOver}"</span> /&gt;</span>
                <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">ObjectAnimationUsingKeyFrames</span>&gt;</span>
                ...                
            <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">Storyboard</span>&gt;</span>
            <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">VisualState.Setters</span>&gt;</span>
                <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">Setter</span> <span class="hljs-attr" style="color: red;">Target</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"ContentPresenter.(controls:AnimatedIcon.State)"</span> <span class="hljs-attr" style="color: red;">Value</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"PointerOver"</span> /&gt;</span>
            <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">VisualState.Setters</span>&gt;</span>
        <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">VisualState</span>&gt;</span></pre>



<p>The important thing to note about how Styles are defined for controls is that it provides a way that you as a developer can override the look and feel of any of the controls. You can clone the existing Style and make any changes to either the property setters, or the ControlTemplate. You don&#8217;t need to clone the entire Style, instead you can base your new Style on the built-in Style (by setting the BasedOn attribute) and then only override the properties you want to modify.</p>



<pre class="hljs" style="display: block; overflow-x: auto; padding: 0.5em; background: rgb(255, 255, 255); color: rgb(0, 0, 0);"><span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">Style</span> <span class="hljs-attr" style="color: red;">x:Key</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"CustomButtonStyle"</span>
        <span class="hljs-attr" style="color: red;">TargetType</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Button"</span>
        <span class="hljs-attr" style="color: red;">BasedOn</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"{StaticResource DefaultButtonStyle}"</span>&gt;</span><span class="xml">
  <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">Setter</span> <span class="hljs-attr" style="color: red;">Property</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Padding"</span>
          <span class="hljs-attr" style="color: red;">Value</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"40"</span> /&gt;</span>
</span><span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">Style</span>&gt;</span></pre>



<p>In summary the take away points are that if you want to understand the default control styles for Windows UI (and Uno Platform) you can inspect the generic.xaml file. You can also see from this file the additional styles that are available for a control. You can use this information to override theme resources, to make changes to the theme of your application. Lastly you can use these styles as the basis for your custom control styles.</p>



<p></p>



<p></p>



<p></p>



<p></p>



<p></p>
<p>The post <a href="https://nicksnettravels.builttoroam.com/default-winui-styles/">Understanding Styles and Resources in Windows and Uno Platform Applications</a> appeared first on <a href="https://nicksnettravels.builttoroam.com">Nick&#039;s .NET Travels</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://nicksnettravels.builttoroam.com/default-winui-styles/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title>How Figma Component Variants map to XAML Visual States in Windows UI</title>
		<link>https://nicksnettravels.builttoroam.com/figma-winui-xaml/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=figma-winui-xaml</link>
					<comments>https://nicksnettravels.builttoroam.com/figma-winui-xaml/#comments</comments>
		
		<dc:creator><![CDATA[Nick]]></dc:creator>
		<pubDate>Sun, 04 Aug 2024 16:50:05 +0000</pubDate>
				<category><![CDATA[Design]]></category>
		<category><![CDATA[Development]]></category>
		<category><![CDATA[Figma]]></category>
		<category><![CDATA[Fluent]]></category>
		<category><![CDATA[Uno]]></category>
		<category><![CDATA[Uno Platform]]></category>
		<category><![CDATA[Windows App SDK]]></category>
		<category><![CDATA[Windows UI]]></category>
		<category><![CDATA[XAML]]></category>
		<guid isPermaLink="false">https://nicksnettravels.builttoroam.com/?p=3251</guid>

					<description><![CDATA[<p>In a previous post I covered using Figma to design and develop applications for Windows and the  Uno Platform. This was a high level post that didn&#8217;t get into either Figma files (Fluent and Material) in much detail. One thing that is common to both files is the use of components, and component variants, to ... <a title="How Figma Component Variants map to XAML Visual States in Windows UI" class="read-more" href="https://nicksnettravels.builttoroam.com/figma-winui-xaml/" aria-label="Read more about How Figma Component Variants map to XAML Visual States in Windows UI">Read more</a></p>
<p>The post <a href="https://nicksnettravels.builttoroam.com/figma-winui-xaml/">How Figma Component Variants map to XAML Visual States in Windows UI</a> appeared first on <a href="https://nicksnettravels.builttoroam.com">Nick&#039;s .NET Travels</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>In a <a href="https://nicksnettravels.builttoroam.com/design-windows-figma/">previous post</a> I covered using Figma to design and develop applications for Windows and the  <a href="https://platform.uno/">Uno Platform</a>. This was a high level post that didn&#8217;t get into either Figma files (<a href="https://www.figma.com/community/file/1159947337437047524/windows-ui-3">Fluent</a> and <a href="https://www.figma.com/community/file/1110792522046146058">Material</a>) in much detail. One thing that is common to both files is the use of components, and component variants, to not only describe different UI controls but also their visual states. In this post we&#8217;re going to look at the <a href="https://www.figma.com/community/file/1159947337437047524/windows-ui-3">Windows UI 3</a> Figma file and how it describes controls that you&#8217;d typically use when building a Windows (or Uno Platform) application in XAML (or C# Markup). This won&#8217;t be a full guide to the Figma file, so I would encourage you to read through the documentation contained in the file, specifically the Templates &amp; Tasks, and Guidance &amp; Charts pages.</p>



<h2 class="wp-block-heading">Button Component</h2>



<p>We&#8217;re going to jump to the Basic Input page and look at the Button component. At the top of the Button section of the page, there&#8217;s a brief description of the element, followed by a &#8220;Copy me&#8221; section. </p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2024/08/image.png"><img loading="lazy" decoding="async" width="300" height="197" src="https://wordpressblogimages.builttoroam.com/blogimages/2024/08/image-300x197.png" alt="" class="wp-image-3254" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2024/08/image-300x197.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2024/08/image-1024x671.png 1024w, https://wordpressblogimages.builttoroam.com/blogimages/2024/08/image-768x503.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2024/08/image.png 1108w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>If you want to make use of a control in your design, you can select the element from the &#8220;Copy me&#8221; section and use copy and paste to create a new instance on your design. Alternatively, you can find the control in the Assets window. From the Assets window, you can drag the control directly onto your design. Alternatively, if you click on the control, you&#8217;ll be presented with the list of Properties you can select before clicking the Insert Instance button.</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2024/08/image-66af91bfaf3dd.png"><img loading="lazy" decoding="async" width="253" height="300" src="https://wordpressblogimages.builttoroam.com/blogimages/2024/08/image-66af91bfaf3dd-253x300.png" alt="" class="wp-image-3255" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2024/08/image-66af91bfaf3dd-253x300.png 253w, https://wordpressblogimages.builttoroam.com/blogimages/2024/08/image-66af91bfaf3dd.png 764w" sizes="auto, (max-width: 253px) 100vw, 253px" /></a></figure>



<p>Each of the Properties correlates to a variant of the component and can either be selected prior to inserting an instance, or afterwards via the element properties window.</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2024/08/image-66af94766d4fc.png"><img loading="lazy" decoding="async" width="300" height="262" src="https://wordpressblogimages.builttoroam.com/blogimages/2024/08/image-66af94766d4fc-300x262.png" alt="" class="wp-image-3256" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2024/08/image-66af94766d4fc-300x262.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2024/08/image-66af94766d4fc.png 613w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<h2 class="wp-block-heading">Button Variants</h2>



<p>Let&#8217;s return to the Basic input page and take a look at the next section, Variants. This section defines the different overall layouts for the Button</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="623" src="https://wordpressblogimages.builttoroam.com/blogimages/2024/08/image-66af961e09199-1024x623.png" alt="" class="wp-image-3257" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2024/08/image-66af961e09199-1024x623.png 1024w, https://wordpressblogimages.builttoroam.com/blogimages/2024/08/image-66af961e09199-300x182.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2024/08/image-66af961e09199-768x467.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2024/08/image-66af961e09199.png 1115w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p><strong>Style: </strong>The Style property determines the overall Button style such as Accent, Standard (ie Default) or Subtle</p>



<p><strong>Layout:</strong> The different Layout options include Text only, Icon, Icon before and after text</p>



<p><strong>Size: </strong>The Size options are Standard and Compact</p>



<p>Note that there are a number of &#8220;Design Preview Only&#8221; badges that have been applied under the variant title. These badges indicate that there are variant options that are <strong>not</strong> included in the standard fluent styles that ship with Windows UI.</p>



<h2 class="wp-block-heading">Main Components</h2>



<p>The next section, Main Components, provides a visual guide to some of the different combinations of variants of the Button. </p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2024/08/image-66afa8b2804a8.png"><img loading="lazy" decoding="async" width="300" height="223" src="https://wordpressblogimages.builttoroam.com/blogimages/2024/08/image-66afa8b2804a8-300x223.png" alt="" class="wp-image-3258" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2024/08/image-66afa8b2804a8-300x223.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2024/08/image-66afa8b2804a8-768x571.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2024/08/image-66afa8b2804a8.png 954w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>Going down the page are the variants that relate to the layout of the Button such as Style, Layout and Size. Again, there are some variants that are marked as Design Preview Only, so these don&#8217;t correlate to actual styles that ship with Windows UI.</p>



<p>Each variant is shown in dark and light mode to illustrate how the Button would look in dark and light theme respectively. </p>



<p>Across the page are the variants that relate to the states of the Button. These are represented by two properties, Focus and State. The State property has values Rest, Hover, Pressed and Disabled. The Focus property is a boolean value.</p>



<h2 class="wp-block-heading">Variants in XAML</h2>



<p>Now that we have a bit of an understanding how components and variants are defined in Figma for the Button control, let&#8217;s look at how this relates to the way the Button control is defined in XAML. The built-in/default styles for controls that are part of Windows UI / Windows App Sdk are included in the generic.xaml file included int Microsoft.WindowsAppSdk nuget package (eg <em>c:\Users\[User]\.nuget\packages\microsoft.windowsappsdk\1.5.240627000\lib\net6.0-windows10.0.18362.0\Microsoft.WinUI\Themes\generic.xaml</em>).</p>



<p>The Style variant property correlates to the different Button styles, AccentButtonStyle (Accent) and DefaultButtonStyle (Normal). The Subtle variant included in the Figma file is marked as Design Preview Only as it doesn&#8217;t exist in the styles that ship with the Windows App Sdk.</p>



<p>If we take a look at the DefaultButtonStyle, which is also the implicit, or default, style for a Button, we can see that there are different visual states that map to the variants defined by the State property: Normal (Rest), PointerOver (Hover), Pressed and Disabled.</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2024/08/image-66afb003ccdf8.png"><img loading="lazy" decoding="async" width="282" height="300" src="https://wordpressblogimages.builttoroam.com/blogimages/2024/08/image-66afb003ccdf8-282x300.png" alt="" class="wp-image-3260" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2024/08/image-66afb003ccdf8-282x300.png 282w, https://wordpressblogimages.builttoroam.com/blogimages/2024/08/image-66afb003ccdf8.png 670w" sizes="auto, (max-width: 282px) 100vw, 282px" /></a></figure>



<p>The last variant property is Focus. This isn&#8217;t represented by visual states since Windows UI controls have an option to UseSystemFocusVisuals (see <a href="https://learn.microsoft.com/en-us/uwp/api/windows.ui.xaml.controls.control.usesystemfocusvisuals">documentation</a> for how system focus visuals work)</p>



<p>In this post we&#8217;ve seen that the Windows UI Figma file defines the visual styles of the controls that ship with Windows UI and the Windows App Sdk. We&#8217;ve seen that the component variants aligns to styles and visual states for XAML controls, and that there some variants that are only defined in the Figma file. </p>



<p> </p>
<p>The post <a href="https://nicksnettravels.builttoroam.com/figma-winui-xaml/">How Figma Component Variants map to XAML Visual States in Windows UI</a> appeared first on <a href="https://nicksnettravels.builttoroam.com">Nick&#039;s .NET Travels</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://nicksnettravels.builttoroam.com/figma-winui-xaml/feed/</wfw:commentRss>
			<slash:comments>2</slash:comments>
		
		
			</item>
		<item>
		<title>Using Web Authentication (OAuth2) to access Figma from Windows and Uno Platform Application</title>
		<link>https://nicksnettravels.builttoroam.com/figma-oauth-uno-extensions/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=figma-oauth-uno-extensions</link>
					<comments>https://nicksnettravels.builttoroam.com/figma-oauth-uno-extensions/#comments</comments>
		
		<dc:creator><![CDATA[Nick]]></dc:creator>
		<pubDate>Wed, 31 Jul 2024 03:24:41 +0000</pubDate>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[Authentication]]></category>
		<category><![CDATA[Figma]]></category>
		<category><![CDATA[OAuth]]></category>
		<category><![CDATA[Uno]]></category>
		<category><![CDATA[Uno Platform]]></category>
		<category><![CDATA[Uno.Extensions]]></category>
		<category><![CDATA[Web]]></category>
		<guid isPermaLink="false">https://nicksnettravels.builttoroam.com/?p=3245</guid>

					<description><![CDATA[<p>OAuth2 is quite a common authentication standard for web services to use. Whilst a lot of services have now updated to use OpenID Connect, there are still some, like the Figma api, that still use OAuth2. In this post we&#8217;re going to walk through using the Uno.Extensions web authentication package to simplify not only the ... <a title="Using Web Authentication (OAuth2) to access Figma from Windows and Uno Platform Application" class="read-more" href="https://nicksnettravels.builttoroam.com/figma-oauth-uno-extensions/" aria-label="Read more about Using Web Authentication (OAuth2) to access Figma from Windows and Uno Platform Application">Read more</a></p>
<p>The post <a href="https://nicksnettravels.builttoroam.com/figma-oauth-uno-extensions/">Using Web Authentication (OAuth2) to access Figma from Windows and Uno Platform Application</a> appeared first on <a href="https://nicksnettravels.builttoroam.com">Nick&#039;s .NET Travels</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>OAuth2 is quite a common authentication standard for web services to use. Whilst a lot of services have now updated to use OpenID Connect, there are still some, like the Figma api, that still use OAuth2. In this post we&#8217;re going to walk through using the Uno.Extensions web authentication package to simplify not only the authentication process but also the subsequent calling of the Figma api. </p>



<p>We&#8217;re going to start with a new application created using the Uno Platform Template Wizard from within Visual Studio. Using the recommended preset, the only change is to check the Web option for Authentication (I&#8217;ve also opted to go with Mvvm for this sample but Mvux will work just as well)</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2024/07/image-66a9a42174f76.png"><img loading="lazy" decoding="async" width="300" height="204" src="https://wordpressblogimages.builttoroam.com/blogimages/2024/07/image-66a9a42174f76-300x204.png" alt="" class="wp-image-3246" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2024/07/image-66a9a42174f76-300x204.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2024/07/image-66a9a42174f76-1024x698.png 1024w, https://wordpressblogimages.builttoroam.com/blogimages/2024/07/image-66a9a42174f76-768x523.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2024/07/image-66a9a42174f76.png 1303w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<h2 class="wp-block-heading">Settings</h2>



<p>We&#8217;ll start by updating the AppSettings to include information we&#8217;ll need. In order to authenticate with Figma you&#8217;ll need to register an application. Navigate to the <a href="https://www.figma.com/developers/apps">MyApps</a> tab in the Figma developer portal. Add an new application and make note of the generated ClientId, ClientSecret and the Callback url (to support device authentication we&#8217;ve added a protocol base callback, btrfigma://callback)</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="808" height="355" src="https://wordpressblogimages.builttoroam.com/blogimages/2024/07/image-66a9a58369f6a.png" alt="" class="wp-image-3247" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2024/07/image-66a9a58369f6a.png 808w, https://wordpressblogimages.builttoroam.com/blogimages/2024/07/image-66a9a58369f6a-300x132.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2024/07/image-66a9a58369f6a-768x337.png 768w" sizes="auto, (max-width: 808px) 100vw, 808px" /></figure>



<p> This information can be used to populate the appsettings.json (or the appsettings.development.json for debug) file. The following json can be used but make sure you update the AppConfig values according to the application you&#8217;ve registered with Figma.</p>



<pre class="hljs" style="display: block; overflow-x: auto; padding: 0.5em; background: rgb(255, 255, 255); color: rgb(0, 0, 0);">{
  <span class="hljs-attr" style="color: red;">"AppConfig"</span>: {
    <span class="hljs-attr" style="color: red;">"ClientId"</span>: <span class="hljs-string" style="color: rgb(163, 21, 21);">"{figma client id}"</span>,
    <span class="hljs-attr" style="color: red;">"ClientSecret"</span>: <span class="hljs-string" style="color: rgb(163, 21, 21);">"{figma client secret}"</span>,
    <span class="hljs-attr" style="color: red;">"RedirectUri"</span>: <span class="hljs-string" style="color: rgb(163, 21, 21);">"btrfigma://callback"</span>
  },
  <span class="hljs-attr" style="color: red;">"WebAuthentication"</span>: {
    <span class="hljs-attr" style="color: red;">"LoginStartUri"</span>: <span class="hljs-string" style="color: rgb(163, 21, 21);">"https://www.figma.com/oauth?client_id={0}&amp;redirect_uri={1}&amp;scope=files:read,file_comments:write&amp;response_type=code"</span>,
    <span class="hljs-attr" style="color: red;">"AccessTokenKey"</span>: <span class="hljs-string" style="color: rgb(163, 21, 21);">"code"</span>
  },
  <span class="hljs-attr" style="color: red;">"FigmaAuthClient"</span>: {
    <span class="hljs-attr" style="color: red;">"Url"</span>: <span class="hljs-string" style="color: rgb(163, 21, 21);">"https://www.figma.com"</span>,
    <span class="hljs-attr" style="color: red;">"UseNativeHandler"</span>: <span class="hljs-literal" style="color: rgb(163, 21, 21);">true</span>
  },
  <span class="hljs-attr" style="color: red;">"FigmaApiClient"</span>: {
    <span class="hljs-attr" style="color: red;">"Url"</span>: <span class="hljs-string" style="color: rgb(163, 21, 21);">"https://api.figma.com"</span>,
    <span class="hljs-attr" style="color: red;">"UseNativeHandler"</span>: <span class="hljs-literal" style="color: rgb(163, 21, 21);">true</span>
  }
}</pre>



<p>We&#8217;ll need to modify the AppConfig class to replace the Environment property with ClientId, ClientSecret and RedirectUri</p>



<pre class="hljs" style="display: block; overflow-x: auto; padding: 0.5em; background: rgb(255, 255, 255); color: rgb(0, 0, 0);"><span class="hljs-keyword" style="color: rgb(0, 0, 255);">public</span> record AppConfig
{
    <span class="hljs-keyword" style="color: rgb(0, 0, 255);">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">string</span>? ClientId { <span class="hljs-keyword" style="color: rgb(0, 0, 255);">get</span>; init; }
    <span class="hljs-keyword" style="color: rgb(0, 0, 255);">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">string</span>? ClientSecret { <span class="hljs-keyword" style="color: rgb(0, 0, 255);">get</span>; init; }
    <span class="hljs-keyword" style="color: rgb(0, 0, 255);">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">string</span>? RedirectUri { <span class="hljs-keyword" style="color: rgb(0, 0, 255);">get</span>; init; }
}
</pre>



<p>Note that in addition to the AppConfig section, there are three additional sections:</p>



<ul class="wp-block-list">
<li>WebAuthentication &#8211; This is used by Uno.Extensions web configuration to define the url used to start the login process. The inclusion of the redirect_uri parameter will automatically be used to determine the end of the web authentication process</li>



<li>FigmaAuthClient &#8211; The initial web authentication process will return a code to the application. This needs to be converted into access and refresh tokens by calling the token endpoint, which is part of the oauth endpoint off www.figma.com</li>



<li>FigmaApiClient &#8211; The Figma apis for retrieving information about figma files are defined on a different base uri, api.figma.com</li>
</ul>



<p>This information will be used in the subsequent sections as we complete the configuration for the application.</p>



<h2 class="wp-block-heading">Configuration</h2>



<p>There are three main additions that need to be made to the configuration of the application defined in app.xaml.cs: Registering Auth Endpoint, Registering Api Endpoint, Configuring Web Authentication. </p>



<h3 class="wp-block-heading">Registering Auth Endpoint</h3>



<p>In order to register an endpoint that can be called by the application, the first thing to do is to create an interface that defines the path and parameters for the request. The IFigmaAuthClient interface includes two methods, GetToken and GetRefreshToken. </p>



<pre class="hljs" style="display: block; overflow-x: auto; padding: 0.5em; background: rgb(255, 255, 255); color: rgb(0, 0, 0);">[Headers(<span class="hljs-string" style="color: rgb(163, 21, 21);">"Content-Type: application/json"</span>)]
<span class="hljs-keyword" style="color: rgb(0, 0, 255);">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">interface</span> <span class="hljs-title" style="color: rgb(163, 21, 21);">IFigmaAuthClient</span>
{
    [Post(<span class="hljs-string" style="color: rgb(163, 21, 21);">"/api/oauth/token?client_id={clientId}&amp;client_secret={clientSecret}&amp;redirect_uri={redirectUri}&amp;code={code}&amp;grant_type=authorization_code"</span>)]
    <span class="hljs-function">Task&lt;AuthResponse&gt; <span class="hljs-title" style="color: rgb(163, 21, 21);">GetToken</span>(<span class="hljs-params"><span class="hljs-keyword" style="color: rgb(0, 0, 255);">string</span> clientId, <span class="hljs-keyword" style="color: rgb(0, 0, 255);">string</span> clientSecret, <span class="hljs-keyword" style="color: rgb(0, 0, 255);">string</span> redirectUri, <span class="hljs-keyword" style="color: rgb(0, 0, 255);">string</span> code, CancellationToken cancellationToken = <span class="hljs-keyword" style="color: rgb(0, 0, 255);">default</span></span>)</span>;

    [Post(<span class="hljs-string" style="color: rgb(163, 21, 21);">"/api/oauth/refresh?client_id={clientId}&amp;client_secret={clientSecret}&amp;refresh_token={refreshToken}"</span>)]
    <span class="hljs-function">Task&lt;AuthResponse&gt; <span class="hljs-title" style="color: rgb(163, 21, 21);">GetRefreshToken</span>(<span class="hljs-params"><span class="hljs-keyword" style="color: rgb(0, 0, 255);">string</span> clientId, <span class="hljs-keyword" style="color: rgb(0, 0, 255);">string</span> clientSecret, <span class="hljs-keyword" style="color: rgb(0, 0, 255);">string</span> refreshToken, CancellationToken cancellationToken = <span class="hljs-keyword" style="color: rgb(0, 0, 255);">default</span></span>)</span>;
}

<span class="hljs-function"><span class="hljs-keyword" style="color: rgb(0, 0, 255);">public</span> record <span class="hljs-title" style="color: rgb(163, 21, 21);">AuthResponse</span>(<span class="hljs-params"><span class="hljs-keyword" style="color: rgb(0, 0, 255);">long</span> user_id, <span class="hljs-keyword" style="color: rgb(0, 0, 255);">string</span> access_token, <span class="hljs-keyword" style="color: rgb(0, 0, 255);">string</span> refresh_token, <span class="hljs-keyword" style="color: rgb(0, 0, 255);">long</span> expires_in</span>)</span>;
</pre>



<p>In app.xaml.cs update the <code>.UseHttp</code> method as follows:</p>



<pre class="hljs" style="display: block; overflow-x: auto; padding: 0.5em; background: rgb(255, 255, 255); color: rgb(0, 0, 0);">.UseHttp((context, services) =&gt; services
    <span class="hljs-comment" style="color: green;">// Register HttpClient</span>
<span class="hljs-meta" style="color: rgb(43, 145, 175);">#<span class="hljs-meta-keyword">if</span> DEBUG</span>
    <span class="hljs-comment" style="color: green;">// DelegatingHandler will be automatically injected into Refit Client</span>
    .AddTransient&lt;DelegatingHandler, DebugHttpHandler&gt;()
<span class="hljs-meta" style="color: rgb(43, 145, 175);">#<span class="hljs-meta-keyword">endif</span></span>
    .AddRefitClient&lt;IFigmaAuthClient&gt;(context))</pre>



<h3 class="wp-block-heading">Registering Api Endpoint</h3>



<p>The api endpoint is defined in the same way as the auth endpoint.</p>



<pre class="hljs" style="display: block; overflow-x: auto; padding: 0.5em; background: rgb(255, 255, 255); color: rgb(0, 0, 0);">[Headers(<span class="hljs-string" style="color: rgb(163, 21, 21);">"Content-Type: application/json"</span>)]
<span class="hljs-keyword" style="color: rgb(0, 0, 255);">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">interface</span> <span class="hljs-title" style="color: rgb(163, 21, 21);">IFigmaApiClient</span>
{
    [Get(<span class="hljs-string" style="color: rgb(163, 21, 21);">"/v1/me"</span>)]
    <span class="hljs-function">Task&lt;FigmaUser&gt; <span class="hljs-title" style="color: rgb(163, 21, 21);">GetMe</span>(<span class="hljs-params">CancellationToken cancellationToken = <span class="hljs-keyword" style="color: rgb(0, 0, 255);">default</span></span>)</span>;
}

<span class="hljs-keyword" style="color: rgb(0, 0, 255);">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">class</span> <span class="hljs-title" style="color: rgb(163, 21, 21);">FigmaUser</span>
{
    [JsonPropertyName(<span class="hljs-string" style="color: rgb(163, 21, 21);">"id"</span>)]
    <span class="hljs-keyword" style="color: rgb(0, 0, 255);">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">string</span> Id { <span class="hljs-keyword" style="color: rgb(0, 0, 255);">get</span>; <span class="hljs-keyword" style="color: rgb(0, 0, 255);">set</span>; }

    [JsonPropertyName(<span class="hljs-string" style="color: rgb(163, 21, 21);">"email"</span>)]
    <span class="hljs-keyword" style="color: rgb(0, 0, 255);">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">string</span> Email { <span class="hljs-keyword" style="color: rgb(0, 0, 255);">get</span>; <span class="hljs-keyword" style="color: rgb(0, 0, 255);">set</span>; }

    [JsonPropertyName(<span class="hljs-string" style="color: rgb(163, 21, 21);">"handle"</span>)]
    <span class="hljs-keyword" style="color: rgb(0, 0, 255);">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">string</span> Handle { <span class="hljs-keyword" style="color: rgb(0, 0, 255);">get</span>; <span class="hljs-keyword" style="color: rgb(0, 0, 255);">set</span>; }

    [JsonPropertyName(<span class="hljs-string" style="color: rgb(163, 21, 21);">"img_url"</span>)]
    <span class="hljs-keyword" style="color: rgb(0, 0, 255);">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">string</span> ImageUrl { <span class="hljs-keyword" style="color: rgb(0, 0, 255);">get</span>; <span class="hljs-keyword" style="color: rgb(0, 0, 255);">set</span>; }
}</pre>



<p>And the registration:</p>



<pre class="hljs" style="display: block; overflow-x: auto; padding: 0.5em; background: rgb(255, 255, 255); color: rgb(0, 0, 0);">.UseHttp((context, services) =&gt; services
    <span class="hljs-comment" style="color: green;">// Register HttpClient</span>
<span class="hljs-meta" style="color: rgb(43, 145, 175);">#<span class="hljs-meta-keyword">if</span> DEBUG</span>
    <span class="hljs-comment" style="color: green;">// DelegatingHandler will be automatically injected into Refit Client</span>
    .AddTransient&lt;DelegatingHandler, DebugHttpHandler&gt;()
<span class="hljs-meta" style="color: rgb(43, 145, 175);">#<span class="hljs-meta-keyword">endif</span></span>
    .AddRefitClient&lt;IFigmaAuthClient&gt;(context)
    .AddRefitClient&lt;IFigmaApiClient&gt;(context)
    )</pre>



<h3 class="wp-block-heading">Configuring Web Authentication</h3>



<p>The bulk of the complexity for authenticating with Figma is handled within the web authentication configuration which requires defining three different callbacks on the builder exposed by the AddWeb extension method.</p>



<pre class="hljs" style="display: block; overflow-x: auto; padding: 0.5em; background: rgb(255, 255, 255); color: rgb(0, 0, 0);">.UseAuthentication(auth =&gt;
    auth.AddWeb(name: <span class="hljs-string" style="color: rgb(163, 21, 21);">"WebAuthentication"</span>, configure: builder =&gt;
    {
        <span class="hljs-comment" style="color: green;">// Define PrepareLoginStartUri, PostLogin and Refresh callbacks     </span>
    })
)</pre>



<p>First up is the <code>PrepareLoginStartUri</code> method, which is used to add ClientId and RedirectUri to the parameterized loginUri to return the uri that will be used to launch the web authentication process.</p>



<pre class="hljs" style="display: block; overflow-x: auto; padding: 0.5em; background: rgb(255, 255, 255); color: rgb(0, 0, 0);">builder.PrepareLoginStartUri((IServiceProvider sp, ITokenCache cache, IDictionary&lt;<span class="hljs-keyword" style="color: rgb(0, 0, 255);">string</span>, <span class="hljs-keyword" style="color: rgb(0, 0, 255);">string</span>&gt;? credentials, <span class="hljs-keyword" style="color: rgb(0, 0, 255);">string</span> loginUri, CancellationToken ct) =&gt;
{
    <span class="hljs-keyword" style="color: rgb(0, 0, 255);">var</span> appConfig = sp.GetRequiredService&lt;IOptions&lt;AppConfig&gt;&gt;().Value;
    <span class="hljs-keyword" style="color: rgb(0, 0, 255);">return</span> ValueTask.FromResult(<span class="hljs-keyword" style="color: rgb(0, 0, 255);">string</span>.Format(loginUri, appConfig.ClientId, appConfig.RedirectUri));
})</pre>



<p>Next up, the PostLogin method, which converts the code returned by the web authentication process into access and refresh tokens.</p>



<pre class="hljs" style="display: block; overflow-x: auto; padding: 0.5em; background: rgb(255, 255, 255); color: rgb(0, 0, 0);">.PostLogin(<span class="hljs-keyword" style="color: rgb(0, 0, 255);">async</span> (sp, cache, credentials, tokens, ct) =&gt;
{
    <span class="hljs-keyword" style="color: rgb(0, 0, 255);">var</span> figma = sp.GetRequiredService&lt;IFigmaAuthClient&gt;();
    <span class="hljs-keyword" style="color: rgb(0, 0, 255);">var</span> appConfig = sp.GetRequiredService&lt;IOptions&lt;AppConfig&gt;&gt;().Value;
    <span class="hljs-keyword" style="color: rgb(0, 0, 255);">var</span> code = tokens[TokenCacheExtensions.AccessTokenKey];

    <span class="hljs-keyword" style="color: rgb(0, 0, 255);">var</span> authData = <span class="hljs-keyword" style="color: rgb(0, 0, 255);">await</span> figma.GetToken(appConfig.ClientId, appConfig.ClientSecret, appConfig.RedirectUri, code, ct);
    <span class="hljs-keyword" style="color: rgb(0, 0, 255);">if</span> (authData <span class="hljs-keyword" style="color: rgb(0, 0, 255);">is</span> <span class="hljs-literal" style="color: rgb(163, 21, 21);">null</span>)
    {
        <span class="hljs-keyword" style="color: rgb(0, 0, 255);">return</span> tokens;
    }
    tokens[TokenCacheExtensions.AccessTokenKey] = authData.access_token;
    tokens[TokenCacheExtensions.RefreshTokenKey] = authData.refresh_token;
    tokens[<span class="hljs-string" style="color: rgb(163, 21, 21);">"ExpiresIn"</span>] = authData.expires_in.ToString();
    tokens[<span class="hljs-string" style="color: rgb(163, 21, 21);">"UserId"</span>] = authData.user_id.ToString();
    <span class="hljs-keyword" style="color: rgb(0, 0, 255);">return</span> tokens;
})</pre>



<p>Lastly, the Refresh method, which uses the refresh token returned as part of the login process to create a new access token. This is called each time the application is launched, or when an api call fails with an authorization error, to get a new access token. If the call to Refresh method fails, the application will be automatically logged out, requiring the user to complete the web authentication process again.</p>



<pre class="hljs" style="display: block; overflow-x: auto; padding: 0.5em; background: rgb(255, 255, 255); color: rgb(0, 0, 0);">.Refresh(<span class="hljs-keyword" style="color: rgb(0, 0, 255);">async</span> (sp, cache, tokens, ct) =&gt;
{
    <span class="hljs-keyword" style="color: rgb(0, 0, 255);">try</span>
    {
        <span class="hljs-keyword" style="color: rgb(0, 0, 255);">var</span> figma = sp.GetRequiredService&lt;IFigmaAuthClient&gt;();
        <span class="hljs-keyword" style="color: rgb(0, 0, 255);">var</span> appConfig = sp.GetRequiredService&lt;IOptions&lt;AppConfig&gt;&gt;().Value;
        <span class="hljs-keyword" style="color: rgb(0, 0, 255);">var</span> refreshToken = tokens[TokenCacheExtensions.RefreshTokenKey];

        <span class="hljs-keyword" style="color: rgb(0, 0, 255);">var</span> authData = <span class="hljs-keyword" style="color: rgb(0, 0, 255);">await</span> figma.GetRefreshToken(appConfig.ClientId, appConfig.ClientSecret, refreshToken, ct);

        <span class="hljs-keyword" style="color: rgb(0, 0, 255);">if</span> (authData <span class="hljs-keyword" style="color: rgb(0, 0, 255);">is</span> <span class="hljs-literal" style="color: rgb(163, 21, 21);">null</span>)
        {
            <span class="hljs-keyword" style="color: rgb(0, 0, 255);">return</span> tokens;
        }
        tokens[TokenCacheExtensions.AccessTokenKey] = authData.access_token;
        tokens[<span class="hljs-string" style="color: rgb(163, 21, 21);">"ExpiresIn"</span>] = authData.expires_in.ToString();
        <span class="hljs-keyword" style="color: rgb(0, 0, 255);">return</span> tokens;
    }
    <span class="hljs-keyword" style="color: rgb(0, 0, 255);">catch</span>
    {
        <span class="hljs-keyword" style="color: rgb(0, 0, 255);">return</span> tokens;
    }
});</pre>



<h3 class="wp-block-heading">Callback Protocol</h3>



<p>In order for authentication to work, you need to make sure you update the <code>myprotocol</code> protocol setup when the application was created using the Uno Platform template with the protocol used in the application defined with Figma. In the case of this application we&#8217;ll replace <code>myprotocol</code> with <code>btrfigma</code> (You can simply do a find and replace all in Visual Studio to make sure you update this value for all platforms).</p>



<h2 class="wp-block-heading">Application Code</h2>



<p>Now that we have the application configured, we can make use of api endpoint within our application. The <code>MainViewModel</code> has been updated as follows:</p>



<pre class="hljs" style="display: block; overflow-x: auto; padding: 0.5em; background: rgb(255, 255, 255); color: rgb(0, 0, 0);"><span class="hljs-keyword" style="color: rgb(0, 0, 255);">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">partial</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">class</span> <span class="hljs-title" style="color: rgb(163, 21, 21);">MainViewModel</span> : <span class="hljs-title" style="color: rgb(163, 21, 21);">ObservableObject</span>
{
    <span class="hljs-keyword" style="color: rgb(0, 0, 255);">private</span> IAuthenticationService _authentication;

    <span class="hljs-keyword" style="color: rgb(0, 0, 255);">private</span> IFigmaApiClient _figma;

    [ObservableProperty]
    <span class="hljs-keyword" style="color: rgb(0, 0, 255);">private</span> FigmaUser? _user;

    <span class="hljs-function"><span class="hljs-keyword" style="color: rgb(0, 0, 255);">public</span> <span class="hljs-title" style="color: rgb(163, 21, 21);">MainViewModel</span>(<span class="hljs-params">
        IAuthenticationService authentication,
        IDispatcher dispatcher,
        INavigator navigator,
        IFigmaApiClient figma</span>)
    </span>{
        _authentication = authentication;
        _figma = figma;
        _ = LoadUserProfile(dispatcher);
    }

    <span class="hljs-function"><span class="hljs-keyword" style="color: rgb(0, 0, 255);">private</span> ValueTask <span class="hljs-title" style="color: rgb(163, 21, 21);">LoadUserProfile</span>(<span class="hljs-params">IDispatcher dispatcher</span>)
        </span>=&gt; dispatcher.ExecuteAsync(<span class="hljs-keyword" style="color: rgb(0, 0, 255);">async</span> ()=&gt; User = <span class="hljs-keyword" style="color: rgb(0, 0, 255);">await</span> _figma.GetMe());


    [RelayCommand]
    <span class="hljs-function"><span class="hljs-keyword" style="color: rgb(0, 0, 255);">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">async</span> Task <span class="hljs-title" style="color: rgb(163, 21, 21);">DoLogout</span>(<span class="hljs-params">CancellationToken token</span>)
    </span>{
        <span class="hljs-keyword" style="color: rgb(0, 0, 255);">await</span> _authentication.LogoutAsync(token);
    }
}
</pre>



<p>And the XAML for MainPage.</p>



<pre class="hljs" style="display: block; overflow-x: auto; padding: 0.5em; background: rgb(255, 255, 255); color: rgb(0, 0, 0);"><span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">Page</span> <span class="hljs-attr" style="color: red;">x:Class</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"FigmaWebSampleApp.Presentation.MainPage"</span>
      <span class="hljs-attr" style="color: red;">xmlns</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"http://schemas.microsoft.com/winfx/2006/xaml/presentation"</span>
      <span class="hljs-attr" style="color: red;">xmlns:x</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"http://schemas.microsoft.com/winfx/2006/xaml"</span>
      <span class="hljs-attr" style="color: red;">xmlns:local</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"using:FigmaWebSampleApp.Presentation"</span>
      <span class="hljs-attr" style="color: red;">xmlns:uen</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"using:Uno.Extensions.Navigation.UI"</span>
      <span class="hljs-attr" style="color: red;">xmlns:utu</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"using:Uno.Toolkit.UI"</span>
      <span class="hljs-attr" style="color: red;">xmlns:um</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"using:Uno.Material"</span>
      <span class="hljs-attr" style="color: red;">NavigationCacheMode</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Required"</span>
      <span class="hljs-attr" style="color: red;">Background</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"{ThemeResource BackgroundBrush}"</span>&gt;</span>

  <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">Grid</span> <span class="hljs-attr" style="color: red;">utu:SafeArea.Insets</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"VisibleBounds"</span>&gt;</span>
    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">Grid.RowDefinitions</span>&gt;</span>
      <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">RowDefinition</span> <span class="hljs-attr" style="color: red;">Height</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Auto"</span> /&gt;</span>
      <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">RowDefinition</span> /&gt;</span>
    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">Grid.RowDefinitions</span>&gt;</span>
    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">utu:NavigationBar</span> <span class="hljs-attr" style="color: red;">Content</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"{Binding Title}"</span> /&gt;</span>

    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">StackPanel</span> <span class="hljs-attr" style="color: red;">Grid.Row</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"1"</span>
                <span class="hljs-attr" style="color: red;">HorizontalAlignment</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Center"</span>
                <span class="hljs-attr" style="color: red;">VerticalAlignment</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Center"</span>
                <span class="hljs-attr" style="color: red;">Spacing</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"16"</span>&gt;</span>
      <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">Image</span> <span class="hljs-attr" style="color: red;">Height</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"100"</span>
             <span class="hljs-attr" style="color: red;">Width</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"100"</span>
             <span class="hljs-attr" style="color: red;">Source</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"{Binding User.ImageUrl}"</span> /&gt;</span>
      <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">TextBlock</span> <span class="hljs-attr" style="color: red;">Text</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"{Binding User.Id}"</span> /&gt;</span>
      <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">TextBlock</span> <span class="hljs-attr" style="color: red;">Text</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"{Binding User.Email}"</span> /&gt;</span>
      <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">Button</span> <span class="hljs-attr" style="color: red;">Content</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Logout"</span>
              <span class="hljs-attr" style="color: red;">Command</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"{Binding LogoutCommand}"</span> /&gt;</span>
    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">StackPanel</span>&gt;</span>
  <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">Grid</span>&gt;</span>
<span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">Page</span>&gt;</span>
</pre>



<h2 class="wp-block-heading">Summary</h2>



<p>Now we have all the pieces setup to run the application, login to Figma and return information about the current Figma user in the application.</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2024/07/image-66a9ada71f1fe.png"><img loading="lazy" decoding="async" width="300" height="276" src="https://wordpressblogimages.builttoroam.com/blogimages/2024/07/image-66a9ada71f1fe-300x276.png" alt="" class="wp-image-3249" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2024/07/image-66a9ada71f1fe-300x276.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2024/07/image-66a9ada71f1fe.png 542w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>Whilst it appears there&#8217;s a few steps to setup to get this to work, this is significantly simpler that having to create a web authentication flow from scratch and then having to interact with HttpClient to do the code to token hand off and the subsequent refreshing of tokens. Note that what&#8217;s abstracted here is that the access token is automatically passed as part of the calls to the api endpoint, with no extra code required!</p>



<p></p>
<p>The post <a href="https://nicksnettravels.builttoroam.com/figma-oauth-uno-extensions/">Using Web Authentication (OAuth2) to access Figma from Windows and Uno Platform Application</a> appeared first on <a href="https://nicksnettravels.builttoroam.com">Nick&#039;s .NET Travels</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://nicksnettravels.builttoroam.com/figma-oauth-uno-extensions/feed/</wfw:commentRss>
			<slash:comments>4</slash:comments>
		
		
			</item>
		<item>
		<title>Using Figma to Develop Windows and Uno Platform Applications</title>
		<link>https://nicksnettravels.builttoroam.com/design-windows-figma/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=design-windows-figma</link>
					<comments>https://nicksnettravels.builttoroam.com/design-windows-figma/#comments</comments>
		
		<dc:creator><![CDATA[Nick]]></dc:creator>
		<pubDate>Tue, 30 Jul 2024 02:08:50 +0000</pubDate>
				<category><![CDATA[Design]]></category>
		<category><![CDATA[Figma]]></category>
		<category><![CDATA[Uno]]></category>
		<category><![CDATA[Uno Platform]]></category>
		<category><![CDATA[Windows]]></category>
		<category><![CDATA[Windows App SDK]]></category>
		<category><![CDATA[Windows UI]]></category>
		<guid isPermaLink="false">https://nicksnettravels.builttoroam.com/?p=3239</guid>

					<description><![CDATA[<p>Designing applications for Windows and the Uno Platform can be difficult if you attempt to start from a clean slate and assume that you have to design everything from the ground up. This would require you to design even simple elements like a TextBox and a Button. After designing each element, a developer would then ... <a title="Using Figma to Develop Windows and Uno Platform Applications" class="read-more" href="https://nicksnettravels.builttoroam.com/design-windows-figma/" aria-label="Read more about Using Figma to Develop Windows and Uno Platform Applications">Read more</a></p>
<p>The post <a href="https://nicksnettravels.builttoroam.com/design-windows-figma/">Using Figma to Develop Windows and Uno Platform Applications</a> appeared first on <a href="https://nicksnettravels.builttoroam.com">Nick&#039;s .NET Travels</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>Designing applications for Windows and the <a href="https://platform.uno/">Uno Platform</a> can be difficult if you attempt to start from a clean slate and assume that you have to design everything from the ground up. This would require you to design even simple elements like a TextBox and a Button. After designing each element, a developer would then have to convert the design into XAML. Whilst this is relatively straight forward in XAML, given the support for templated, or lookless, controls, it&#8217;s still a massive undertaking before you even start designing and developing your application. In this post we&#8217;ll look at two existing design systems, Fluent and Material, and how you can use Figma to design applications using design files offered by Microsoft and Uno Platform.</p>



<h2 class="wp-block-heading">Fluent</h2>



<p>Let&#8217;s start with the Fluent design system, which is the default for Windows UI / Windows App Sdk based applications. Since the Uno Platform extends Windows UI cross platform, Fluent is also the default design for cross platform applications developed using the Uno Platform</p>



<figure class="wp-block-image size-medium"><a href="https://platform.uno/docs/articles/external/uno.themes/doc/fluent-getting-started.html"><img loading="lazy" decoding="async" width="300" height="275" src="https://wordpressblogimages.builttoroam.com/blogimages/2024/07/image-300x275.png" alt="" class="wp-image-3240" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2024/07/image-300x275.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2024/07/image.png 700w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>Microsoft has a Fluent Figma file specifically for Windows UI, <a href="https://www.figma.com/community/file/1159947337437047524/windows-ui-3">Windows UI 3</a>, which is can be used as a starting point for designers wanting to use Fluent as the basis of the Windows or Uno Platform application design.</p>



<p>Whilst there&#8217;s no explicit tooling available for exporting designs out of the Fluent Figma file, if designs stick to using the predefined components, converting the Figma design into XAML is a relatively straight forward task. One useful trick that makes it easy to determine spacing/positioning of elements is to hold down the the ALT key when an element is selected. As you then move the mouse across other elements, Figma will show lines and labels indicating the distance between the elements.</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2024/07/image-66a84967d1dc3.png"><img loading="lazy" decoding="async" width="300" height="222" src="https://wordpressblogimages.builttoroam.com/blogimages/2024/07/image-66a84967d1dc3-300x222.png" alt="" class="wp-image-3242" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2024/07/image-66a84967d1dc3-300x222.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2024/07/image-66a84967d1dc3.png 448w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<h2 class="wp-block-heading">Material</h2>



<p>For Material there are plenty of Figma design files out there but for building Windows applications the best Figma file to use is the <a href="https://www.figma.com/community/file/1110792522046146058">Material Toolkit</a> offered by the Uno Platform.</p>



<figure class="wp-block-image size-medium"><a href="https://platform.uno/docs/articles/external/uno.themes/doc/material-getting-started.html"><img loading="lazy" decoding="async" width="300" height="271" src="https://wordpressblogimages.builttoroam.com/blogimages/2024/07/image-66a83b8d137e4-300x271.png" alt="" class="wp-image-3241" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2024/07/image-66a83b8d137e4-300x271.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2024/07/image-66a83b8d137e4.png 700w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>What distinguishes the Material Toolkit from other Figma design files is that it has been specifically designed to work with Windows UI and the Uno Platform. This means that you can design your application using the Material Toolkit and export either XAML or C# Markup using the <a href="https://www.figma.com/community/plugin/1045528009520465828/uno-platform-figma-to-c-or-xaml">Uno Platform (Figma to C# or XAML) Plugin</a>.</p>



<p>Depending on which design system you want to use for your application you can pick the appropriate Figma design file to start your application. Bothe design files have been created with Windows UI in mind and as such will work for designing both Windows and Uno Platform cross platform applications.</p>
<p>The post <a href="https://nicksnettravels.builttoroam.com/design-windows-figma/">Using Figma to Develop Windows and Uno Platform Applications</a> appeared first on <a href="https://nicksnettravels.builttoroam.com">Nick&#039;s .NET Travels</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://nicksnettravels.builttoroam.com/design-windows-figma/feed/</wfw:commentRss>
			<slash:comments>2</slash:comments>
		
		
			</item>
		<item>
		<title>Add some Swagger to your Windows and Uno Platform application using Kiota and OpenAPI</title>
		<link>https://nicksnettravels.builttoroam.com/kiota-gettingstarted/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=kiota-gettingstarted</link>
					<comments>https://nicksnettravels.builttoroam.com/kiota-gettingstarted/#comments</comments>
		
		<dc:creator><![CDATA[Nick]]></dc:creator>
		<pubDate>Mon, 24 Jun 2024 01:56:28 +0000</pubDate>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[Kiota]]></category>
		<category><![CDATA[OpenAPI]]></category>
		<category><![CDATA[Swagger]]></category>
		<category><![CDATA[Uno]]></category>
		<category><![CDATA[Uno Platform]]></category>
		<category><![CDATA[WASM]]></category>
		<category><![CDATA[WebAssembly]]></category>
		<category><![CDATA[Windows]]></category>
		<category><![CDATA[Windows App SDK]]></category>
		<category><![CDATA[WinUI]]></category>
		<guid isPermaLink="false">https://nicksnettravels.builttoroam.com/?p=3233</guid>

					<description><![CDATA[<p>This post is going to walk through using the Microsoft tool, Kiota, to generate client code from a Swagger / OpenAPI definition that can be used within a Windows (WinUI/Windows App Sdk) / Uno Platform application. Ok, so let&#8217;s backup a little &#8211; firstly, Swagger / OpenAPI (see description) is used to describe service endpoints. ... <a title="Add some Swagger to your Windows and Uno Platform application using Kiota and OpenAPI" class="read-more" href="https://nicksnettravels.builttoroam.com/kiota-gettingstarted/" aria-label="Read more about Add some Swagger to your Windows and Uno Platform application using Kiota and OpenAPI">Read more</a></p>
<p>The post <a href="https://nicksnettravels.builttoroam.com/kiota-gettingstarted/">Add some Swagger to your Windows and Uno Platform application using Kiota and OpenAPI</a> appeared first on <a href="https://nicksnettravels.builttoroam.com">Nick&#039;s .NET Travels</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>This post is going to walk through using the Microsoft tool, Kiota, to generate client code from a Swagger / OpenAPI definition that can be used within a Windows (WinUI/Windows App Sdk) / <a href="https://platform.uno/dotnettravels-uno">Uno Platform</a> application. </p>



<p>Ok, so let&#8217;s backup a little &#8211; firstly, Swagger / OpenAPI (see <a href="https://en.wikipedia.org/wiki/OpenAPI_Specification">description</a>) is used to describe service endpoints. For example, let&#8217;s create a new application, KiotaSampleApp, using the Uno Platform Template Wizard by selecting the Blank preset, and then enable the Server option under Features. </p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2024/06/image.png"><img loading="lazy" decoding="async" width="300" height="232" src="https://wordpressblogimages.builttoroam.com/blogimages/2024/06/image-300x232.png" alt="" class="wp-image-3234" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2024/06/image-300x232.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2024/06/image-1024x791.png 1024w, https://wordpressblogimages.builttoroam.com/blogimages/2024/06/image-768x593.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2024/06/image.png 1043w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>This will generate both an Uno Platform application, as well as a Server project, which will contain a basic WeatherForecast service. If you run the Server project and navigate to https://localhost:5002/swagger/index.html, you&#8217;ll see the following Swagger UI that let&#8217;s you browse and interact with the WeatherForecast service.</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2024/06/image-6678cdad91755.png"><img loading="lazy" decoding="async" width="300" height="273" src="https://wordpressblogimages.builttoroam.com/blogimages/2024/06/image-6678cdad91755-300x273.png" alt="" class="wp-image-3235" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2024/06/image-6678cdad91755-300x273.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2024/06/image-6678cdad91755-768x698.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2024/06/image-6678cdad91755.png 773w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>At the top of the page, there is a link to the generated json file that defines the service endpoints, https://localhost:5002/swagger/v1/swagger.json.</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2024/06/image-6678cdd97bf56.png"><img loading="lazy" decoding="async" width="300" height="273" src="https://wordpressblogimages.builttoroam.com/blogimages/2024/06/image-6678cdd97bf56-300x273.png" alt="" class="wp-image-3236" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2024/06/image-6678cdd97bf56-300x273.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2024/06/image-6678cdd97bf56-768x698.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2024/06/image-6678cdd97bf56.png 773w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>Whilst there&#8217;s a lot of references to &#8220;Swagger&#8221;, as you can see at the top of the json document, the first property, openapi, has a value 3.0.1, indicating that the json conforms to version 3.0.1 of the OpenAPI specification. This means that it can be used by Kiota to generate client code (see <a href="https://learn.microsoft.com/en-us/openapi/kiota/">documentation</a>)</p>



<p>Before we start generating code in our Uno Platform application, we first need to add some package references. Either use the NuGet package manager to add the following packages, or run the dotnet commands to add references to the KiotaSampleApp project.</p>



<pre class="hljs" style="display: block; overflow-x: auto; padding: 0.5em; background: rgb(255, 255, 255); color: rgb(0, 0, 0);">dotnet add package Microsoft.Kiota.Abstractions
dotnet add package Microsoft.Kiota.Http.HttpClientLibrary
dotnet add package Microsoft.Kiota.Serialization.Form
dotnet add package Microsoft.Kiota.Serialization.Json
dotnet add package Microsoft.Kiota.Serialization.Text
dotnet add package Microsoft.Kiota.Serialization.Multipart</pre>



<p>Now that we have the references, we need to install and run the Kiota tool. There are various ways to install Kiota (see <a href="https://learn.microsoft.com/en-us/openapi/kiota/install">documentation</a>); for this post I went with installing Kiota as a .NET tool.</p>



<pre class="hljs" style="display: block; overflow-x: auto; padding: 0.5em; background: rgb(255, 255, 255); color: rgb(0, 0, 0);">dotnet tool install --global Microsoft.OpenApi.Kiota</pre>



<p>Once installed, you can invoke Kiota from the command line. Make sure you have the Server project running, so that Kiota can access the swagger.json file. Run the following command from within the KiotaSampleApp project directory.</p>



<pre class="hljs" style="display: block; overflow-x: auto; padding: 0.5em; background: rgb(255, 255, 255); color: rgb(0, 0, 0);">kiota generate -l CSharp -c WeatherClient -n KiotaSampleApp.Client -d https://localhost:<span class="hljs-number">5002</span>/swagger/v1/swagger.json -o ./Client</pre>



<p>The generated client files will be automatically included in the KiotaSampleApp, so all you have to do is write some code to use the WeatherClient, as follows:</p>



<pre class="hljs" style="display: block; overflow-x: auto; padding: 0.5em; background: rgb(255, 255, 255); color: rgb(0, 0, 0);"><span class="hljs-function"><span class="hljs-keyword" style="color: rgb(0, 0, 255);">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">async</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">void</span> <span class="hljs-title" style="color: rgb(163, 21, 21);">LoadWeatherClick</span>(<span class="hljs-params"><span class="hljs-keyword" style="color: rgb(0, 0, 255);">object</span> sender, RoutedEventArgs e</span>)
</span>{
    <span class="hljs-comment" style="color: green;">// API requires no authentication, so use the anonymous</span>
    <span class="hljs-comment" style="color: green;">// authentication provider</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 255);">var</span> authProvider = <span class="hljs-keyword" style="color: rgb(0, 0, 255);">new</span> AnonymousAuthenticationProvider();
    <span class="hljs-comment" style="color: green;">// Create request adapter using the HttpClient-based implementation</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 255);">var</span> adapter = <span class="hljs-keyword" style="color: rgb(0, 0, 255);">new</span> HttpClientRequestAdapter(authProvider, httpClient: <span class="hljs-keyword" style="color: rgb(0, 0, 255);">new</span> HttpClient());
    <span class="hljs-comment" style="color: green;">// Create the API client</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 255);">var</span> client = <span class="hljs-keyword" style="color: rgb(0, 0, 255);">new</span> WeatherClient(adapter);
    adapter.BaseUrl = <span class="hljs-string" style="color: rgb(163, 21, 21);">"https://localhost:5002"</span>;
    <span class="hljs-comment" style="color: green;">// GET /posts</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 255);">var</span> weather = <span class="hljs-keyword" style="color: rgb(0, 0, 255);">await</span> client.Api.Weatherforecast.GetAsync();
    Console.WriteLine(<span class="hljs-string" style="color: rgb(163, 21, 21);">$"Retrieved <span class="hljs-subst">{weather?.Count}</span> forecasts."</span>);
}</pre>



<p><strong>Important Note</strong>: When creating the HttpClientRequestAdapter, this code is creating an instance of the HttpClient. This is required to avoid an &#8220;System.PlatformNotSupportedException: Operation is not supported on this platform&#8221; error that occurs when attempting to create an instance of the SocketsHttpHandler, when running as a WebAssembly (WASM) application. It&#8217;s not required for other target platforms.</p>



<p>As you can see from this example, getting started with Kiota is relatively straight forward and means that you can easily generate code for accessing services defined by a Swagger or OpenAPI endpoint.</p>



<p></p>
<p>The post <a href="https://nicksnettravels.builttoroam.com/kiota-gettingstarted/">Add some Swagger to your Windows and Uno Platform application using Kiota and OpenAPI</a> appeared first on <a href="https://nicksnettravels.builttoroam.com">Nick&#039;s .NET Travels</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://nicksnettravels.builttoroam.com/kiota-gettingstarted/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title>What’s a Navigation Region in Windows and Uno Platform Applications?</title>
		<link>https://nicksnettravels.builttoroam.com/uno-extensions-navigators/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=uno-extensions-navigators</link>
					<comments>https://nicksnettravels.builttoroam.com/uno-extensions-navigators/#comments</comments>
		
		<dc:creator><![CDATA[Nick]]></dc:creator>
		<pubDate>Tue, 11 Jun 2024 06:25:56 +0000</pubDate>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[Navigation]]></category>
		<category><![CDATA[Uno]]></category>
		<category><![CDATA[Uno Platform]]></category>
		<category><![CDATA[Uno.Extensions]]></category>
		<guid isPermaLink="false">https://nicksnettravels.builttoroam.com/?p=3228</guid>

					<description><![CDATA[<p>In all but the simplest single page application, the layout of an application has to be dynamicaly changed in order to display information, or capture input from the user. Most application frameworks provide a variety of components to make this easy. For example in a WinUI / Windows App SDK application can use a Frame ... <a title="What&#8217;s a Navigation Region in Windows and Uno Platform Applications?" class="read-more" href="https://nicksnettravels.builttoroam.com/uno-extensions-navigators/" aria-label="Read more about What&#8217;s a Navigation Region in Windows and Uno Platform Applications?">Read more</a></p>
<p>The post <a href="https://nicksnettravels.builttoroam.com/uno-extensions-navigators/">What&#8217;s a Navigation Region in Windows and Uno Platform Applications?</a> appeared first on <a href="https://nicksnettravels.builttoroam.com">Nick&#039;s .NET Travels</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>In all but the simplest single page application, the layout of an application has to be dynamicaly changed in order to display information, or capture input from the user. Most application frameworks provide a variety of components to make this easy. For example in a WinUI / Windows App SDK application can use a Frame to navigate between pages. Alternatively, a Flyout or ContentDialog can be used to display information to the user, or perhaps a NavigationView or TabBar can be used to switch content on a single page. All of these are examples of what can collectively be categorised as navigation. In this post we&#8217;re going to dig into the concept of navigation, with particular focus on the Navigation component that&#8217;s part of Uno.Extensions and how it provides a region based abstraction for navigation in Windows and Uno Platform applications.</p>



<p>My <a href="https://nicksnettravels.builttoroam.com/navigation-startup/">previous post</a> gave a simple definition of a region as being an abstraction for any element in the application that&#8217;s capable of navigating (ie displaying) a view. The default (recommended) preset in the Uno Platform Solution Wizard uses a Frame to navigate between two pages but there are other types of regions. Regions are linked in a hierarchy that matches the hierarchy found in the visual tree within the application. As we get into discussing how routes are processed, the importance of this hierarchy will become evident. </p>



<p>The other thing to know about regions is that they have a corresponding INavigator implementation. The region itself, doesn&#8217;t include any control specific implmentation, instead it&#8217;s the corresponding INavigator that contains all the smarts to navigate with the specified control.</p>



<p>Here&#8217;s a quick list of the supported element types and the corresponding navigator:</p>



<ul class="wp-block-list">
<li><strong>Frame &#8211; FrameNavigator</strong> &#8211; Navigates forward to new pages, or back to previous pages. The FrameNavigator also responds to when the Frame navigates, which means navigation can be initialised by the Frame. For example, on mobile device, a swipe will navigate to a previous page on a Frame, without the developer writing any navigation logic.</li>



<li><strong>ContentControl &#8211; ContentControlNavigator</strong> &#8211; Navigates by creating a new instance of the view and setting it as the Content on the ContentControl. Note that if the view is a page, a Frame is injected, along with a corresponding FrameNavigator, and used to navigate to the page. This means that if the page then attempts to navigate to another page, it will automatically have a back stack, making it possible to navigate back to the original page. </li>



<li><strong>ContentDialog &#8211; ContentDialogNavigator </strong>&#8211; If the view that you&#8217;re navigating to inherits from ContentDialog, the navigation will be treated as a dialog navigation (as if you&#8217;d prefixed the navigation route with the ! prefix) and the view will be displayed as a ContentDialog. </li>



<li><strong>Flyout</strong> &#8211; <strong>FlyoutNavigator</strong> &#8211; If the view that you&#8217;re navigating to inherits from Flyout, the navigation will be treat as a dialog navigation. Alternatively, you can prefix any navigation with ! and it will be treated as a dialog navigation with the view hosted inside a Flyout.</li>



<li><strong>MessageDialog</strong> &#8211; <strong>MessageDialogNavigator</strong> &#8211; If the navigation route is a predefined MessageDialog, or you&#8217;ve used the MessageDialog navigation extension methods, a MessageDialog will be displayed. </li>



<li><strong>NavigationView &#8211; NavigationViewNavigator</strong> &#8211; A selector based navigator where the navigation route will select a menu item in the NavigationView. Selector based navigators also listen for changes on the control and will initiate a new navigation based on the selected item. </li>



<li><strong>TabBar &#8211; TabBarNavigator </strong>&#8211; A selector based navigator (similar to NavigationViewNavigator)</li>



<li><strong>Panel &#8211; PanelVisibilityNavigator</strong> &#8211; Navigates by hiding and showing children of the Panel based on the Name assigned to them. If there is no child that matches the navigation route, and a view can be determines from the route (either from a RouteMap, or via reflection) a new instance will be created and added to the Panel. Again, if the view is a Page, a Frame will be injected first, and use to navigate to the Page. Note that this Navigator is <strong>not</strong> registered for implicit use, meaning that just because you nominate a Panel as a navigation Region (by adding the <code>Region.IsAttached="true"</code> attached property to the Panel), it won&#8217;t use the PanelVisibilityNavigator. To use this Navigator, you need to also set the <code>Region.Navigator="Visibility"</code></li>



<li><strong>Popup &#8211; PopupNavigator</strong> &#8211; Navigates by hiding or showing the corresponding popup</li>



<li><strong>DrawerControl &#8211; DrawerControlNavigator &#8211; </strong>Navigaes by hiding or showing the corresponding DrawerControl.</li>
</ul>



<p>The base class, <code>Navigator</code>, is also a valid Navigator and will be used if no other Navigator can be resolved. For example if you set <code>Region.IsAttached="true"</code> on a Panel, by default the <code>Navigator</code> class will be used. When the <code>base</code> <code>Navigator</code> class is used directly, it exhibit a slightly different behavior, acting to combine, or link, nested Regions. You can think of the <code>Navigator</code> acting as a composite Navigator, meaning that any navigation request that is set to it, will be forwarded to the Navigator instances for the child Regions. </p>



<p>An example of this composite behavior can be found in the Uno Platform documentation for Uno.Extensions Navigation that shows how to use the TabBar control (<a href="https://platform.uno/docs/articles/external/uno.extensions/doc/Learn/Navigation/Advanced/HowTo-UseTabBar.html#code-example">see example</a>). Here&#8217;s a reduced snippet of the XAML.</p>



<pre class="hljs" style="display: block; overflow-x: auto; padding: 0.5em; background: rgb(255, 255, 255); color: rgb(0, 0, 0);"><span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">Page</span> <span class="hljs-attr" style="color: red;">x:Class</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"UsingTabBar.Views.MainPage"</span> <span class="hljs-attr" style="color: red;">...</span> &gt;</span>
    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">Grid</span> <span class="hljs-attr" style="color: red;">uen:Region.Attached</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"True"</span>&gt;</span>
        <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">Grid</span> <span class="hljs-attr" style="color: red;">uen:Region.Attached</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"True"</span>
              <span class="hljs-attr" style="color: red;">uen:Region.Navigator</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Visibility"</span>&gt;</span>
            <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">Grid</span> <span class="hljs-attr" style="color: red;">uen:Region.Name</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"One"</span>  <span class="hljs-attr" style="color: red;">Visibility</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Collapsed"</span>&gt;</span>
                <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">TextBlock</span> <span class="hljs-attr" style="color: red;">Text</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"One"</span> /&gt;</span>
            <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">Grid</span>&gt;</span>
            <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">Grid</span> <span class="hljs-attr" style="color: red;">uen:Region.Name</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Two"</span>  <span class="hljs-attr" style="color: red;">Visibility</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Collapsed"</span>&gt;</span>
                <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">TextBlock</span> <span class="hljs-attr" style="color: red;">Text</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Two"</span> /&gt;</span>
            <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">Grid</span>&gt;</span>
            <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">Grid</span> <span class="hljs-attr" style="color: red;">uen:Region.Name</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Three"</span> <span class="hljs-attr" style="color: red;">Visibility</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Collapsed"</span>&gt;</span>
                <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">TextBlock</span> <span class="hljs-attr" style="color: red;">Text</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Three"</span> /&gt;</span>
            <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">Grid</span>&gt;</span>
        <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">Grid</span>&gt;</span>
        <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">utu:TabBar</span>  <span class="hljs-attr" style="color: red;">uen:Region.Attached</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"True"</span>&gt;</span>
            <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">utu:TabBar.Items</span>&gt;</span>
                <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">utu:TabBarItem</span> <span class="hljs-attr" style="color: red;">uen:Region.Name</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"One"</span> /&gt;</span>
                <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">utu:TabBarItem</span> <span class="hljs-attr" style="color: red;">uen:Region.Name</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Two"</span> /&gt;</span>
                <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">utu:TabBarItem</span> <span class="hljs-attr" style="color: red;">uen:Region.Name</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Three"</span> /&gt;</span>
            <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">utu:TabBar.Items</span>&gt;</span>
        <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">utu:TabBar</span>&gt;</span>
    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">Grid</span>&gt;</span>
<span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">Page</span>&gt;</span>
</pre>



<p>The first Grid is set as a Region and will use the <code>Navigator</code>. The second Grid is set as a Region and will use the <code>PanelVisibilityNavigator</code>. The TabBar is set as a Region and will use the <code>TabBarNavigator</code>. Navigation request set to the <code>Navigator</code> will be forwarded to the other two Navigators. When the selected TabBarItem is changed, a navigation request is forwarded up to the <code>Navigator</code> which is then sent back to both child Navigators (the <code>TabBarNavigator</code> ignores the request since the correct TabBarItem is already selected).</p>



<p>In this post we&#8217;ve started to touch on the different Navigators and how they&#8217;re used within the Region based navigation system provided by Uno.Extensions. In subsequent posts we&#8217;ll look at more examples for the different Navigators. </p>
<p>The post <a href="https://nicksnettravels.builttoroam.com/uno-extensions-navigators/">What&#8217;s a Navigation Region in Windows and Uno Platform Applications?</a> appeared first on <a href="https://nicksnettravels.builttoroam.com">Nick&#039;s .NET Travels</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://nicksnettravels.builttoroam.com/uno-extensions-navigators/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title>Navigation using Regions in Windows and Uno Platform Applications</title>
		<link>https://nicksnettravels.builttoroam.com/navigation-startup/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=navigation-startup</link>
					<comments>https://nicksnettravels.builttoroam.com/navigation-startup/#comments</comments>
		
		<dc:creator><![CDATA[Nick]]></dc:creator>
		<pubDate>Thu, 30 May 2024 09:16:19 +0000</pubDate>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[Navigation]]></category>
		<category><![CDATA[Uno Platform]]></category>
		<category><![CDATA[Uno.Extensions]]></category>
		<category><![CDATA[Windows App SDK]]></category>
		<guid isPermaLink="false">https://nicksnettravels.builttoroam.com/?p=3224</guid>

					<description><![CDATA[<p>Out of the box, applications built using WinUI / Windows App Sdk or the Uno Platform have access to a wide range of controls, such as Frame, TabBar and NavigationView that can be used for navigation. However, there&#8217;s no common pattern/metaphor that makes it navigate within an application. Uno.Extensions includes Navigation which provides a consistent abstraction for ... <a title="Navigation using Regions in Windows and Uno Platform Applications" class="read-more" href="https://nicksnettravels.builttoroam.com/navigation-startup/" aria-label="Read more about Navigation using Regions in Windows and Uno Platform Applications">Read more</a></p>
<p>The post <a href="https://nicksnettravels.builttoroam.com/navigation-startup/">Navigation using Regions in Windows and Uno Platform Applications</a> appeared first on <a href="https://nicksnettravels.builttoroam.com">Nick&#039;s .NET Travels</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>Out of the box, applications built using WinUI / Windows App Sdk or the <a href="https://platform.uno/dotnettravels-uno">Uno Platform</a> have access to a wide range of controls, such as Frame, TabBar and NavigationView that can be used for navigation. However, there&#8217;s no common pattern/metaphor that makes it navigate within an application. Uno.Extensions includes Navigation which provides a consistent abstraction for navigation either in code (both codebehind and in Model/ViewModel) or XAML. In this post I&#8217;m going to start by giving a simple example of how Navigation works and then discuss the concept of Regions.</p>



<p>We&#8217;ll kick of this post by creating a new application using the Uno Platform Template Wizard. If you just want to build for Windows, you can just pick Windows from the Platforms tab in the Wizard. For the purpose of this post we&#8217;ll go with the Recommended preset, which will create a XAML based Material themed application that uses both MVUX (a Reactive pattern for state management) and region based navigation (i.e. Uno.Extensions with Navigation).</p>



<p>If we run up the generated application, clicking the button will navigate from MainPage to SecondPage.</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="982" height="446" src="https://wordpressblogimages.builttoroam.com/blogimages/2024/05/image-66582f7326ef8.png" alt="" class="wp-image-3225" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2024/05/image-66582f7326ef8.png 982w, https://wordpressblogimages.builttoroam.com/blogimages/2024/05/image-66582f7326ef8-300x136.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2024/05/image-66582f7326ef8-768x349.png 768w" sizes="auto, (max-width: 982px) 100vw, 982px" /></figure>



<p>Unlike an application that you&#8217;d get if you used the Blank App template for WinUI/Windows App SDK, if you look in App.xaml.cs you won&#8217;t see the creation of a Frame or explicit calls to Navigate to MainPage. If you look inside ShellModel you&#8217;ll see there&#8217;s a Start method that&#8217;s invoked from the constructor, which invokes the <code>NavigateViewModelAsync</code> method, specifying the MainModel.</p>



<pre class="hljs" style="display: block; overflow-x: auto; padding: 0.5em; background: rgb(255, 255, 255); color: rgb(0, 0, 0);"><span class="hljs-function"><span class="hljs-keyword" style="color: rgb(0, 0, 255);">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">async</span> Task <span class="hljs-title" style="color: rgb(163, 21, 21);">Start</span>(<span class="hljs-params"></span>)
</span>{
    <span class="hljs-keyword" style="color: rgb(0, 0, 255);">await</span> _navigator.NavigateViewModelAsync&lt;MainModel&gt;(<span class="hljs-keyword" style="color: rgb(0, 0, 255);">this</span>);
}</pre>



<p>I&#8217;m not going to go into detail right now about ViewMap and RouteMap but if you look in App.xaml.cs you&#8217;ll see there are three ViewMap instances defined that match pages and models. In this case <code>MainModel</code> is associated with <code>MainPage</code>, which is how Navigation knows to navigate to the <code>MainPage</code> from the call to <code>NavigateViewModelAsync</code>.</p>



<p>So the next question is, where&#8217;s the Frame that&#8217;s being used to navigate between <code>MainPage</code> and <code>SecondPage</code>. One of the built in capabilities of Navigation is that if you attempt to navigate to a <code>Page</code> but there&#8217;s no <code>Frame</code>, a new <code>Frame</code> will be created and used to navigate. We&#8217;ll come back to this when we look at how <code>NavigationView</code> works but in the context of a new application, a <code>Frame</code> is created and used for navigation. </p>



<p>The follow up question is how does this newly created Frame get added to the application. To answer this, let&#8217;s step through the startup sequence for the application.</p>



<ul class="wp-block-list">
<li>An instance of the App class gets created</li>



<li>The overridden App.OnLaunched method is invoked, which kicks of the initialization sequence for the application.</li>



<li>An <code>IApplicationBuilder</code> instance is create by calling CreateBuilder and then a sequence of extension methods is invoked to register services etc. Note that these extension methods are very quick to execute because they don&#8217;t do much other than to register other callbacks for when Build is invoked.</li>



<li>There are a couple of extension methods invoked on <code>MainWindow</code> to enable hot reload (in DEBUG) and to set the Window icon</li>



<li>The NavigateAsync method is called on the <code>IApplicationBuilder</code>, specifying the UIElement that should be used as the root element of the application, in this case <code>Shell</code>. </li>



<li>Inside the <code>NavigateAsync</code> method, a new instance of <code>Shell</code> will be created and set as the <code>Content</code> for the <code>Window</code> of the application. At this point the Window is activated so that the application appears and shows the progress indicator that&#8217;s part of the <code>Shell</code>.</li>



<li><code>Build</code> is invoked on the <code>IApplicationBuilder</code>, which calls <code>Build</code> on internally held <code>IHostBuilder</code> in order to create the <code>IHost</code> instance. Note that this is done after the instance of <code>Shell</code> is created to avoid any delays in displaying the application.</li>



<li>After the <code>IHost</code> instance has been created, an instance of <code>ShellModel</code> is created (as this is the first RouteMap defined for the application), which in turn calls NavigateViewModelAsync to navigate to the <code>MainModel</code>.</li>



<li>As there&#8217;s currently no Frame available, a new Frame is created and added to the <code>Content</code> property of the <code>ContentControl</code> specified by the <code>Shell</code>. In this case the ExtendedSplashScreen is returned &#8211; once all the startup logic has completed, the ExtendedSplashScreen will change states from displaying the <code>LoadingContent</code>, to displaying the <code>Content</code></li>



<li>The Navigate method on the Frame is invoked in order to navigate to the <code>MainPage</code></li>
</ul>



<p>As you can see from this sequence, there&#8217;s quite a few steps that are abstracted away through the use of Navigation, coupled with the Shell / ExtendedSplashScreen control.</p>



<p>Navigating from <code>MainPage</code> to <code>SecondPage</code> can be done a number of different ways. When the application is created from the template, the navigation is invoked by calling the <code>NavigateViewModelAsync</code> method via code in the <code>MainModel</code> (1 in the code below).</p>



<pre class="hljs" style="display: block; overflow-x: auto; padding: 0.5em; background: rgb(255, 255, 255); color: rgb(0, 0, 0);"><span class="hljs-function"><span class="hljs-keyword" style="color: rgb(0, 0, 255);">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">async</span> Task <span class="hljs-title" style="color: rgb(163, 21, 21);">GoToSecond</span>(<span class="hljs-params"></span>)
</span>{
    <span class="hljs-keyword" style="color: rgb(0, 0, 255);">var</span> name = <span class="hljs-keyword" style="color: rgb(0, 0, 255);">await</span> Name;

    <span class="hljs-comment" style="color: green;">// 1 - Navigate based on Model/ViewModel</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 255);">await</span> _navigator.NavigateViewModelAsync&lt;SecondModel&gt;(<span class="hljs-keyword" style="color: rgb(0, 0, 255);">this</span>, data: <span class="hljs-keyword" style="color: rgb(0, 0, 255);">new</span> Entity(name!));
    <span class="hljs-comment" style="color: green;">// 2 - Navigate to a view</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 255);">await</span> _navigator.NavigateViewAsync&lt;SecondPage&gt;(<span class="hljs-keyword" style="color: rgb(0, 0, 255);">this</span>, data: <span class="hljs-keyword" style="color: rgb(0, 0, 255);">new</span> Entity(name!));
    <span class="hljs-comment" style="color: green;">// 3 - Navigate based on Data</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 255);">await</span> _navigator.NavigateDataAsync(<span class="hljs-keyword" style="color: rgb(0, 0, 255);">this</span>, <span class="hljs-keyword" style="color: rgb(0, 0, 255);">new</span> Entity(name!));
}</pre>



<p>Other alternative methods are <code>NavigateViewAsync</code>, where you can specify the type of view (in this case <code>SecondPage</code>) that you want to navigate to, and <code>NavigateDataAsync</code> where you specify an data instance and Navigation works out which view to navigate to based on the registered ViewMap instances.</p>



<p>You can also invoke navigation from either the codebehind or in XAML. Here&#8217;s an example of both:</p>



<p><strong>Codebehind</strong></p>



<pre class="hljs" style="display: block; overflow-x: auto; padding: 0.5em; background: rgb(255, 255, 255); color: rgb(0, 0, 0);"><span class="hljs-function"><span class="hljs-keyword" style="color: rgb(0, 0, 255);">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">async</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">void</span> <span class="hljs-title" style="color: rgb(163, 21, 21);">NavigateSecondPageClick</span>(<span class="hljs-params"><span class="hljs-keyword" style="color: rgb(0, 0, 255);">object</span> sender, RoutedEventArgs e</span>)
</span>{
    <span class="hljs-keyword" style="color: rgb(0, 0, 255);">await</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">this</span>.Navigator().NavigateViewModelAsync&lt;SecondModel&gt;(<span class="hljs-keyword" style="color: rgb(0, 0, 255);">this</span>);
}</pre>



<p><strong>XAML</strong></p>



<pre class="hljs" style="display: block; overflow-x: auto; padding: 0.5em; background: rgb(255, 255, 255); color: rgb(0, 0, 0);"><span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">Button</span> <span class="hljs-attr" style="color: red;">Content</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Go to Second Page"</span>
        <span class="hljs-attr" style="color: red;">uen:Navigation.Request</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Second"</span> /&gt;</span></pre>



<p>As you can see from these code examples the navigation methods exist on an <code>INavigator</code> instance that is either passed into the constructor of a Model/ViewModel, or can be retrieved using the <code>Navigator()</code> extension method. You can think of an <code>INavigator</code> as being the controller for navigation for a particular Region. A Region is a logical abstraction for an element within the application responsible for navigating between views. In this case the Frame that was created during startup is a Region and there is a corresponding <code>FrameNavigator</code> instance that is used to control, and respond to, navigation on the Frame. It&#8217;s the <code>FrameNavigator</code> instance that&#8217;s injected into the <code>MainModel</code> constructor which is subsequently used to navigate to <code>SecondPage</code>.</p>



<p>In this post we&#8217;ve covered how Navigation works during application startup and discussed in brief the concept of a Region. I&#8217;ll continue this discussion in the next post where we look in more detail at other types of Regions and how they relate to each other.</p>



<p></p>



<p></p>



<p></p>



<p></p>
<p>The post <a href="https://nicksnettravels.builttoroam.com/navigation-startup/">Navigation using Regions in Windows and Uno Platform Applications</a> appeared first on <a href="https://nicksnettravels.builttoroam.com">Nick&#039;s .NET Travels</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://nicksnettravels.builttoroam.com/navigation-startup/feed/</wfw:commentRss>
			<slash:comments>2</slash:comments>
		
		
			</item>
		<item>
		<title>Using Syncfusion Controls in Uno Platform Application using MAUI Embedding.</title>
		<link>https://nicksnettravels.builttoroam.com/uno-maui-syncfusion/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=uno-maui-syncfusion</link>
					<comments>https://nicksnettravels.builttoroam.com/uno-maui-syncfusion/#comments</comments>
		
		<dc:creator><![CDATA[Nick]]></dc:creator>
		<pubDate>Mon, 13 May 2024 02:08:26 +0000</pubDate>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[.NET Maui]]></category>
		<category><![CDATA[Syncfusion]]></category>
		<category><![CDATA[Uno Platform]]></category>
		<category><![CDATA[Windows App SDK]]></category>
		<guid isPermaLink="false">https://nicksnettravels.builttoroam.com/?p=3213</guid>

					<description><![CDATA[<p>The Uno Platform supports many third party control libraries, such as Mapsui and LiveCharts, but sometimes there are components that you want to use that haven&#8217;t been adapted to work with Uno. For this, you can turn to .NET MAUI Embedding which allows for any .NET MAUI control to be hosted within an Uno Platform ... <a title="Using Syncfusion Controls in Uno Platform Application using MAUI Embedding." class="read-more" href="https://nicksnettravels.builttoroam.com/uno-maui-syncfusion/" aria-label="Read more about Using Syncfusion Controls in Uno Platform Application using MAUI Embedding.">Read more</a></p>
<p>The post <a href="https://nicksnettravels.builttoroam.com/uno-maui-syncfusion/">Using Syncfusion Controls in Uno Platform Application using MAUI Embedding.</a> appeared first on <a href="https://nicksnettravels.builttoroam.com">Nick&#039;s .NET Travels</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>The <a href="https://platform.uno/dotnettravels-uno">Uno Platform</a> supports many third party control libraries, such as <a href="https://mapsui.com/">Mapsui </a>and <a href="https://livecharts.dev/">LiveCharts</a>, but sometimes there are components that you want to use that haven&#8217;t been adapted to work with Uno. For this, you can turn to <a href="https://platform.uno/docs/articles/external/uno.extensions/doc/Learn/Maui/MauiOverview.html?tabs=single-project">.NET MAUI Embedding</a> which allows for any .NET MAUI control to be hosted within an Uno Platform application. In this post I&#8217;m going to walk through creating a new Uno Platform application with .NET MAUI Embedding to make use of the controls from Syncfusion.</p>



<p>Let&#8217;s get started with a new application. In the Uno Platform Template Wizard, I&#8217;ve selected the Blank preset and then customized if by checking the .NET MAUI Embedding option under Features.</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2024/05/image.png"><img loading="lazy" decoding="async" width="300" height="213" src="https://wordpressblogimages.builttoroam.com/blogimages/2024/05/image-300x213.png" alt="" class="wp-image-3214" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2024/05/image-300x213.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2024/05/image-1024x727.png 1024w, https://wordpressblogimages.builttoroam.com/blogimages/2024/05/image-768x545.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2024/05/image.png 1277w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>If you&#8217;ve used the wizard previously, you&#8217;ll notice that there&#8217;s one less steps as you no longer have to pick between the two presets before addiving at the customization screen. The presets are still there, they&#8217;re located in the top left corner, immediately below the name of the application you&#8217;re creating. After selecting a preset, if you start to customize the options, you&#8217;ll notice a third Custom option appears &#8211; you can switch between this option and the presets to compare, before clicking Create to complete the creation of your application.</p>



<p>The newly created application is significantly simpler with the 5.2 release of the Uno Platform where the various target platforms are now available via a single project (in the past, each target platform had its own project &#8211; this is still supported, so don&#8217;t feel you need to urgently change to the new structure!!!).</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2024/05/image-66416d222b5b1.png"><img loading="lazy" decoding="async" width="237" height="300" src="https://wordpressblogimages.builttoroam.com/blogimages/2024/05/image-66416d222b5b1-237x300.png" alt="" class="wp-image-3215" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2024/05/image-66416d222b5b1-237x300.png 237w, https://wordpressblogimages.builttoroam.com/blogimages/2024/05/image-66416d222b5b1.png 373w" sizes="auto, (max-width: 237px) 100vw, 237px" /></a></figure>



<p>Because we&#8217;re using .NET MAUI Embedding, there&#8217;s a second project, which is a .NET MAUI library. This project is where we&#8217;ll reference any .NET MAUI third party control libraries and where we can customize any .NET MAUI elements we want to add to the application. </p>



<p>To get started with Syncfusion, right-click the MauiControls library and select Manage NuGet Packages. Search for &#8220;syncfusion maui&#8221; and select the library that you want to install. In this case we&#8217;re going to be using adding a data grid, so we&#8217;ll install the Syncfusion.Maui.DataGrid package.</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2024/05/image-66416e1178790.png"><img loading="lazy" decoding="async" width="300" height="117" src="https://wordpressblogimages.builttoroam.com/blogimages/2024/05/image-66416e1178790-300x117.png" alt="" class="wp-image-3216" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2024/05/image-66416e1178790-300x117.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2024/05/image-66416e1178790-1024x399.png 1024w, https://wordpressblogimages.builttoroam.com/blogimages/2024/05/image-66416e1178790-768x299.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2024/05/image-66416e1178790.png 1266w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>After installing the package reference we can start to make use of the controls provided by Syncfusion. If you&#8217;re not familiar with the third party controls, Syncfusion provide some great getting started documentation. We&#8217;ll get started by walking through the <a href="https://help.syncfusion.com/maui/datagrid/getting-started">Get Started with .NET MAUI DataGrid (SfDataGrid)</a> documentation.</p>



<p>We&#8217;ve already completed steps 1 and 2, which is to create a new application and add a reference to Syncfusion.Maui.DataGrid. The next step is to add the namespace and an instance of the SfDataGrid control to the XAML file. In this case, you need to make sure you&#8217;re adding this to a XAML file in the MauiControls (.NET MAUI) project <strong>not</strong> the main application (Uno Platform) project. The MauiControls project already has an EmbeddedControl.xaml, so we&#8217;ve updated it to create an instance of the SfDataGrid control.</p>



<pre class="hljs" style="display: block; overflow-x: auto; padding: 0.5em; background: rgb(255, 255, 255); color: rgb(0, 0, 0);"><span class="php"><span class="hljs-meta" style="color: rgb(43, 145, 175);">&lt;?</span>xml version=<span class="hljs-string" style="color: rgb(163, 21, 21);">"1.0"</span> encoding=<span class="hljs-string" style="color: rgb(163, 21, 21);">"utf-8"</span> <span class="hljs-meta" style="color: rgb(43, 145, 175);">?&gt;</span></span>
<span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">ContentView</span> <span class="hljs-attr" style="color: red;">xmlns</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"http://schemas.microsoft.com/dotnet/2021/maui"</span>
             <span class="hljs-attr" style="color: red;">xmlns:x</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"http://schemas.microsoft.com/winfx/2009/xaml"</span>
             <span class="hljs-attr" style="color: red;">x:Class</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"SyncfusionDemoApp.MauiControls.EmbeddedControl"</span>
             <span class="hljs-attr" style="color: red;">HorizontalOptions</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Fill"</span>
             <span class="hljs-attr" style="color: red;">VerticalOptions</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Fill"</span>
             <span class="hljs-attr" style="color: red;">xmlns:syncfusion</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"clr-namespace:Syncfusion.Maui.DataGrid;assembly=Syncfusion.Maui.DataGrid"</span>&gt;</span>
  <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">syncfusion:SfDataGrid</span> /&gt;</span>
<span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">ContentView</span>&gt;</span>
</pre>



<p><strong>Note:</strong> since we&#8217;ve removed all the existing elements in the <code>EmbeddedControl</code>, it&#8217;s important to also clear up any code in the codehind file (by default there&#8217;s an event handler, which updates the text on a button). </p>



<pre class="hljs" style="display: block; overflow-x: auto; padding: 0.5em; background: rgb(255, 255, 255); color: rgb(0, 0, 0);"><span class="hljs-keyword" style="color: rgb(0, 0, 255);">namespace</span> <span class="hljs-title" style="color: rgb(163, 21, 21);">SyncfusionDemoApp.MauiControls</span>;

<span class="hljs-keyword" style="color: rgb(0, 0, 255);">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">partial</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">class</span> <span class="hljs-title" style="color: rgb(163, 21, 21);">EmbeddedControl</span> : <span class="hljs-title" style="color: rgb(163, 21, 21);">ContentView</span>
{
    <span class="hljs-function"><span class="hljs-keyword" style="color: rgb(0, 0, 255);">public</span> <span class="hljs-title" style="color: rgb(163, 21, 21);">EmbeddedControl</span>(<span class="hljs-params"></span>)
    </span>{
        InitializeComponent();
    }
}
</pre>



<p>The next step is to register the handler, which is done by calling the <code>ConfigureSyncfusionCore</code> method. Unlike in a .NET MAUI application where this is done in the <code>CreateMauiApp</code> method, in .NET MAUI Embedding, this should be done in the <code>UseMauiControls</code> method in the <code>AppBuilderExtensions</code> class.</p>



<pre class="hljs" style="display: block; overflow-x: auto; padding: 0.5em; background: rgb(255, 255, 255); color: rgb(0, 0, 0);"><span class="hljs-keyword" style="color: rgb(0, 0, 255);">using</span> Syncfusion.Maui.Core.Hosting;

<span class="hljs-keyword" style="color: rgb(0, 0, 255);">namespace</span> <span class="hljs-title" style="color: rgb(163, 21, 21);">SyncfusionDemoApp</span>;

<span class="hljs-keyword" style="color: rgb(0, 0, 255);">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">static</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">class</span> <span class="hljs-title" style="color: rgb(163, 21, 21);">AppBuilderExtensions</span>
{
    <span class="hljs-function"><span class="hljs-keyword" style="color: rgb(0, 0, 255);">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">static</span> MauiAppBuilder <span class="hljs-title" style="color: rgb(163, 21, 21);">UseMauiControls</span>(<span class="hljs-params"><span class="hljs-keyword" style="color: rgb(0, 0, 255);">this</span> MauiAppBuilder builder</span>) </span>=&gt;
        builder
            .ConfigureFonts(fonts =&gt;
            {
                fonts.AddFont(<span class="hljs-string" style="color: rgb(163, 21, 21);">"Assets/Fonts/OpenSansRegular.ttf"</span>, <span class="hljs-string" style="color: rgb(163, 21, 21);">"OpenSansRegular"</span>);
                fonts.AddFont(<span class="hljs-string" style="color: rgb(163, 21, 21);">"Assets/Fonts/OpenSansSemibold.ttf"</span>, <span class="hljs-string" style="color: rgb(163, 21, 21);">"OpenSansSemibold"</span>);
            })
            .ConfigureSyncfusionCore();
}
</pre>



<p>In order for the SfDataGrid to show any data, it needs to be bound to some data. There is an example provided in the Syncfusion docs. We&#8217;ll add the <code>OrderInfo</code> and <code>OrderInfoRepository</code> to the MauiControls project (both added to the <code>Models</code> namespace).</p>



<figure class="wp-block-image size-full"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2024/05/image-664170d8a3538.png"><img loading="lazy" decoding="async" width="248" height="173" src="https://wordpressblogimages.builttoroam.com/blogimages/2024/05/image-664170d8a3538.png" alt="" class="wp-image-3217"/></a></figure>



<p>We can create an instance of the <code>OrderInfoRepository</code> and assign it as the <code>BindingContext</code> as part of the XAML for defining the SfDataGrid. The following XAML was taken from the Syncfusion documentataion.</p>



<pre class="hljs" style="display: block; overflow-x: auto; padding: 0.5em; background: rgb(255, 255, 255); color: rgb(0, 0, 0);"><span class="php"><span class="hljs-meta" style="color: rgb(43, 145, 175);">&lt;?</span>xml version=<span class="hljs-string" style="color: rgb(163, 21, 21);">"1.0"</span> encoding=<span class="hljs-string" style="color: rgb(163, 21, 21);">"utf-8"</span> <span class="hljs-meta" style="color: rgb(43, 145, 175);">?&gt;</span></span>
<span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">ContentView</span> <span class="hljs-attr" style="color: red;">xmlns</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"http://schemas.microsoft.com/dotnet/2021/maui"</span>
             <span class="hljs-attr" style="color: red;">xmlns:x</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"http://schemas.microsoft.com/winfx/2009/xaml"</span>
             <span class="hljs-attr" style="color: red;">x:Class</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"SyncfusionDemoApp.MauiControls.EmbeddedControl"</span>
             <span class="hljs-attr" style="color: red;">HorizontalOptions</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Fill"</span>
             <span class="hljs-attr" style="color: red;">VerticalOptions</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Fill"</span>
             <span class="hljs-attr" style="color: red;">xmlns:local</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"clr-namespace:SyncfusionDemoApp.Models"</span>
             <span class="hljs-attr" style="color: red;">xmlns:syncfusion</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"clr-namespace:Syncfusion.Maui.DataGrid;assembly=Syncfusion.Maui.DataGrid"</span>&gt;</span>
  <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">syncfusion:SfDataGrid</span> <span class="hljs-attr" style="color: red;">x:Name</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"dataGrid"</span>
                         <span class="hljs-attr" style="color: red;">ItemsSource</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"{Binding OrderInfoCollection}"</span>&gt;</span>

    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">syncfusion:SfDataGrid.BindingContext</span>&gt;</span>
      <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">local:OrderInfoRepository</span> <span class="hljs-attr" style="color: red;">x:Name</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"viewModel"</span> /&gt;</span>
    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">syncfusion:SfDataGrid.BindingContext</span>&gt;</span>

    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">syncfusion:SfDataGrid.Columns</span>&gt;</span>
      <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">syncfusion:DataGridNumericColumn</span> <span class="hljs-attr" style="color: red;">HeaderText</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Order ID"</span>
                                        <span class="hljs-attr" style="color: red;">Format</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"0"</span>
                                        <span class="hljs-attr" style="color: red;">MappingName</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"OrderID"</span>
                                        <span class="hljs-attr" style="color: red;">Width</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"150"</span> /&gt;</span>
      <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">syncfusion:DataGridTextColumn</span>  <span class="hljs-attr" style="color: red;">HeaderText</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Customer ID"</span>
                                      <span class="hljs-attr" style="color: red;">MappingName</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"CustomerID"</span>
                                      <span class="hljs-attr" style="color: red;">Width</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"150"</span> /&gt;</span>
      <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">syncfusion:DataGridTextColumn</span>  <span class="hljs-attr" style="color: red;">HeaderText</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Ship Country"</span>
                                      <span class="hljs-attr" style="color: red;">MappingName</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"ShipCountry"</span>
                                      <span class="hljs-attr" style="color: red;">Width</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"150"</span> /&gt;</span>
    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">syncfusion:SfDataGrid.Columns</span>&gt;</span>
  <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">syncfusion:SfDataGrid</span>&gt;</span>
<span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">ContentView</span>&gt;</span>
</pre>



<p>Some minor changes to note:</p>



<ul class="wp-block-list">
<li>The SfDataGrid is added directly to the ContentView, whereas in the Syncfusion docs it&#8217;s added to the Control property on the ContentPage</li>



<li>The BindingContext is set directly on the SfDataGrid, whereas in the Syncfusion docus it&#8217;s added as the BindingCotnext on the ContentPage</li>



<li>The <code>local</code> namespace was added to the ContentView in order to access the classes in the Models namespace.</li>
</ul>



<p>At this point you&#8217;ve done everything required to embed a Syncfusion DataGrid into your application. Unfortunately, there&#8217;s a known issue with the Windows App Sdk where you may see and error &#8220;<em>The parameter is incorrect. This element does not have a XamlRoot. Either set the XamlRoot property or add the element to a tree.</em>&#8220;</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2024/05/image-6641734f35a3a.png"><img loading="lazy" decoding="async" width="300" height="48" src="https://wordpressblogimages.builttoroam.com/blogimages/2024/05/image-6641734f35a3a-300x48.png" alt="" class="wp-image-3218" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2024/05/image-6641734f35a3a-300x48.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2024/05/image-6641734f35a3a-1024x165.png 1024w, https://wordpressblogimages.builttoroam.com/blogimages/2024/05/image-6641734f35a3a-768x124.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2024/05/image-6641734f35a3a.png 1410w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>This error is a result of the trial license key notification that Syncfusion displays if you haven&#8217;t provided a valid license key. There are two work arounds:</p>



<ul class="wp-block-list">
<li><strong>Provide a License Ke</strong>y</li>
</ul>



<pre class="hljs" style="display: block; overflow-x: auto; padding: 0.5em; background: rgb(255, 255, 255); color: rgb(0, 0, 0);"><span class="hljs-keyword" style="color: rgb(0, 0, 255);">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">static</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">class</span> <span class="hljs-title" style="color: rgb(163, 21, 21);">AppBuilderExtensions</span>
{
    <span class="hljs-function"><span class="hljs-keyword" style="color: rgb(0, 0, 255);">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">static</span> MauiAppBuilder <span class="hljs-title" style="color: rgb(163, 21, 21);">UseMauiControls</span>(<span class="hljs-params"><span class="hljs-keyword" style="color: rgb(0, 0, 255);">this</span> MauiAppBuilder builder</span>)
    </span>{
        SyncfusionLicenseProvider.RegisterLicense(<span class="hljs-string" style="color: rgb(163, 21, 21);">"---mylicensekey---"</span>);
        <span class="hljs-keyword" style="color: rgb(0, 0, 255);">return</span> builder
            .ConfigureFonts(fonts =&gt;
            {
                fonts.AddFont(<span class="hljs-string" style="color: rgb(163, 21, 21);">"Assets/Fonts/OpenSansRegular.ttf"</span>, <span class="hljs-string" style="color: rgb(163, 21, 21);">"OpenSansRegular"</span>);
                fonts.AddFont(<span class="hljs-string" style="color: rgb(163, 21, 21);">"Assets/Fonts/OpenSansSemibold.ttf"</span>, <span class="hljs-string" style="color: rgb(163, 21, 21);">"OpenSansSemibold"</span>);
            })
            .ConfigureSyncfusionCore();
    }
}</pre>



<ul class="wp-block-list">
<li><strong>Set the Source property on the MauiHost in Loaded event</strong></li>
</ul>



<p>Remove the <code>Source</code> property from the <code>MauiHost</code> element in the <code>MainPage</code> XAML, and attach an event handler to the <code>Loaded</code> event on the <code>MauiHost</code>.</p>



<pre class="hljs" style="display: block; overflow-x: auto; padding: 0.5em; background: rgb(255, 255, 255); color: rgb(0, 0, 0);"><span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">Page</span> <span class="hljs-attr" style="color: red;">x:Class</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"SyncfusionDemoApp.MainPage"</span>
      <span class="hljs-attr" style="color: red;">xmlns</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"http://schemas.microsoft.com/winfx/2006/xaml/presentation"</span>
      <span class="hljs-attr" style="color: red;">xmlns:x</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"http://schemas.microsoft.com/winfx/2006/xaml"</span>
      <span class="hljs-attr" style="color: red;">xmlns:local</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"using:SyncfusionDemoApp"</span>
      <span class="hljs-attr" style="color: red;">xmlns:d</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"http://schemas.microsoft.com/expression/blend/2008"</span>
      <span class="hljs-attr" style="color: red;">xmlns:mc</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"http://schemas.openxmlformats.org/markup-compatibility/2006"</span>
      <span class="hljs-attr" style="color: red;">xmlns:maui</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"http://schemas.microsoft.com/winfx/2006/xaml/presentation"</span>
      <span class="hljs-attr" style="color: red;">xmlns:not_maui</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"http://notmaui"</span>
      <span class="hljs-attr" style="color: red;">mc:Ignorable</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"d not_maui"</span>
      <span class="hljs-attr" style="color: red;">xmlns:controls</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"using:SyncfusionDemoApp.MauiControls"</span>
      <span class="hljs-attr" style="color: red;">Background</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"{ThemeResource ApplicationPageBackgroundThemeBrush}"</span>&gt;</span>
  <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">StackPanel</span> <span class="hljs-attr" style="color: red;">HorizontalAlignment</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Center"</span>
              <span class="hljs-attr" style="color: red;">VerticalAlignment</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Center"</span>&gt;</span>
    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">TextBlock</span> <span class="hljs-attr" style="color: red;">AutomationProperties.AutomationId</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"HelloTextBlock"</span>
               <span class="hljs-attr" style="color: red;">Text</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Hello Uno Platform"</span>
               <span class="hljs-attr" style="color: red;">HorizontalAlignment</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Center"</span> /&gt;</span>
    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">maui:Grid</span>&gt;</span>
      <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">embed:MauiHost</span> <span class="hljs-attr" style="color: red;">x:Name</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"MauiHostElement"</span>
                      <span class="hljs-attr" style="color: red;">xmlns:embed</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"using:Uno.Extensions.Maui"</span>
                      <span class="hljs-attr" style="color: red;">Loaded</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"MauiHostElementLoaded"</span> /&gt;</span>
    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">maui:Grid</span>&gt;</span>
    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">not_maui:Grid</span>&gt;</span>
      <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">TextBlock</span> <span class="hljs-attr" style="color: red;">AutomationProperties.AutomationId</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"NotMauiTextBlock"</span>
                 <span class="hljs-attr" style="color: red;">Text</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Alternative content for Non-Maui targets"</span>
                 <span class="hljs-attr" style="color: red;">HorizontalAlignment</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Center"</span> /&gt;</span>
    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">not_maui:Grid</span>&gt;</span>
  <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">StackPanel</span>&gt;</span>
<span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">Page</span>&gt;</span>
</pre>



<p>In the codebehind, set the Source property on the MauiHost</p>



<pre class="hljs" style="display: block; overflow-x: auto; padding: 0.5em; background: rgb(255, 255, 255); color: rgb(0, 0, 0);"><span class="hljs-keyword" style="color: rgb(0, 0, 255);">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">sealed</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">partial</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">class</span> <span class="hljs-title" style="color: rgb(163, 21, 21);">MainPage</span> : <span class="hljs-title" style="color: rgb(163, 21, 21);">Page</span>
{
    <span class="hljs-function"><span class="hljs-keyword" style="color: rgb(0, 0, 255);">public</span> <span class="hljs-title" style="color: rgb(163, 21, 21);">MainPage</span>(<span class="hljs-params"></span>)
    </span>{
        <span class="hljs-keyword" style="color: rgb(0, 0, 255);">this</span>.InitializeComponent();
    }

    <span class="hljs-function"><span class="hljs-keyword" style="color: rgb(0, 0, 255);">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">void</span> <span class="hljs-title" style="color: rgb(163, 21, 21);">MauiHostElementLoaded</span>(<span class="hljs-params"><span class="hljs-keyword" style="color: rgb(0, 0, 255);">object</span> sender, RoutedEventArgs e</span>)
    </span>{
        <span class="hljs-keyword" style="color: rgb(0, 0, 255);">if</span> (sender <span class="hljs-keyword" style="color: rgb(0, 0, 255);">is</span> MauiHost mauiHost)
        {
            mauiHost.Source = <span class="hljs-keyword" style="color: rgb(0, 0, 255);">typeof</span>(EmbeddedControl);
        }
    }
}</pre>



<p>Now you can run the application and you should see the Syncfusion License dialog appear.</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2024/05/image-6641747bd69e6.png"><img loading="lazy" decoding="async" width="300" height="218" src="https://wordpressblogimages.builttoroam.com/blogimages/2024/05/image-6641747bd69e6-300x218.png" alt="" class="wp-image-3219" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2024/05/image-6641747bd69e6-300x218.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2024/05/image-6641747bd69e6-768x559.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2024/05/image-6641747bd69e6.png 805w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>Click OK to proceed to the application where the SfDataGrid will appear.</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2024/05/image-66417497c3760.png"><img loading="lazy" decoding="async" width="300" height="187" src="https://wordpressblogimages.builttoroam.com/blogimages/2024/05/image-66417497c3760-300x187.png" alt="" class="wp-image-3221" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2024/05/image-66417497c3760-300x187.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2024/05/image-66417497c3760.png 690w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>In this post we&#8217;ve walked through adding a Syncfusion SfDataGrid to your application. This process is the same for any of the Syncfusion Maui controls &#8211; most have similar getting started guides that walk you through creating a simple example with data so that you can see it in action. For other component vendors that have .NET MAUI controls, the process is similiar: add package reference; initialise the library in the <code>UseMauiControls</code> method and add XAML/C# to create and populate the control in the EmbeddedControl XAML file.</p>



<p></p>
<p>The post <a href="https://nicksnettravels.builttoroam.com/uno-maui-syncfusion/">Using Syncfusion Controls in Uno Platform Application using MAUI Embedding.</a> appeared first on <a href="https://nicksnettravels.builttoroam.com">Nick&#039;s .NET Travels</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://nicksnettravels.builttoroam.com/uno-maui-syncfusion/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title>Uno Platform 5.2 Released – One Project To Rule Them All</title>
		<link>https://nicksnettravels.builttoroam.com/uno-platform-5-2-released-one-project-to-rule-them-all/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=uno-platform-5-2-released-one-project-to-rule-them-all</link>
					<comments>https://nicksnettravels.builttoroam.com/uno-platform-5-2-released-one-project-to-rule-them-all/#comments</comments>
		
		<dc:creator><![CDATA[Nick]]></dc:creator>
		<pubDate>Tue, 23 Apr 2024 03:55:49 +0000</pubDate>
				<category><![CDATA[Announcements]]></category>
		<category><![CDATA[Android]]></category>
		<category><![CDATA[iOS]]></category>
		<category><![CDATA[MacCatalyst]]></category>
		<category><![CDATA[MacOS]]></category>
		<category><![CDATA[Single Project]]></category>
		<category><![CDATA[Uno Platform]]></category>
		<category><![CDATA[WASM]]></category>
		<category><![CDATA[WebAssembly]]></category>
		<category><![CDATA[Windows]]></category>
		<guid isPermaLink="false">https://nicksnettravels.builttoroam.com/?p=3206</guid>

					<description><![CDATA[<p>This has been a work in progress over the last couple of releases in order to deliver a better developer experience for the Uno Platform. The 5.1 release introduced the Uno.Sdk which allowed for better integration with Visual Studio &#8211; no more pesky &#8220;reload project&#8221; warnings appearing. With the 5.2 release the Uno Platform goes ... <a title="Uno Platform 5.2 Released &#8211; One Project To Rule Them All" class="read-more" href="https://nicksnettravels.builttoroam.com/uno-platform-5-2-released-one-project-to-rule-them-all/" aria-label="Read more about Uno Platform 5.2 Released &#8211; One Project To Rule Them All">Read more</a></p>
<p>The post <a href="https://nicksnettravels.builttoroam.com/uno-platform-5-2-released-one-project-to-rule-them-all/">Uno Platform 5.2 Released &#8211; One Project To Rule Them All</a> appeared first on <a href="https://nicksnettravels.builttoroam.com">Nick&#039;s .NET Travels</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>This has been a work in progress over the last couple of releases in order to deliver a better developer experience for the Uno Platform. The 5.1 release introduced the Uno.Sdk which allowed for better integration with Visual Studio &#8211; no more pesky &#8220;reload project&#8221; warnings appearing. With the 5.2 release the Uno Platform goes next level with the consolidation of all those target platform projects into a single project. That&#8217;s right, you get to build for Desktop (Windows, MacOS, Linux), Mobile (iOS, Android, MacCatalyst) and Web (WebAssembly) all from a single project. In this post we&#8217;ll take a quick look at the new getting started experience but check out the <a href="https://platform.uno/blog/the-first-and-only-true-single-project-for-mobile-web-desktop-and-embedded-in-net/">announcement post </a>for other great features in the 5.2 release.</p>



<p>One of the pieces of feedback that we received regarding the wizard was that developers were presented with two options, &#8220;Blank&#8221; and &#8220;Recommended,&#8221; and it wasn&#8217;t clear that these were simply presets for the various options in the Uno Platform new application template. For anyone who&#8217;s looked at the <code>unoapp</code> template that&#8217;s included in the dotnet new template (<a href="https://www.nuget.org/packages/Uno.Templates/5.2.27">Install from NuGet</a>) you&#8217;ll know that there are a lot of options, so the aim was to provide starting points that make it easier for developers to get started. The new experience combines the two main pages of the application into a single page.</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2024/04/image-66272e27ad6be.png"><img loading="lazy" decoding="async" width="300" height="197" src="https://wordpressblogimages.builttoroam.com/blogimages/2024/04/image-66272e27ad6be-300x197.png" alt="" class="wp-image-3207" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2024/04/image-66272e27ad6be-300x197.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2024/04/image-66272e27ad6be-1024x672.png 1024w, https://wordpressblogimages.builttoroam.com/blogimages/2024/04/image-66272e27ad6be-768x504.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2024/04/image-66272e27ad6be.png 1230w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>At the top of the left column you&#8217;ll see a new &#8220;Presets&#8221; selection which allows you to toggle between the Blank and Recommended options. As you switch between them, the selections in the main area, and the Summary, are updated, so you can see what&#8217;s included in each. Of course, you can still decide to customise the options, at which point you&#8217;ll see a third option appear, &#8220;Custom&#8221;.</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2024/04/image-66272ea8e184a.png"><img loading="lazy" decoding="async" width="300" height="197" src="https://wordpressblogimages.builttoroam.com/blogimages/2024/04/image-66272ea8e184a-300x197.png" alt="" class="wp-image-3208" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2024/04/image-66272ea8e184a-300x197.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2024/04/image-66272ea8e184a-1024x672.png 1024w, https://wordpressblogimages.builttoroam.com/blogimages/2024/04/image-66272ea8e184a-768x504.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2024/04/image-66272ea8e184a.png 1230w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>This allows you to easily compare what you&#8217;ve selected with either the Blank or Recommended options by switching between them. If you want to reset your Custom selection, simply click on Blank or Recommended and then start changing the options; the wizard will treat this as your new Custom configuration.</p>



<p>Once you&#8217;re done with making your selection, hit the Create button and a new solution will be created for you. The following was created using the Recommended option, so there are a few folders illustrating how files can be arrange but the important thing is that it&#8217;s a single project.</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2024/04/image-6627307f40444.png"><img loading="lazy" decoding="async" width="283" height="300" src="https://wordpressblogimages.builttoroam.com/blogimages/2024/04/image-6627307f40444-283x300.png" alt="" class="wp-image-3209" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2024/04/image-6627307f40444-283x300.png 283w, https://wordpressblogimages.builttoroam.com/blogimages/2024/04/image-6627307f40444.png 414w" sizes="auto, (max-width: 283px) 100vw, 283px" /></a></figure>



<p>To pick which target you want to debug, click the down arrow next to the run button to see the list of startup targets</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2024/04/image-662730e242036.png"><img loading="lazy" decoding="async" width="300" height="186" src="https://wordpressblogimages.builttoroam.com/blogimages/2024/04/image-662730e242036-300x186.png" alt="" class="wp-image-3210" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2024/04/image-662730e242036-300x186.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2024/04/image-662730e242036.png 540w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>There&#8217;s plenty more to explore in the 5.2 release, so grab the Visual Studio <a href="https://marketplace.visualstudio.com/items?itemName=unoplatform.uno-platform-addin-2022">Wizard</a>, or check out the <a href="https://new.platform.uno/">live wizard</a>. If you&#8217;re using VS Code, the <a href="https://marketplace.visualstudio.com/items?itemName=unoplatform.vscode">extension for VS code</a> has also been updated to work with the new single project structure.</p>
<p>The post <a href="https://nicksnettravels.builttoroam.com/uno-platform-5-2-released-one-project-to-rule-them-all/">Uno Platform 5.2 Released &#8211; One Project To Rule Them All</a> appeared first on <a href="https://nicksnettravels.builttoroam.com">Nick&#039;s .NET Travels</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://nicksnettravels.builttoroam.com/uno-platform-5-2-released-one-project-to-rule-them-all/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title>Switching AI Models with ChatGPT in a Windows and Uno Platform Application</title>
		<link>https://nicksnettravels.builttoroam.com/pick-ai-model/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=pick-ai-model</link>
					<comments>https://nicksnettravels.builttoroam.com/pick-ai-model/#comments</comments>
		
		<dc:creator><![CDATA[Nick]]></dc:creator>
		<pubDate>Sat, 13 Apr 2024 18:44:57 +0000</pubDate>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[Azure]]></category>
		<category><![CDATA[ChatGPT]]></category>
		<category><![CDATA[Configuration]]></category>
		<category><![CDATA[Navigation]]></category>
		<category><![CDATA[OpenAI]]></category>
		<category><![CDATA[Settings]]></category>
		<category><![CDATA[Uno Platform]]></category>
		<category><![CDATA[Uno.Extensions]]></category>
		<category><![CDATA[Windows]]></category>
		<guid isPermaLink="false">https://nicksnettravels.builttoroam.com/?p=3199</guid>

					<description><![CDATA[<p>In my previous post I walked through how to connect to ChatGPT in order to integrate AI into a multi-platform (Windows App SDK and the&#160;Uno Platform) based application. In this post we&#8217;re going to add the ability to switch which AI model (GPT 3, 4 etc) is used when connecting to ChatGPT. We&#8217;ll also cover ... <a title="Switching AI Models with ChatGPT in a Windows and Uno Platform Application" class="read-more" href="https://nicksnettravels.builttoroam.com/pick-ai-model/" aria-label="Read more about Switching AI Models with ChatGPT in a Windows and Uno Platform Application">Read more</a></p>
<p>The post <a href="https://nicksnettravels.builttoroam.com/pick-ai-model/">Switching AI Models with ChatGPT in a Windows and Uno Platform Application</a> appeared first on <a href="https://nicksnettravels.builttoroam.com">Nick&#039;s .NET Travels</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>In my <a href="https://nicksnettravels.builttoroam.com/chatgpt-in-windows-app/">previous post</a> I walked through how to connect to ChatGPT in order to integrate AI into a multi-platform (Windows App SDK and the&nbsp;<a href="https://platform.uno/dotnettravels-uno">Uno Platform</a>) based application. In this post we&#8217;re going to add the ability to switch which AI model (GPT 3, 4 etc) is used when connecting to ChatGPT. We&#8217;ll also cover using Configuration and Settings within an Uno Platform application in order to load the API key from appsettings and persist the choice of AI model.</p>



<p>Let&#8217;s start by creating a new Uno Platform application &#8211;  as a teaser, we&#8217;re going to be using the new Uno Platform wizard and project template that is just about to be published in the coming week. This means that some of the screenshots will be blurred in patches to avoid spoiling the surprises that will come with the release.</p>



<p><img decoding="async" style="width: 1px;" src="data:image/png;base64,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csut0Tk8Zsy6ap99Ppa4BuV8+NrXvqIuvfRy/b2iHnYdZs16VtcBSB0Arg/UG+y8884V7UDW9Srlu8gx8F0zwD7/ymx/8tQHZWJY/2233abDcm0UaZfQPuB6kfrLNYb9uv32mfp7ztNWktro7h6Xsr9pyl/jjkdNPS5LEijr73EZtPnBoZGjo5d23AgilX79GcXtNFAh1pilJplUHOfYZR1KX0e0yGUCySw9FevY+e0kHbYcdhrI3DZw0j3ZayK32FUSndTbrwzy9o4sGgd5fT7CbPnytpJW9rgccNRRR31/g/X+27jygguq/gM7YMggEyKEkGIsX7LChPw0tukPS3/kzQFqu9Wy69EIznoi3ub3d8g71DSb8GH7TbX//vvpOB5cH3zwIfXii3PVoEED1RZbbKHGjh2rZs2aFdgz+oEWvP766zrfuHEbaAMQ1c47L3yghoiwxRab6wfvO+64S2255RZq+PDhOg0vt4DABVFh//33VUOGDFU33XSzevnll9W2226j52+DoPXMM8/qPAcffKBad9111eDBg6P6ysM5kPIgFiAvynv44YfV008/HWx3S70ewEM45ub8v//7P70d1Pull15W99xzr45L/VxQnwEDBqp58+apj3/8ELXHHrtH9YFwctllU9Vaa60VPNQfrPM++eRT6t5779Pljx49WpeBemO+wGef/V9dzw996L8TAoJNWt68x/fii3+jRaHtt99e5xk2bGU1bdrVOs3+vnA8QnFxRx2HoHT++ReqkSNHqsMO+4TaZJON1aOPPqZuvfU2fXzWXnttXd4rr7yiFix4R4tRm266abSPECJRpnyvOGb4XiGqoCyQtm/PP/+8th122F6tvvrqUV581zjPdtppR13vFStWqPvvf0CtsspoNWbMGJ0P24ThnMG+4LuBeLVgwYLE/rWaMx+MxcVvbzXQhJIUab/svI1sG+Rak2u+WtuQdb3gHMMfRtAj89BDJ+rz6T//eV3dfPOtie9UzofHHntcl4fzDOeQ1AHnD645rI864HqfO3euvhYkL/x33XWXWrhwkc4HIOZBwF9//fXVAQfsp/Pdffc96qGHHg7O2530ub/xxhtV1F/OSfeaAY1sf7Au6mNfc/Y1gjJfeukl9eabb+rrDtcAjkvRdulf/5qj/8iANPzh45FHHlX//Oc/ddly7WEbEFyz2kpSG3bb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dW0DzgP7Ojr88E8m8sm5vv3226kbb7wpah8mTPiYvjZtcO5IO5P2fVe7dlEvF5yLuAZd5BxFHTEkW64nuWY/97nPqDlz/h1tC+fxgQcekNg/91xGno98ZFfd9uH4yPXmXme+NseH7/rJe8677aXveBZpi0i52G3DkqPfN6E0Na+NH3TdKrtVbTOBcsrsUWrSuGZO3RIfkN6Ro02oNhYtXBgLLvqjzyzxX38kl2EWnSG5NOmeMJB1k774M8KJViXlXOjJOkmcpOzTKS21aEUbg66FfAGkbnp6/N+37feFs5Z5fVlLkBYGOuZZpx1ZumC+CTWXa2+ZqQYcddRR399gvf82ruYyYEivCRFCSDGWL1lhQrVT70/DI28OVNutVk89aqvBWU/E2/z+DoNNqD4gTODBev3111cHHLCf2mSTjdXdd9+jHnroYbXzzjupwYPD7eDB96233lL/93//p7bddhs1btwG6qWXXlb33HOvjg8fPjzKBxs7dozacccd1brrrqsf0pcvX24Esx11Ph+/+MX5as6cF4KH5Alqjz12V2+//ba66667dRq2J+AFLxA2IHbsv/++asiQoeqmm27W87+hLgACw2WXTY32a/3119NlYb+2227baL+wzdmzZ+ttfvjDO6v5899WN9xwo1p77bXUWmutpfNMnXpFUN796mMf21vts8/eaunSZXr7EA232GJzneeFF15Q559/oRo5cqQ67LBP6OP46KOPqVtvvS06Pq+//rp68MGH9L7I/oRiwpvav9NOO2r/ihUr1P33P6BWWWW0GjNmjM4HgeLXv/6NGjSoVwsJECaefPJJNWvWMzo9S1jIU3+IKeedF4o1EGTgxzbvuOMuteWWWyS+35deekm9+eab+vjje8axvffe+9Qaa6yeEExuueVW/b3jeACsa58DEHqmTLko+s5x/N977z19/CGQS1k4R7Hv8l1im/gun376abXrrrvqPHmOf6s588GlJqTU6VsOMKFyOOsJETta0zbgnMA9t7QNzzzzrM5nnzs41zF/5IsvztXCOfLhPLr77nsT15sI3hDpPvGJQ9Xo0aOD6+F+XR7OfaHatYvzEucK6oJz9eCDD9Tt0cYbb+T1Y3/kepTrSa5Z1HnQoIHBdbFFsO7Y4Lqbpa89uz4XX/wbLUZuv/32+voZNmxlNW3a1TpNrnmc8xdc8Ev16quv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D+r4snzvvff5ikDCDZpJG5o60ichFU98QaV659RTfxPcmxzNo88667e+0o8v7Uwss85GkUavXj39OdBEe+HCD4O1sf7n2Bb2eND/XFVW4jDyOsemGovnS3NMrhOWLVvm5+A5MAAHQRCBcCrWXDzRKLrpvhbZYh9M9hoyUBCvISMQU6GVKc6X14GR49kfz58+QTn/VCrzutL0lutEyFZ2nRb556agIzW79rwPed2Yli5d4q8fXTmEhbflOvM6cd25/rz+qWQbXKb7s8X5cd6EXGxnn0tUFqYjnfdctj9v6T6OAdN4Hnz28Ry++GJp/L0RxWfNtttu5x5++FG/T6o3OQbHCuP50KfwjBkv+NeMCk+eU/gz154758c2nJ99NnM+6eAzjP3aZwr/t2QqF+chFamZ6m7JL1RC0nz7J42K/EjgTFRL/rVr5Zp0V9V+RaR2K5o8eXLJsT2PDG5WrwbbtAiWREQys/H7lcFSzSn+dws3eM9cnkc0sEz85aHQPztpCsmXaQVGUtdtXJnbPhkbtNhypOW6jko8Qq1owFoX8FlL6GmBajJcIzAomuSH2GdDoj9iphMqZvLHz2T7qztVl8WLWrnB7ZYHt6pXgxatgiURkfyX699b0/XkczNVcSkikjv8op/LX/Zzvb/qRbPE6GjDNOtD69blq31ERCqDvhup4AujGTKVlQwwJFJY6k5wKCIikoqCSxERqRLLln3lxo4d5/tfI8BkzkTzPjXnE5FcYnAagstwf470FZmoP0eRwqVAU0RE6h4FlyIiOZfrLxaF+UXF+nyjX0QCTKot6adx8OALgi1ERHKDP4bQxyEDytDnIf058keSRP05itRumfRRmej3C4WjIiKSPxjIUX1cikhBys8+LqO/7GfawX2qLwux/emzU6R2qLivIPv8SD9EUB+XIrXDxpUV9bmYzu8WmYaPmX/e1Bbq41JEJD011cfl5OkvqOJSROoSfiHP5JfyTLePquzjo3K9PxEREZFC//0i0z8Ui4hIIVFwKSIiIpJ39IcKEZHkwmGlPitFRGozBZciUkdU5pfayv5CrF+oRUREpDrUld859LuViEhdoeBSRApUJr+w5uKX28ruQ79gi4iISGUl+n2CdTaJiIjULgouRaSApfolPde/xFd2f7k+HxEREal77PcJ/V4hIiK1n4JLERERkRpHf20aYCITJSUl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GjYOlkRE8l9N/d/04Sf/UcWliIiIiCRGaHnvvfe57bbbzp111m/daaed4j75ZJErLr7TB4Jhc+bMdV98sdR1797NB44EgWzHADdh9Bk5Y8YL7uCDD/LbNW7cyD300CP+WJng+MXF49x7771Xup+j/fm1abOzP9/wYDrhbYYMucBvQ4DIBIJFWw+W+/Y91i8nQmjJ81q69At/PZiaNGnij/vaa68FW5UZN+4ut+222/nnesghh/htnn56WnCviIiIiFREwaWISJUpCSYRkcL0yivzfGh59tlnuc6dO/vg7dRTf+MrFhcuXBhsFbPLLm3c0KEX+oCOafDg8/12L744O9iizKWXXhLa7gJ/jKlTnw7uTQ/nRng4aNCZrnv37v78OM/27du56dNn+G2omGQb+qhkm7333ttvQ0hJ5SXox5L1hI9guW3btn45kWeeiYWOPAeuBxPPm30++eRUf19Yt26H++PzXAk52W7RokXBvSIiIiJSEQWXIiJVIhxY5iq8VBAqItWLQO7aa68JbsU0ahRrkk6T57A99tgjWIoh/COko9oxjICzefPmwS3nlzt16uS+/fZbX82YLppzs3+CxrBevY70VZ/gvjvuuN2Hi2GElBwvU1R5UnG6//77l3sOOOKIw31QS1gaFm4+jmyPLSIiIlIXKbgUESkICixFpGbQtPnWW0f6fiyZxo4dF9yTWps2u/gwL5XWrXfw8/Xr0+8/iQDRqiTDCCupbjQ0Vacp+rBhV8SfA4/NxhdffOHnrVqV9dtprC/PTz9NP3wVERERkYopuBQRqRYKHkWk8ND0mdBvv/32830/Mp100gnBvfmP0PK22253S5cu8U3c7TlQqSkiIiIi+U/BpYhItVF4KSKFZfbs2b6ZNRWMVDIyRZs+V+S77751jRunHjnXmp1bM/R00Jfl2rVrg1tlCCutufY777zrKz7PPPMM3wemPYdElZrpYJR0rF+/wc/DVqyIPYfdd0/eP6aIiIiIZEbBpYhItVJ4KSKFZd268uHgV199FSyVR5+TYfRXaf1BhjGqeHhEcpYZKIcBeioaFCeKPjUZeCfapySD54wff39wKybcXJ3jMeJ5NujXksCU5vPh54C33nrbh7QEoyIiIiKSGwouRUSqncJLESkMhHTvvfe+by4+ffpzwTw2YncUIeU999zr5s+f7+bMmeOKi+/0Qd6R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/sI89dRUs2L5CttW5fLly83cufPMo+MnmL323NOuf+abM02bNq3tOkSB2K5du0T3JdZxeaN2W9qe1jd+/KPRz8rc9+eaZcuX1SvHH/5wg12PyiEa6/Mqy7p168z223dq8LFD+aleV/iHnVnftTB7t89/OW54t+5vTr/fu5k31XAzZ75lliz5zgYEg7799lvz1luzTJcuP7aDuKy1xYsXmbFjH7LXL62jbdstzDbbbGPfcxQAe+SR8XaZadOm1143vjU71l6DmjVLXP5EZXKUSanrzNKly8xuu+3qzY1k1j3++BO2vNdc83tbfvn4449teTp33tFstVXkD1GqrjhhwkTzwANj7Xu6nm65ZbvafWlr33fb2HbbbWqvX2/a5aZOfdp88skn5oc//GF0OQmu67333jOtWrWqd0x07PTZffbZx5sTkcpxSvW4q53Iv//9uWhZtcyaNWui31887pjr/4I3a/+P2GWXnevtX7zvJFHZ1YbdTTfdYtq1a1vvhu6zzz6z342oXPrOxo17JOG63b7eddc95v333693DBOVQe/dccdIW3a3rPsO3PcryY5PQ1331npvypire9R4U9nRuFlzbyr7kp0j7rvbY49eZvPNN7fzguem/zzS/Yx/XTruweuBlr/vvvtt9m+s88F9p/qN/u1vd9jvXb+deN9nNs9z0Tr8v7eqqqpNfj/JthnkzongufLHP/7J1vA54IADvDm192NvvFE7/8+2vMuWLau3z+77EP3mtW3Re7oGatD088+/EC2bvqdUrsv+/Xbn4+zZ75j27dvXOx+T7buuZSqH6PqsZfzXZf92kl0P/cc9+P0H//9KdGzCIgz3OOWiUPdyUshnYSAXli5daq6//vra/8euMddee6259dZb7XX+Bz/4genQoYNdRjGEv/zlL+ZHP/qROfDAA+28fJg8ebL5/PPPzcUXX+zNSZ326/777zcXXXRR3P2ShmyjGBTq/6b5C/5D5zyp0I1WPK29m/N8UCbjpZdcZqcv9lUzd1XW1cGQy6bUtAKDMuWpJ2xV8+nTX4lmiI4aNdqONf+KKy6306LpVKulr1ixwlxz7dXRciiDVbRt5+MFH5t77v4/O60MVVfNfsxdo+znARQ3PbRq2GefvaPBJrVXpgdWR53Q6MGwS5cuZtiwc21VwDlz5pjRo8dkpROWnXfe2Rx88MH2IV4P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939IWH9jABDLxo0bTVVVlampqfHmAEiEwCUAAABiUoC6ffv2ZsGCj7w5EZ988okd67358+sHkT755D92vPPOO9txWMUKWmoolaD8pEmPeVMAkF+jRo0yJ554olm6dKk3J7mZM2eajh072nGx0H5mUmZ9bqeddjKzZs3y5qQm0+0Bxa7xkCFDfr/zj3/kvcyvxs1aeFMAkJ7qdfmvihY067sWZu/2+S/HDe/W/c3p93s386ayQ5lTjz8+2TzwwFib2fLee++ZVq1aRTOnRPPvuGOk2WOPXmbChInRZZcuXWZ23HEH06zZpmVSdswf/nCD+fjjj+3rt96aZT+jIIGjqqgPPvhQ7Ton2fe+/PJLs+WW7Uzbtm29JTbl1rvtttuYf/3rTVuWqVOftkGVH/7wh/U+qwyxxx9/wowb97BdZubMt2y2WJcuP7bva/s33XSLadeurb0pdHRMrrnm93Zayyobcty4R+qVPbhubb9p06Z2feK2Idq3Rx4ZbyZPfsJMmzbd/O9/30aPmzu2S5Z8F11W69pnn33sa1H127FjH7KfD+5DPC5707+cO3bi5ms//v7356LHMdb6g/vfkO8g0XEqVde9td6bMubqHtnNtGjcrLk3lV1ffvmVmTdvfr3fvL5rfZ8dO3Yw//3vf+v9RvXddurUMTpPvz//79j9zpNdQ3S90LD33nuZrbbays7z02cUOHXrTba8o9+1zjH//gT5f9ePPfa4/c137ryjXW8q10mdJ9qOft933XVP9HxXho1+5/rc//3fvdHzrG3bLep9XlSG++67314Tg9eKeNwx6Nq1i82IbdGiee1ndvTejX+MVJ541yV9z5dcMtx+P7vttqv3iQg1FfDhhx/a70Dr0PfqjpPjX7fbVx2T999/v97vJlEZ3Pehskvw/5Dgb0yC15tY17N0rl/5FIZ7nHJRqHs5yeWzsAJbN954oznnnHPMrbfeWnsuPG7WrVtXe+7v7S2RHgUhf/3rX5sDDzzQdOjQwZtbx71/8cUX29evvPKKef75582QIUPMFltsYecls3jx4trr3QRz/PHHx9yGo3s07ZN/uPfee+3nu3TpkvL2suGtt94y//jHP5KWOejf//63ef31181xxx2X1ucy3R6QDYX6v2n+gv+QcQkAiNDD+OjRd5lFixabE074pR1atmxZ++D8gG3nLmjMmLvNllu2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" alt="">In the wizard, we&#8217;re going to select the Recommended preset configuration and then from Extensions we&#8217;re going to remove the Http and Localization options, mainly because we don&#8217;t need them in this application. The Microsoft Azure.AI.OpenAI library isn&#8217;t able to directly use the Http factory capabilities of Microsoft.Extensions, so for now, we&#8217;ll uncheck the Http option.</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2024/04/image.png"><img loading="lazy" decoding="async" width="300" height="269" src="https://wordpressblogimages.builttoroam.com/blogimages/2024/04/image-300x269.png" alt="" class="wp-image-3201" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2024/04/image-300x269.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2024/04/image-1024x919.png 1024w, https://wordpressblogimages.builttoroam.com/blogimages/2024/04/image-768x689.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2024/04/image.png 1326w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<h2 class="wp-block-heading">Configuration for API Key</h2>



<p>Once the application has been created, the first thing we&#8217;re going to do is to add the API key (see my <a href="https://nicksnettravels.builttoroam.com/chatgpt-in-windows-app/">previous post</a> where I talk about where to get the OpenAI API key) to the appsettings.json file. Since we might be using a different API key for development, we&#8217;re actually going to add the key to the appsettings.development.json file. This file is only loaded when the hosting environment is set to Development. There&#8217;s conditional logic in setup of the application that sets the hosting environment to Development when the build configuration is Debug.</p>



<pre class="hljs" style="display: block; overflow-x: auto; padding: 0.5em; background: rgb(255, 255, 255); color: rgb(0, 0, 0);">{
  <span class="hljs-attr" style="color: red;">"AppConfig"</span>: {
    <span class="hljs-attr" style="color: red;">"Environment"</span>: <span class="hljs-string" style="color: rgb(163, 21, 21);">"Development"</span>,
      <span class="hljs-attr" style="color: red;">"ApiKey"</span>: <span class="hljs-string" style="color: rgb(163, 21, 21);">"&lt;your api key&gt;"</span>
  }
}
</pre>



<p>In order for the ApiKey to be read, the AppConfig class needs to be extended with a property, ApiKey, that aligns with the key used in the json file.</p>



<pre class="hljs" style="display: block; overflow-x: auto; padding: 0.5em; background: rgb(255, 255, 255); color: rgb(0, 0, 0);"><span class="hljs-keyword" style="color: rgb(0, 0, 255);">public</span> record AppConfig
{
    <span class="hljs-keyword" style="color: rgb(0, 0, 255);">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">string</span>? Environment { <span class="hljs-keyword" style="color: rgb(0, 0, 255);">get</span>; init; }
    <span class="hljs-keyword" style="color: rgb(0, 0, 255);">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">string</span>? ApiKey { <span class="hljs-keyword" style="color: rgb(0, 0, 255);">get</span>; init; }
}</pre>



<h2 class="wp-block-heading">Settings for AI Model</h2>



<p>When using the Azure.AI.OpenAI library you can pick the AI service model that you want to use. A full list of these can be found in the <a href="https://learn.microsoft.com/en-us/azure/ai-services/openai/concepts/model-retirements#current-models">documentation</a>. </p>



<p>To allow the user to pick the AI model they want to use, we&#8217;re going to add a Settings page to our application. We&#8217;ll also rename the SecondPage of our application to ChatPage, and the corresponding model from SecondModel to ChatModel. Then we&#8217;ll tie these pages together with a NavigationView to navigate between them.</p>



<h3 class="wp-block-heading">NavigationView</h3>



<p>We&#8217;ll update the MainPage to include a NavigationView.</p>



<pre class="hljs" style="display: block; overflow-x: auto; padding: 0.5em; background: rgb(255, 255, 255); color: rgb(0, 0, 0);"><span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">Page</span> <span class="hljs-attr" style="color: red;">x:Class</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"SimpleChat.Presentation.MainPage"</span>
      <span class="hljs-attr" style="color: red;">xmlns</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"http://schemas.microsoft.com/winfx/2006/xaml/presentation"</span>
      <span class="hljs-attr" style="color: red;">xmlns:x</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"http://schemas.microsoft.com/winfx/2006/xaml"</span>
      <span class="hljs-attr" style="color: red;">xmlns:local</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"using:SimpleChat.Presentation"</span>
      <span class="hljs-attr" style="color: red;">xmlns:uen</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"using:Uno.Extensions.Navigation.UI"</span>
      <span class="hljs-attr" style="color: red;">xmlns:utu</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"using:Uno.Toolkit.UI"</span>
      <span class="hljs-attr" style="color: red;">xmlns:um</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"using:Uno.Material"</span>
      <span class="hljs-attr" style="color: red;">NavigationCacheMode</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Required"</span>
      <span class="hljs-attr" style="color: red;">Background</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"{ThemeResource BackgroundBrush}"</span>&gt;</span>

  <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">Grid</span> <span class="hljs-attr" style="color: red;">utu:SafeArea.Insets</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"VisibleBounds"</span>&gt;</span>
    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">NavigationView</span> <span class="hljs-attr" style="color: red;">x:Name</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"NavView"</span>
      <span class="hljs-attr" style="color: red;">uen:Region.Attached</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"True"</span>
      <span class="hljs-attr" style="color: red;">Loaded</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"NavViewLoaded"</span>&gt;</span>
      <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">NavigationView.MenuItems</span>&gt;</span>
        <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">NavigationViewItem</span> <span class="hljs-attr" style="color: red;">Content</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Chat"</span> <span class="hljs-attr" style="color: red;">uen:Region.Name</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Chat"</span>/&gt;</span>
        <span class="hljs-comment" style="color: green;">&lt;!-- Hack: This is to ensure a Settings item is picked up by the Navigator for NavigationView --&gt;</span>
        <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">NavigationViewItem</span> <span class="hljs-attr" style="color: red;">Content</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Settings"</span> <span class="hljs-attr" style="color: red;">uen:Region.Name</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Settings"</span> <span class="hljs-attr" style="color: red;">Visibility</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Collapsed"</span>/&gt;</span>
      <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">NavigationView.MenuItems</span>&gt;</span>

      <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">Grid</span> <span class="hljs-attr" style="color: red;">uen:Region.Attached</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"True"</span>
            <span class="hljs-attr" style="color: red;">uen:Region.Navigator</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Visibility"</span>&gt;</span>
      <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">Grid</span>&gt;</span>
    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">NavigationView</span>&gt;</span>
  <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">Grid</span>&gt;</span>
<span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">Page</span>&gt;</span>
</pre>



<p>We also need to add the <code>NavViewLoaded</code> method in the codebehind file.</p>



<pre class="hljs" style="display: block; overflow-x: auto; padding: 0.5em; background: rgb(255, 255, 255); color: rgb(0, 0, 0);"><span class="hljs-function"><span class="hljs-keyword" style="color: rgb(0, 0, 255);">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">void</span> <span class="hljs-title" style="color: rgb(163, 21, 21);">NavViewLoaded</span>(<span class="hljs-params"><span class="hljs-keyword" style="color: rgb(0, 0, 255);">object</span> sender, RoutedEventArgs e</span>)
</span>{
    <span class="hljs-keyword" style="color: rgb(0, 0, 255);">if</span> (sender <span class="hljs-keyword" style="color: rgb(0, 0, 255);">is</span> NavigationView navView &amp;&amp;
        navView.SettingsItem <span class="hljs-keyword" style="color: rgb(0, 0, 255);">is</span> FrameworkElement settingsItem)
    {
        Region.SetName(settingsItem, <span class="hljs-string" style="color: rgb(163, 21, 21);">"Settings"</span>);
    }
}</pre>



<p>So there&#8217;s a couple of things to break down here. Firstly, we&#8217;re using the Uno.Extensions.Navigation which is a navigation abstraction provided by Uno.Extensions. One of the limitations of the current support for NavigationView is that it doesn&#8217;t handle the SettingsItem on the NavigationView. There&#8217;s a couple of hacks we need to do in order to get it to work:</p>



<ul class="wp-block-list">
<li>In the codebehind, we&#8217;re going to use the Region.SetName method to set the Region.Name attached property on the SettingsItem. Unfortunately, the SettingsItem in the NavigationView is readonly, so we can&#8217;t set it to be a new NavigationViewItem in XAML where we could set the Region.Name attached property.</li>



<li>Currently, the support for NavigationView looks at the list of MenuItems to determine the selected item. Since the SettingsItem isn&#8217;t in this list, clicking the SettingsItem would navigate to the Settings page but would do it at the MainPage level, rather than placing the SettingsPage inside the NavigationView. The workaround here is to add an additional NavigationViewItem to the MenuItems with the same Region.Name attached property but set it to Collapsed.</li>
</ul>



<h3 class="wp-block-heading">SettingsPage</h3>



<p>We&#8217;re going to use the SettingsPage to provide the user with a way to pick the AI service model they want to use in the chat. First, we&#8217;ll start with the layout that will include a ComboBox to pick the service model.</p>



<pre class="hljs" style="display: block; overflow-x: auto; padding: 0.5em; background: rgb(255, 255, 255); color: rgb(0, 0, 0);"><span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">Page</span>
    <span class="hljs-attr" style="color: red;">x:Class</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"SimpleChat.Presentation.SettingsPage"</span>
    <span class="hljs-attr" style="color: red;">xmlns</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"http://schemas.microsoft.com/winfx/2006/xaml/presentation"</span>
    <span class="hljs-attr" style="color: red;">xmlns:x</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"http://schemas.microsoft.com/winfx/2006/xaml"</span>
    <span class="hljs-attr" style="color: red;">xmlns:d</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"http://schemas.microsoft.com/expression/blend/2008"</span>
    <span class="hljs-attr" style="color: red;">xmlns:local</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"using:SimpleChat.Presentation"</span>
    <span class="hljs-attr" style="color: red;">xmlns:mc</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"http://schemas.openxmlformats.org/markup-compatibility/2006"</span>
    <span class="hljs-attr" style="color: red;">xmlns:uen</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"using:Uno.Extensions.Navigation.UI"</span>
    <span class="hljs-attr" style="color: red;">xmlns:um</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"using:Uno.Material"</span>
    <span class="hljs-attr" style="color: red;">xmlns:utu</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"using:Uno.Toolkit.UI"</span>
    <span class="hljs-attr" style="color: red;">Background</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"{ThemeResource ApplicationPageBackgroundThemeBrush}"</span>
    <span class="hljs-attr" style="color: red;">mc:Ignorable</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"d"</span>&gt;</span>
    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">Grid</span>&gt;</span>
        <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">Grid.RowDefinitions</span>&gt;</span>
            <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">RowDefinition</span> <span class="hljs-attr" style="color: red;">Height</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Auto"</span> /&gt;</span>
            <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">RowDefinition</span> /&gt;</span>
        <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">Grid.RowDefinitions</span>&gt;</span>
        <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">utu:NavigationBar</span> <span class="hljs-attr" style="color: red;">Content</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Settings Page"</span> /&gt;</span>

        <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">StackPanel</span>
            <span class="hljs-attr" style="color: red;">Grid.Row</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"1"</span>
            <span class="hljs-attr" style="color: red;">Spacing</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"12"</span>&gt;</span>
            <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">TextBlock</span> <span class="hljs-attr" style="color: red;">Text</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"AI Model"</span> /&gt;</span>
            <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">ComboBox</span>
                <span class="hljs-attr" style="color: red;">ItemsSource</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"{Binding ServiceModels}"</span>
                <span class="hljs-attr" style="color: red;">SelectedItem</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"{Binding SelectedServiceModel, Mode=TwoWay}"</span> /&gt;</span>
        <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">StackPanel</span>&gt;</span>
    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">Grid</span>&gt;</span>
<span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">Page</span>&gt;</span>
</pre>



<p>There&#8217;s no code in the codebehind file. Instead all the logic is encapsulated in the ServiceModel. </p>



<pre class="hljs" style="display: block; overflow-x: auto; padding: 0.5em; background: rgb(255, 255, 255); color: rgb(0, 0, 0);"><span class="hljs-keyword" style="color: rgb(0, 0, 255);">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">partial</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">class</span> <span class="hljs-title" style="color: rgb(163, 21, 21);">SettingsModel</span>
{
    <span class="hljs-keyword" style="color: rgb(0, 0, 255);">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">readonly</span> IWritableOptions&lt;SettingsInfo&gt; _settings;

    <span class="hljs-keyword" style="color: rgb(0, 0, 255);">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">string</span>[] ServiceModels { <span class="hljs-keyword" style="color: rgb(0, 0, 255);">get</span>; } =
        [
            <span class="hljs-string" style="color: rgb(163, 21, 21);">"gpt-35-turbo"</span>,
            <span class="hljs-string" style="color: rgb(163, 21, 21);">"gpt-4"</span>,
            .......
        ];

    <span class="hljs-keyword" style="color: rgb(0, 0, 255);">public</span> IState&lt;<span class="hljs-keyword" style="color: rgb(0, 0, 255);">string</span>&gt; SelectedServiceModel =&gt; State&lt;<span class="hljs-keyword" style="color: rgb(0, 0, 255);">string</span>&gt;.Value(<span class="hljs-keyword" style="color: rgb(0, 0, 255);">this</span>, () =&gt; _settings.Value.ServiceModel?? <span class="hljs-string" style="color: rgb(163, 21, 21);">"gpt-4-1106-preview"</span>);

    <span class="hljs-function"><span class="hljs-keyword" style="color: rgb(0, 0, 255);">public</span> <span class="hljs-title" style="color: rgb(163, 21, 21);">SettingsModel</span>(<span class="hljs-params">IWritableOptions&lt;SettingsInfo&gt; settings</span>)
    </span>{
        _settings = settings;

        SelectedServiceModel.ForEachAsync(<span class="hljs-keyword" style="color: rgb(0, 0, 255);">async</span> (serviceModel, ct) =&gt;
        {
            <span class="hljs-keyword" style="color: rgb(0, 0, 255);">await</span> _settings.UpdateAsync(settings =&gt; settings with { ServiceModel = serviceModel });
        });
    }
}</pre>



<p>The list of available service models is exposed by the ServiceModels property, which is data boudn to the ItemsSource property on the ComboBox. The SelectedServiceModel property is an IState (making use of the MVUX state management pattern that&#8217;s part of Uno.Extensions) and is two-way data bound to the SelectedItem property on the ComboBox.</p>



<p>In the constructor for the SettingsModel, a SettingsInfo instance is received which is used to retrieve the current ServiceModel and subsequently to write back the new value when the user changes the selected service model.</p>



<p>For this to work, we need to register the SettingsInfo type in the setup of the application.</p>



<pre class="hljs" style="display: block; overflow-x: auto; padding: 0.5em; background: rgb(255, 255, 255); color: rgb(0, 0, 0);"><span class="hljs-keyword" style="color: rgb(0, 0, 255);">public</span> record SettingsInfo
{
    <span class="hljs-keyword" style="color: rgb(0, 0, 255);">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">string</span>? ServiceModel { <span class="hljs-keyword" style="color: rgb(0, 0, 255);">get</span>; init; }
}

<span class="hljs-comment" style="color: green;">// App configuration</span>
.UseConfiguration(configure: configBuilder =&gt;
    configBuilder
        .EmbeddedSource&lt;App&gt;()
        .Section&lt;AppConfig&gt;()
        .Section&lt;SettingsInfo&gt;()
)</pre>



<h2 class="wp-block-heading">Using the Service Model in Chat</h2>



<p>Now that we have the API key being provided via appsettings.json and a SettingsPage to pick the AI model, let&#8217;s reuse the code from the previous post to provide a simple chat interface.</p>



<pre class="hljs" style="display: block; overflow-x: auto; padding: 0.5em; background: rgb(255, 255, 255); color: rgb(0, 0, 0);"><span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">Page</span> <span class="hljs-attr" style="color: red;">x:Class</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"SimpleChat.Presentation.ChatPage"</span>
      <span class="hljs-attr" style="color: red;">xmlns</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"http://schemas.microsoft.com/winfx/2006/xaml/presentation"</span>
      <span class="hljs-attr" style="color: red;">xmlns:x</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"http://schemas.microsoft.com/winfx/2006/xaml"</span>
      <span class="hljs-attr" style="color: red;">xmlns:local</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"using:SimpleChat.Presentation"</span>
      <span class="hljs-attr" style="color: red;">xmlns:d</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"http://schemas.microsoft.com/expression/blend/2008"</span>
      <span class="hljs-attr" style="color: red;">xmlns:mc</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"http://schemas.openxmlformats.org/markup-compatibility/2006"</span>
      <span class="hljs-attr" style="color: red;">xmlns:uen</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"using:Uno.Extensions.Navigation.UI"</span>
      <span class="hljs-attr" style="color: red;">xmlns:utu</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"using:Uno.Toolkit.UI"</span>
      <span class="hljs-attr" style="color: red;">xmlns:um</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"using:Uno.Material"</span>
      <span class="hljs-attr" style="color: red;">Background</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"{ThemeResource BackgroundBrush}"</span>&gt;</span>

  <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">Grid</span> <span class="hljs-attr" style="color: red;">utu:SafeArea.Insets</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"VisibleBounds"</span>&gt;</span>
    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">Grid.RowDefinitions</span>&gt;</span>
      <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">RowDefinition</span> <span class="hljs-attr" style="color: red;">Height</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Auto"</span> /&gt;</span>
      <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">RowDefinition</span> <span class="hljs-attr" style="color: red;">Height</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Auto"</span> /&gt;</span>
      <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">RowDefinition</span> /&gt;</span>
    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">Grid.RowDefinitions</span>&gt;</span>
    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">utu:NavigationBar</span> <span class="hljs-attr" style="color: red;">Content</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Chat Page"</span>&gt;</span>
      <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">utu:NavigationBar.MainCommand</span>&gt;</span>
        <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">AppBarButton</span>&gt;</span>
          <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">AppBarButton.Icon</span>&gt;</span>
            <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">BitmapIcon</span> <span class="hljs-attr" style="color: red;">UriSource</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"ms-appx:///Assets/Images/back.png"</span> /&gt;</span>
          <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">AppBarButton.Icon</span>&gt;</span>
        <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">AppBarButton</span>&gt;</span>
      <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">utu:NavigationBar.MainCommand</span>&gt;</span>
    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">utu:NavigationBar</span>&gt;</span>
    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">StackPanel</span> <span class="hljs-attr" style="color: red;">Grid.Row</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"1"</span>
                <span class="hljs-attr" style="color: red;">HorizontalAlignment</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Center"</span>
                <span class="hljs-attr" style="color: red;">VerticalAlignment</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Center"</span>&gt;</span>
      <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">TextBox</span> <span class="hljs-attr" style="color: red;">Text</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"{Binding Query, Mode=TwoWay}"</span> /&gt;</span>
      <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">Button</span> <span class="hljs-attr" style="color: red;">Content</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Send"</span>
              <span class="hljs-attr" style="color: red;">Command</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"{Binding Send}"</span> /&gt;</span>
    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">StackPanel</span>&gt;</span>
    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">TextBlock</span> <span class="hljs-attr" style="color: red;">Text</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"{Binding Response}"</span>
               <span class="hljs-attr" style="color: red;">Grid.Row</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"2"</span> /&gt;</span>
  <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">Grid</span>&gt;</span>
<span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">Page</span>&gt;</span>
</pre>



<p>And the ChatModel</p>



<pre class="hljs" style="display: block; overflow-x: auto; padding: 0.5em; background: rgb(255, 255, 255); color: rgb(0, 0, 0);"><span class="hljs-function"><span class="hljs-keyword" style="color: rgb(0, 0, 255);">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">partial</span> record <span class="hljs-title" style="color: rgb(163, 21, 21);">ChatModel</span>(<span class="hljs-params">
    Entity Entity,
    IOptions&lt;AppConfig&gt; Config,
    IOptions&lt;SettingsInfo&gt; Settings</span>)
</span>{
    <span class="hljs-keyword" style="color: rgb(0, 0, 255);">public</span> IState&lt;<span class="hljs-keyword" style="color: rgb(0, 0, 255);">string</span>&gt; Query =&gt; State&lt;<span class="hljs-keyword" style="color: rgb(0, 0, 255);">string</span>&gt;.Value(<span class="hljs-keyword" style="color: rgb(0, 0, 255);">this</span>, () =&gt; <span class="hljs-string" style="color: rgb(163, 21, 21);">"Explain AI"</span>);

    <span class="hljs-keyword" style="color: rgb(0, 0, 255);">public</span> IState&lt;<span class="hljs-keyword" style="color: rgb(0, 0, 255);">string</span>&gt; Response =&gt; State&lt;<span class="hljs-keyword" style="color: rgb(0, 0, 255);">string</span>&gt;.Value(<span class="hljs-keyword" style="color: rgb(0, 0, 255);">this</span>, () =&gt; <span class="hljs-keyword" style="color: rgb(0, 0, 255);">string</span>.Empty);

    <span class="hljs-function"><span class="hljs-keyword" style="color: rgb(0, 0, 255);">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">async</span> Task <span class="hljs-title" style="color: rgb(163, 21, 21);">Send</span>(<span class="hljs-params"><span class="hljs-keyword" style="color: rgb(0, 0, 255);">string</span> query</span>)
    </span>{
        <span class="hljs-keyword" style="color: rgb(0, 0, 255);">var</span> response = <span class="hljs-keyword" style="color: rgb(0, 0, 255);">await</span> GetChatGPTResponseAsync(query);
        <span class="hljs-keyword" style="color: rgb(0, 0, 255);">await</span> Response.SetAsync(response);
    }

    <span class="hljs-function"><span class="hljs-keyword" style="color: rgb(0, 0, 255);">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">async</span> Task&lt;<span class="hljs-keyword" style="color: rgb(0, 0, 255);">string</span>&gt; <span class="hljs-title" style="color: rgb(163, 21, 21);">GetChatGPTResponseAsync</span>(<span class="hljs-params"><span class="hljs-keyword" style="color: rgb(0, 0, 255);">string</span> query</span>)
    </span>{
        <span class="hljs-keyword" style="color: rgb(0, 0, 255);">var</span> client = <span class="hljs-keyword" style="color: rgb(0, 0, 255);">new</span> OpenAIClient(Config.Value.ApiKey);

        <span class="hljs-keyword" style="color: rgb(0, 0, 255);">var</span> completionOptions = <span class="hljs-keyword" style="color: rgb(0, 0, 255);">new</span> ChatCompletionsOptions
        {
            DeploymentName = Settings.Value.ServiceModel,
        };

        completionOptions.Messages.Add(<span class="hljs-keyword" style="color: rgb(0, 0, 255);">new</span> ChatRequestUserMessage(query));

        <span class="hljs-keyword" style="color: rgb(0, 0, 255);">var</span> resp = <span class="hljs-keyword" style="color: rgb(0, 0, 255);">await</span> client.GetChatCompletionsAsync(completionOptions);

        <span class="hljs-keyword" style="color: rgb(0, 0, 255);">if</span> (resp?.Value?.Choices.FirstOrDefault() <span class="hljs-keyword" style="color: rgb(0, 0, 255);">is</span> { } response &amp;&amp;
            response.Message?.Content <span class="hljs-keyword" style="color: rgb(0, 0, 255);">is</span> { } responseMessage)
        {
            <span class="hljs-keyword" style="color: rgb(0, 0, 255);">return</span> responseMessage;
        }
        <span class="hljs-keyword" style="color: rgb(0, 0, 255);">return</span> <span class="hljs-string" style="color: rgb(163, 21, 21);">"No response"</span>;
    }
}</pre>



<p>Running this provides a basic interface for asking ChatGPT and getting a response using the AI service model picked via the SettingsPage.</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2024/04/image-661ad1c5828a6.png"><img loading="lazy" decoding="async" width="300" height="189" src="https://wordpressblogimages.builttoroam.com/blogimages/2024/04/image-661ad1c5828a6-300x189.png" alt="" class="wp-image-3203" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2024/04/image-661ad1c5828a6-300x189.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2024/04/image-661ad1c5828a6-1024x646.png 1024w, https://wordpressblogimages.builttoroam.com/blogimages/2024/04/image-661ad1c5828a6-768x485.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2024/04/image-661ad1c5828a6-1536x969.png 1536w, https://wordpressblogimages.builttoroam.com/blogimages/2024/04/image-661ad1c5828a6.png 1784w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<h2 class="wp-block-heading">Summary</h2>



<p>In this post we&#8217;ve seen how navigation using a NavigationView can be used to switch between SettingsPage and ChatPage. We&#8217;ve also used Configuration to read information from appsettings.json and Settings to capture the AI service model selected by the user. This is the starting point for a chat style application with <a href="https://github.com/nickrandolph/SimpleChat">source code available on GitHub</a>.</p>
<p>The post <a href="https://nicksnettravels.builttoroam.com/pick-ai-model/">Switching AI Models with ChatGPT in a Windows and Uno Platform Application</a> appeared first on <a href="https://nicksnettravels.builttoroam.com">Nick&#039;s .NET Travels</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://nicksnettravels.builttoroam.com/pick-ai-model/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title>Connecting Your Windows and Uno Platform App to ChatGPT with Azure.AI.OpenAI</title>
		<link>https://nicksnettravels.builttoroam.com/chatgpt-in-windows-app/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=chatgpt-in-windows-app</link>
					<comments>https://nicksnettravels.builttoroam.com/chatgpt-in-windows-app/#comments</comments>
		
		<dc:creator><![CDATA[Nick]]></dc:creator>
		<pubDate>Sun, 07 Apr 2024 17:27:35 +0000</pubDate>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[AI]]></category>
		<category><![CDATA[ChatGPT]]></category>
		<category><![CDATA[Uno Platform]]></category>
		<category><![CDATA[WinAppSdk]]></category>
		<category><![CDATA[Windows]]></category>
		<category><![CDATA[Windows App SDK]]></category>
		<category><![CDATA[WinUI]]></category>
		<guid isPermaLink="false">https://nicksnettravels.builttoroam.com/?p=3196</guid>

					<description><![CDATA[<p>In today&#8217;s digital world, integrating AI into your applications has become increasingly important. One powerful AI model that you can leverage is OpenAI&#8217;s GPT, known for its natural language processing capabilities. In this blog post, we&#8217;ll guide you through the process of connecting your Windows app to ChatGPT using the Microsoft Azure.AI.OpenAI library, allowing you ... <a title="Connecting Your Windows and Uno Platform App to ChatGPT with Azure.AI.OpenAI" class="read-more" href="https://nicksnettravels.builttoroam.com/chatgpt-in-windows-app/" aria-label="Read more about Connecting Your Windows and Uno Platform App to ChatGPT with Azure.AI.OpenAI">Read more</a></p>
<p>The post <a href="https://nicksnettravels.builttoroam.com/chatgpt-in-windows-app/">Connecting Your Windows and Uno Platform App to ChatGPT with Azure.AI.OpenAI</a> appeared first on <a href="https://nicksnettravels.builttoroam.com">Nick&#039;s .NET Travels</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>In today&#8217;s digital world, integrating AI into your applications has become increasingly important. One powerful AI model that you can leverage is OpenAI&#8217;s GPT, known for its natural language processing capabilities. In this blog post, we&#8217;ll guide you through the process of connecting your Windows app to ChatGPT using the Microsoft Azure.AI.OpenAI library, allowing you to enhance user interactions with intelligent responses.</p>



<h3 class="wp-block-heading">Prerequisite &#8211; OpenAI API Key</h3>



<p>If you want to follow along, you&#8217;ll need to head to https://platform.openai.com/api-keys and generate or retrieve your API key. If you don&#8217;t already have an OpenAI account, you&#8217;ll need to create one and sign in, in order to access your API key.</p>



<h3 class="wp-block-heading">Step 1: Create your Windows and Uno Platform App</h3>



<p>For this post we&#8217;re going to create a cross platform, or multi-platform, application using the Uno Platform template wizard (if you&#8217;re not using Visual Studio, you can grab the <code>uno.templates</code> dotnet new templates package and use the <code>unoapp</code> template). I&#8217;m going to pick the Recommended option (use &#8220;-preset recommended&#8221; if running <code>dotnet new unoapp</code>) and proceed without customizing it. </p>



<h3 class="wp-block-heading">Step 2: Install the Azure.AI.OpenAI Library</h3>



<p>In the main project of your application, install the Azure.AI.OpenAI library using NuGet Package Manager or the Package Manager Console. Use the following command:</p>



<pre class="wp-block-preformatted"><code>Install-Package Microsoft.Azure.AI.OpenAI -IncludePrerelease</code></pre>



<h3 class="wp-block-heading">Step 3: Connect to ChatGPT</h3>



<p>Now, let&#8217;s integrate ChatGPT into the app. Create a method to interact with ChatGPT. Here&#8217;s an example method that sends a user query to ChatGPT and retrieves a response:</p>



<pre class="hljs" style="display: block; overflow-x: auto; padding: 0.5em; background: rgb(255, 255, 255); color: rgb(0, 0, 0);"><span class="hljs-function"><span class="hljs-keyword" style="color: rgb(0, 0, 255);">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">async</span> Task&lt;<span class="hljs-keyword" style="color: rgb(0, 0, 255);">string</span>&gt; <span class="hljs-title" style="color: rgb(163, 21, 21);">GetChatGPTResponseAsync</span>(<span class="hljs-params"><span class="hljs-keyword" style="color: rgb(0, 0, 255);">string</span> query</span>)
</span>{
    <span class="hljs-keyword" style="color: rgb(0, 0, 255);">var</span> client = <span class="hljs-keyword" style="color: rgb(0, 0, 255);">new</span> OpenAIClient(<span class="hljs-string" style="color: rgb(163, 21, 21);">"OpenAI API Key"</span>);

    <span class="hljs-keyword" style="color: rgb(0, 0, 255);">var</span> completionOptions = <span class="hljs-keyword" style="color: rgb(0, 0, 255);">new</span> ChatCompletionsOptions
    {
        DeploymentName = <span class="hljs-string" style="color: rgb(163, 21, 21);">"gpt-4-1106-preview"</span>,
    };

    completionOptions.Messages.Add(<span class="hljs-keyword" style="color: rgb(0, 0, 255);">new</span> ChatRequestUserMessage(query));

    <span class="hljs-keyword" style="color: rgb(0, 0, 255);">var</span> resp = <span class="hljs-keyword" style="color: rgb(0, 0, 255);">await</span> client.GetChatCompletionsAsync(completionOptions);

    <span class="hljs-keyword" style="color: rgb(0, 0, 255);">if</span> (resp?.Value?.Choices.FirstOrDefault() <span class="hljs-keyword" style="color: rgb(0, 0, 255);">is</span> { } response &amp;&amp;
        response.Message?.Content <span class="hljs-keyword" style="color: rgb(0, 0, 255);">is</span> { } responseMessage)
    {
        <span class="hljs-keyword" style="color: rgb(0, 0, 255);">return</span> responseMessage;
    }
    <span class="hljs-keyword" style="color: rgb(0, 0, 255);">return</span> <span class="hljs-string" style="color: rgb(163, 21, 21);">"No response"</span>;
}</pre>



<p>Replace <code>"OpenAI API Key"</code> with your OpenAI API Key.</p>



<h3 class="wp-block-heading">Step 4: Integrate with Your App</h3>



<p>In the UI for the app, add a text box for user input (data bound to the Query property) and a text block (data bound to the Response property) to display the ChatGPT response. Use the following code to handle user input and display the response:</p>



<pre class="hljs" style="display: block; overflow-x: auto; padding: 0.5em; background: rgb(255, 255, 255); color: rgb(0, 0, 0);"><span class="hljs-keyword" style="color: rgb(0, 0, 255);">public</span> IState&lt;<span class="hljs-keyword" style="color: rgb(0, 0, 255);">string</span>&gt; Query =&gt; State&lt;<span class="hljs-keyword" style="color: rgb(0, 0, 255);">string</span>&gt;.Value(<span class="hljs-keyword" style="color: rgb(0, 0, 255);">this</span>, () =&gt; <span class="hljs-keyword" style="color: rgb(0, 0, 255);">string</span>.Empty);

<span class="hljs-keyword" style="color: rgb(0, 0, 255);">public</span> IState&lt;<span class="hljs-keyword" style="color: rgb(0, 0, 255);">string</span>&gt; Response =&gt; State&lt;<span class="hljs-keyword" style="color: rgb(0, 0, 255);">string</span>&gt;.Value(<span class="hljs-keyword" style="color: rgb(0, 0, 255);">this</span>, () =&gt; <span class="hljs-keyword" style="color: rgb(0, 0, 255);">string</span>.Empty);

<span class="hljs-function"><span class="hljs-keyword" style="color: rgb(0, 0, 255);">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">async</span> Task <span class="hljs-title" style="color: rgb(163, 21, 21);">Send</span>(<span class="hljs-params"><span class="hljs-keyword" style="color: rgb(0, 0, 255);">string</span> query</span>)
</span>{
    <span class="hljs-keyword" style="color: rgb(0, 0, 255);">var</span> response = <span class="hljs-keyword" style="color: rgb(0, 0, 255);">await</span> GetChatGPTResponseAsync(query);
    <span class="hljs-keyword" style="color: rgb(0, 0, 255);">await</span> Response.SetAsync(response);
}</pre>



<h3 class="wp-block-heading">Step 6: Test Your App</h3>



<p>Build and run your app. Enter a query into the text box and submit it. Your app should display a response from ChatGPT based on the user&#8217;s query.</p>



<h3 class="wp-block-heading">Conclusion</h3>



<p>By following these steps, you&#8217;ve successfully connected your Windows and Uno Platform app to ChatGPT using the Microsoft Azure.AI.OpenAI library. This integration opens up a world of possibilities for enhancing user interactions with intelligent responses. Experiment with different queries and see how ChatGPT can enrich your app&#8217;s functionality.</p>



<p></p>
<p>The post <a href="https://nicksnettravels.builttoroam.com/chatgpt-in-windows-app/">Connecting Your Windows and Uno Platform App to ChatGPT with Azure.AI.OpenAI</a> appeared first on <a href="https://nicksnettravels.builttoroam.com">Nick&#039;s .NET Travels</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://nicksnettravels.builttoroam.com/chatgpt-in-windows-app/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title>Managing Dependencies in Windows and Cross Platform Applications</title>
		<link>https://nicksnettravels.builttoroam.com/managing-dependencies/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=managing-dependencies</link>
					<comments>https://nicksnettravels.builttoroam.com/managing-dependencies/#comments</comments>
		
		<dc:creator><![CDATA[Nick]]></dc:creator>
		<pubDate>Fri, 22 Mar 2024 10:53:49 +0000</pubDate>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[NuGet]]></category>
		<category><![CDATA[Uno]]></category>
		<category><![CDATA[Uno Platform]]></category>
		<category><![CDATA[Windows]]></category>
		<category><![CDATA[Windows App SDK]]></category>
		<guid isPermaLink="false">https://nicksnettravels.builttoroam.com/?p=3187</guid>

					<description><![CDATA[<p>As with all software managing dependencies in often a lot harder than it seems, particularly when there are conflicting priorities. In this post I&#8217;m going to talk about some of the challenges developers face relating to dependencies when building Windows and cross/multi platform applications using .NET, the Windows App SDK and the Uno Platform. I&#8217;ll ... <a title="Managing Dependencies in Windows and Cross Platform Applications" class="read-more" href="https://nicksnettravels.builttoroam.com/managing-dependencies/" aria-label="Read more about Managing Dependencies in Windows and Cross Platform Applications">Read more</a></p>
<p>The post <a href="https://nicksnettravels.builttoroam.com/managing-dependencies/">Managing Dependencies in Windows and Cross Platform Applications</a> appeared first on <a href="https://nicksnettravels.builttoroam.com">Nick&#039;s .NET Travels</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>As with all software managing dependencies in often a lot harder than it seems, particularly when there are conflicting priorities. In this post I&#8217;m going to talk about some of the challenges developers face relating to dependencies when building Windows and cross/multi platform applications using .NET, the Windows App SDK and the <a href="https://platform.uno/dotnettravels-uno">Uno Platform</a>. I&#8217;ll start off by saying that there&#8217;s no absolutes here, and no right or wrong answer.</p>



<h2 class="wp-block-heading">Application Dependencies</h2>



<p>Let&#8217;s start by talking about dependencies in general. The minute you run File, New Project and select a template to create your application from, you&#8217;re immediately buying into a set of dependencies. For example, take a minimal example of a console application, which you&#8217;d assume, given it&#8217;s simplicity, that it has almost no dependencies. This is basically correct but you are still taking a dependency on .NET. This is evident when you go to package and distribute the application where you&#8217;re givens options on how you want to reference the framework (see <a href="https://learn.microsoft.com/en-us/dotnet/core/deploying/" target="_blank" rel="noreferrer noopener">Application Publishing</a> for more information).</p>



<p>Once we start to look at a Windows application (and here I&#8217;m referring to an application built using Windows UI and the Windows App SDK), the list of dependencies increases. The Windows App SDK has it&#8217;s own documentation on <a href="https://learn.microsoft.com/en-us/windows/apps/package-and-deploy/deploy-overview" target="_blank" rel="noreferrer noopener">deployment options</a>.</p>



<p>Now if we go cross platform with the Uno Platform, this adds not only the dependencies for .NET for iOS, Android, MacCatalyst but also the runtime for WASM and then the abstraction layer of Uno itself. </p>



<p>All of this before we even get to writing our application and deciding which third party dependencies we need to add. For example, if you want to add maps to your application you might use <a href="https://mapsui.com/index.html" target="_blank" rel="noreferrer noopener">MapsUI</a>, and for charts you can add <a href="https://livecharts.dev/" target="_blank" rel="noreferrer noopener">LiveCharts</a>. For more advanced controls that may not be offered natively for Uno, you can add any of the controls written for .NET MAUI such as those from <a href="https://www.syncfusion.com/maui-controls">Syncfusion</a>,&nbsp;<a href="https://grialkit.com/">Grial Kit</a>,&nbsp;<a href="https://www.telerik.com/maui-ui">Telerik</a>,&nbsp;<a href="https://www.devexpress.com/maui/">DevExpress</a>,&nbsp;<a href="https://www.esri.com/">Esri</a>,&nbsp;<a href="https://www.grapecity.com/componentone/maui-ui-controls/flexgrid-maui-datagrid">Grape City</a>, and of course, the&nbsp;<a href="https://www.nuget.org/packages/CommunityToolkit.Maui">.NET MAUI Community Toolkit</a>. </p>



<h2 class="wp-block-heading">Updating Dependencies</h2>



<p>As a general rule of thumb, applications that you&#8217;re going to be releasing either via the web, or via one of the app stores, should only reference stable releases of dependencies. For the purposes of this post when I talk about a stable release, I&#8217;m just referring about a release that isn&#8217;t marked as preview, beta, dev or any other non-numeric suffix (eg 1.5.0-dev is not a stable release, whereas 1.6.3 is). Of course, there may be times when you&#8217;re waiting on a bug fix, that you might reference a preview/beta/dev version of a dependency but when you go to publish your application, you should do so only with references to stable release. </p>



<p>The question then becomes when should you update your dependencies:</p>



<ul class="wp-block-list">
<li>Should you only update when there are security updates? </li>



<li>Or perhaps only when there are major versions? </li>



<li>Or perhaps only when you require a feature that&#8217;s in a newer version? </li>



<li>What&#8217;s the benefit to updating more or less frequently?</li>
</ul>



<p>These are just some of the questions that you should consider when deciding on a policy for your team as to when to update dependencies.</p>



<p>Let&#8217;s start with a quick discussion as to why you wouldn&#8217;t update dependencies as soon as they&#8217;re available. This often falls into a couple of buckets:</p>



<ul class="wp-block-list">
<li><strong>Not aware of new versions</strong> &#8211; If you&#8217;re in this bucket, then you probably haven&#8217;t started using <a href="https://github.com/dependabot" target="_blank" rel="noreferrer noopener">dependabot </a>(or equivalent). I would highly recommend using a service like dependabot so you know as soon as there is a dependency available, afterall, you can&#8217;t make a decision about something that you&#8217;re not aware of.</li>



<li><strong>Unscheduled work</strong> &#8211; There&#8217;s no scope in the backlog for the current release to update to the latest dependency <strong>and</strong> test it to make sure it hasn&#8217;t caused any regressions. Whilst a lot of updates will be relatively benign, there may be some that require significant rework.</li>
</ul>



<p>The latter is probably one of the main reasons that so many teams don&#8217;t frequently update their dependencies. Each time you update a dependency, there&#8217;s a risk that it will impact your application. It might be as subtle as changing the time it takes for a method to execute, resulting in cascading effects within the application, or it maybe that a dependency changes signficiantly as part of a new major version, resulting in the application logic being reworked to accommodate the change in behaviour. In all of these scenarios, there&#8217;s extra work that subsequently needs to go into testing the application to ensure no existing functionality is broken.</p>



<h2 class="wp-block-heading">Always Update Dependencies</h2>



<p>Ok, so at this point I&#8217;m going to make a bold statement that you should <strong>always update all dependencies as soon as they become available</strong>.</p>



<p>Let&#8217;s revisit the above issues that tend to drive delays to updating dependencies, starting with not being aware that updates exist. In this space, having a tool such as dependabot gives you almost immediate notification that there&#8217;s a new dependency, along with a PR that increases the version to the latest dependency. Whilst I wouldn&#8217;t say these tools are amazing, they do a sufficient job to make you aware of new dependency versions. I say that they&#8217;re not amazing because I&#8217;ve often seen cases where there are multiple related dependencies that have a new version but they get raised as independent PRs, making it harder than it needs to be to increment them. It&#8217;s not hard to cherry-pick commits from various PRs into a single PR but it&#8217;s extra work that could potentially be avoided.</p>



<p>Of course, just creating PRs to increment the version is only part of the story. With a suitable CI pipeline, there should be strong confidence that changing a dependency won&#8217;t break the application. If an update to a dependency causes one or more tests to fail, or perhaps the build itself fails, this will drive developers to update the application for the updated dependency.</p>



<p>Now we&#8217;re into the territory of unscheduled work, where dependency updates are causing the team to have to focus on modifying the application for no other reason than because a dependency changed. In some cases, the updated dependency has some intrinsic benefit to the application, for example better performance, that can be used to justify the effort required to update the application. However, in a lot of cases, updating dependencies won&#8217;t affect the application in any significant way. This begs the question as to why it&#8217;s important to update dependencies?</p>



<h2 class="wp-block-heading">Lazy Dependency Updating</h2>



<p>To answer the question of why updating dependencies is important, let&#8217;s take the reverse position of only updating dependencies when necessary. There may be a variety of reasons that require a dependency to be updated, for example new features, bug fixes (for bugs that manifest themselves in the application) and security concerns in the version used by the application. The underlying rule is to only update dependencies when there is a justifable reason to.</p>



<p>So the issue is that, like code that you have inside your application where it will naturally evolve with your application, dependencies evolve over time too. If you don&#8217;t pick up dependencies as they become available, it&#8217;s a bit like having a long running, stale, branch; at some point you&#8217;re going to have to rebase and/or mege the branch back to main. With dependencies, at some point in the future you will inevitably need to update them, and then you&#8217;ll experience the full pain of having to update through not one or two minor updates but possibly multiple major version updates, depending on how long it was since you updated. This could result in massive rework of your application and in most cases more timeconsuming as you work out what the migration path should be between versions. Now, multiply this by the number of dependencies you have and you can quite easily see this is where this strategy fails.</p>



<h2 class="wp-block-heading">Interdependencies</h2>



<p>To make matters worse, often the dependencies for your application will have interdependencies between them. Further, those relationships will be based on certain version of the dependencies, and not all combinations of the dependency versions will work nicely together.</p>



<p>If you take the lazy updating approach, you&#8217;ll find that you will have to bulk update to the latest changes, with perhaps no simple migration path for your code. Alternatively, you can incrementally attempt to update dependencies and having to balance or match any interpdendencies &#8211; at this point you&#8217;ll be wanting to reconsider life choices, well at least choices pertaining to updating dependencies.</p>



<h2 class="wp-block-heading">Looking Forward using Canaries</h2>



<p>In addition to using tools like dependabot, which typically will be used to highlight stable version updates, another technique is to use canary builds. By this I mean having a dedicated branch to building a version of your application using the absolute latest (including dev, beta, preview etc versions) of each dependency. A separate build process would be configured to run the same build pipeline you do for your application but using the canary branch. The basic approach is:</p>



<ul class="wp-block-list">
<li>Check out the canary branch</li>



<li>Update source code to latest main but merging in all changes</li>



<li>Update package references to latest version of dependencies</li>



<li>Run regular build pipeline including all tests</li>
</ul>



<p>Having this periodically run, perhaps once a day, will give you an even earlier heads up for when new dependencies might cause issues for your application. There may be specific workarounds you need to apply in order to keep your application building/running. The workarounds can be pushed to the canary branch until the stable version of those dependencies are available. At that point, the workarounds can be applied to the main source code branch for the application without much additional effort.</p>



<h2 class="wp-block-heading">Summary</h2>



<p>In this post I&#8217;ve covered some of the pros and cons of eager and lazy dependency updating. Hopefully for your application you&#8217;ve thought about this and have a strategy that works for you and your team.</p>



<p> </p>
<p>The post <a href="https://nicksnettravels.builttoroam.com/managing-dependencies/">Managing Dependencies in Windows and Cross Platform Applications</a> appeared first on <a href="https://nicksnettravels.builttoroam.com">Nick&#039;s .NET Travels</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://nicksnettravels.builttoroam.com/managing-dependencies/feed/</wfw:commentRss>
			<slash:comments>2</slash:comments>
		
		
			</item>
		<item>
		<title>Conditional Template Selector for XAML Applications for Windows and Uno Platform</title>
		<link>https://nicksnettravels.builttoroam.com/conditional-template-selector/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=conditional-template-selector</link>
					<comments>https://nicksnettravels.builttoroam.com/conditional-template-selector/#comments</comments>
		
		<dc:creator><![CDATA[Nick]]></dc:creator>
		<pubDate>Tue, 12 Mar 2024 02:53:15 +0000</pubDate>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[DataTemplate]]></category>
		<category><![CDATA[Uno Platform]]></category>
		<category><![CDATA[Windows UI]]></category>
		<category><![CDATA[WinUI]]></category>
		<category><![CDATA[XAML]]></category>
		<guid isPermaLink="false">https://nicksnettravels.builttoroam.com/?p=3181</guid>

					<description><![CDATA[<p>Ok this post took a bit of inspiration from the C# Markup support that&#8217;s available for the Uno Platform where it&#8217;s easy to build a template selector (for a ListView for example) using a set of Case statements. This got me thinking that there must be a way that we can use a similar technique ... <a title="Conditional Template Selector for XAML Applications for Windows and Uno Platform" class="read-more" href="https://nicksnettravels.builttoroam.com/conditional-template-selector/" aria-label="Read more about Conditional Template Selector for XAML Applications for Windows and Uno Platform">Read more</a></p>
<p>The post <a href="https://nicksnettravels.builttoroam.com/conditional-template-selector/">Conditional Template Selector for XAML Applications for Windows and Uno Platform</a> appeared first on <a href="https://nicksnettravels.builttoroam.com">Nick&#039;s .NET Travels</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>Ok this post took a bit of inspiration from the C# Markup support that&#8217;s available for the <a href="https://platform.uno/dotnettravels-uno">Uno Platform</a> where it&#8217;s easy to build a template selector (for a ListView for example) using a <a href="https://github.com/unoplatform/Uno.Samples/blob/0ec3859a0a496bb33b86323cf0fd922ddfc3c6bd/UI/ChatGPT/ChatGPT/ChatGPT/Presentation/MainPage.cs#L71-L89">set of Case statements</a>. This got me thinking that there must be a way that we can use a similar technique in XAML. Most of the time in XAML when we want to use a template selector, we switch to C#, create a new class that inherits from <a href="https://learn.microsoft.com/en-us/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.datatemplateselector">DataTemplateSelector</a> and would typically expose multiple properties for the different DataTemplates to switch between, and some logic in the SelectTemplateCore method. But what if we could build a generic conditional data template that would allow us to add any number of DataTemplates that would be used for a specific value of a property.</p>



<p>A simple implementation of the <code>ConditionalDataTemplateSelector</code> would be as follows.</p>



<pre class="hljs" style="display: block; overflow-x: auto; padding: 0.5em; background: rgb(255, 255, 255); color: rgb(0, 0, 0);">[ContentProperty(Name = <span class="hljs-keyword" style="color: rgb(0, 0, 255);">nameof</span>(Templates))]
<span class="hljs-keyword" style="color: rgb(0, 0, 255);">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">class</span> <span class="hljs-title" style="color: rgb(163, 21, 21);">ConditionalDataTemplateSelector</span> : <span class="hljs-title" style="color: rgb(163, 21, 21);">DataTemplateSelector</span>
{
    <span class="hljs-keyword" style="color: rgb(0, 0, 255);">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">string</span>? ConditionalProperty { <span class="hljs-keyword" style="color: rgb(0, 0, 255);">get</span>; <span class="hljs-keyword" style="color: rgb(0, 0, 255);">set</span>; }
    <span class="hljs-keyword" style="color: rgb(0, 0, 255);">public</span> IList&lt;ConditionalTemplate&gt; Templates { <span class="hljs-keyword" style="color: rgb(0, 0, 255);">get</span>; } = <span class="hljs-keyword" style="color: rgb(0, 0, 255);">new</span> List&lt;ConditionalTemplate&gt;();

    <span class="hljs-keyword" style="color: rgb(0, 0, 255);">protected</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">override</span> DataTemplate? SelectTemplateCore(<span class="hljs-keyword" style="color: rgb(0, 0, 255);">object</span> item, DependencyObject container)
    {
        <span class="hljs-keyword" style="color: rgb(0, 0, 255);">if</span> (item <span class="hljs-keyword" style="color: rgb(0, 0, 255);">is</span> MainViewModel.Item viewModelItem)
        {
            <span class="hljs-keyword" style="color: rgb(0, 0, 255);">var</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">value</span> = viewModelItem.GetType().GetProperty(ConditionalProperty!)?.GetValue(viewModelItem);
            <span class="hljs-keyword" style="color: rgb(0, 0, 255);">var</span> template = Templates.FirstOrDefault(t =&gt; t.Value <span class="hljs-keyword" style="color: rgb(0, 0, 255);">is</span> not <span class="hljs-literal" style="color: rgb(163, 21, 21);">null</span> &amp;&amp; ( t.Value.Equals(<span class="hljs-keyword" style="color: rgb(0, 0, 255);">value</span>) || t.Value.Equals(<span class="hljs-keyword" style="color: rgb(0, 0, 255);">value</span>+<span class="hljs-keyword" style="color: rgb(0, 0, 255);">string</span>.Empty)))?.ValueTemplate;
            <span class="hljs-keyword" style="color: rgb(0, 0, 255);">return</span> template <span class="hljs-keyword" style="color: rgb(0, 0, 255);">as</span> DataTemplate;
        }

        <span class="hljs-keyword" style="color: rgb(0, 0, 255);">return</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">base</span>.SelectTemplateCore(item, container);
    }
}
[ContentProperty(Name = <span class="hljs-keyword" style="color: rgb(0, 0, 255);">nameof</span>(ValueTemplate))]
<span class="hljs-keyword" style="color: rgb(0, 0, 255);">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">partial</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">class</span> <span class="hljs-title" style="color: rgb(163, 21, 21);">ConditionalTemplate</span>
{
    <span class="hljs-keyword" style="color: rgb(0, 0, 255);">public</span> DataTemplate? ValueTemplate { <span class="hljs-keyword" style="color: rgb(0, 0, 255);">get</span>; <span class="hljs-keyword" style="color: rgb(0, 0, 255);">set</span>; }

    <span class="hljs-keyword" style="color: rgb(0, 0, 255);">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">object</span>? Value { <span class="hljs-keyword" style="color: rgb(0, 0, 255);">get</span>; <span class="hljs-keyword" style="color: rgb(0, 0, 255);">set</span>; }
};</pre>



<p>Here we can see that the <code>ConditionalDataTemplateSelector</code> has two properties:  <code>ConditionalProperty</code> which is the name of the property on the source item to look up the current value, and <code>Templates</code> which is a list of <code>ConditionalTemplate</code>. As we can see from the class definition the <code>ConditionalTemplate</code> has a <code>ValueTemplate</code> property which represents the <code>DataTemplate</code> and a Value property which is the value for which this <code>DataTemplate</code> would be selected.</p>



<p>Ok, this probably sounds all very theoretical, so let&#8217;s see this in action in a simple example. Firstly, some C# that shows the <code>MainViewModel</code>, which exposes an array of <code>Item</code>, which is made up of a <code>Name</code> and <code>Status</code>, where <code>Status</code> is an Enum with values <code>None</code>, <code>Loading </code>and <code>Loaded</code>.</p>



<pre class="hljs" style="display: block; overflow-x: auto; padding: 0.5em; background: rgb(255, 255, 255); color: rgb(0, 0, 0);"><span class="hljs-keyword" style="color: rgb(0, 0, 255);">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">class</span> <span class="hljs-title" style="color: rgb(163, 21, 21);">MainViewModel</span>
{
    <span class="hljs-keyword" style="color: rgb(0, 0, 255);">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">enum</span> Status
    {
        None,
        Loading,
        Loaded
    }

    <span class="hljs-keyword" style="color: rgb(0, 0, 255);">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">class</span> <span class="hljs-title" style="color: rgb(163, 21, 21);">Item</span>
    {
        <span class="hljs-keyword" style="color: rgb(0, 0, 255);">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">string</span>? Name { <span class="hljs-keyword" style="color: rgb(0, 0, 255);">get</span>; <span class="hljs-keyword" style="color: rgb(0, 0, 255);">set</span>; }
        <span class="hljs-keyword" style="color: rgb(0, 0, 255);">public</span> Status Status { <span class="hljs-keyword" style="color: rgb(0, 0, 255);">get</span>; <span class="hljs-keyword" style="color: rgb(0, 0, 255);">set</span>; }
    }

    <span class="hljs-keyword" style="color: rgb(0, 0, 255);">public</span> Item[] Items { <span class="hljs-keyword" style="color: rgb(0, 0, 255);">get</span>; } = [
        <span class="hljs-keyword" style="color: rgb(0, 0, 255);">new</span> Item { Name = <span class="hljs-string" style="color: rgb(163, 21, 21);">"Item 1"</span>, Status = Status.None },
        <span class="hljs-keyword" style="color: rgb(0, 0, 255);">new</span> Item { Name = <span class="hljs-string" style="color: rgb(163, 21, 21);">"Item 2"</span>, Status = Status.Loading },
        <span class="hljs-keyword" style="color: rgb(0, 0, 255);">new</span> Item { Name = <span class="hljs-string" style="color: rgb(163, 21, 21);">"Item 3"</span>, Status = Status.Loaded }
    ];
}</pre>



<p>Now the XAML. Here we are defining three different <code>DataTemplate</code> that are appropriately keyed as <code>NoneTemplate</code>, <code>LoadingTemplate</code> and <code>LoadedTemplate</code>.</p>



<pre class="hljs" style="display: block; overflow-x: auto; padding: 0.5em; background: rgb(255, 255, 255); color: rgb(0, 0, 0);"><span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">Page</span> <span class="hljs-attr" style="color: red;">x:Class</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"DataTemplateSelectorApp.MainPage"</span>
      <span class="hljs-attr" style="color: red;">xmlns</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"http://schemas.microsoft.com/winfx/2006/xaml/presentation"</span>
      <span class="hljs-attr" style="color: red;">xmlns:x</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"http://schemas.microsoft.com/winfx/2006/xaml"</span>
      <span class="hljs-attr" style="color: red;">xmlns:local</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"using:DataTemplateSelectorApp"</span>
      <span class="hljs-attr" style="color: red;">Background</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"{ThemeResource ApplicationPageBackgroundThemeBrush}"</span>&gt;</span>
  <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">Page.Resources</span>&gt;</span>
    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">DataTemplate</span> <span class="hljs-attr" style="color: red;">x:Key</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"NoneTemplate"</span>&gt;</span>
      <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">TextBlock</span> <span class="hljs-attr" style="color: red;">Text</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"None"</span>/&gt;</span>
    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">DataTemplate</span>&gt;</span>
    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">DataTemplate</span> <span class="hljs-attr" style="color: red;">x:Key</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"LoadingTemplate"</span>&gt;</span>
      <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">TextBlock</span> <span class="hljs-attr" style="color: red;">Text</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Loading...."</span>/&gt;</span>
    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">DataTemplate</span>&gt;</span>
    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">DataTemplate</span> <span class="hljs-attr" style="color: red;">x:Key</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"LoadedTemplate"</span>&gt;</span>
      <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">TextBlock</span> <span class="hljs-attr" style="color: red;">Text</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"{Binding Name}"</span>/&gt;</span>
    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">DataTemplate</span>&gt;</span>
    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">local:ConditionalDataTemplateSelector</span>
      <span class="hljs-attr" style="color: red;">x:Key</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"ConditionalSelector"</span>
      <span class="hljs-attr" style="color: red;">ConditionalProperty</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Status"</span>&gt;</span>
      <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">local:ConditionalTemplate</span>
        <span class="hljs-attr" style="color: red;">ValueTemplate</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"{StaticResource NoneTemplate}"</span>
        <span class="hljs-attr" style="color: red;">Value</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"None"</span> /&gt;</span>
      <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">local:ConditionalTemplate</span>
        <span class="hljs-attr" style="color: red;">ValueTemplate</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"{StaticResource LoadingTemplate}"</span>
        <span class="hljs-attr" style="color: red;">Value</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Loading"</span> /&gt;</span>
      <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">local:ConditionalTemplate</span>
        <span class="hljs-attr" style="color: red;">ValueTemplate</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"{StaticResource LoadedTemplate}"</span>
        <span class="hljs-attr" style="color: red;">Value</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Loaded"</span> /&gt;</span>
    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">local:ConditionalDataTemplateSelector</span>&gt;</span>
  <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">Page.Resources</span>&gt;</span>

  <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">ListView</span> <span class="hljs-attr" style="color: red;">ItemsSource</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"{Binding Items}"</span>
            <span class="hljs-attr" style="color: red;">ItemTemplateSelector</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"{StaticResource ConditionalSelector}"</span>/&gt;</span>
<span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">Page</span>&gt;</span>
</pre>



<p>The <code>ConditionalDataTemplateSelector</code> resource specifies the <code>Status</code> property to be inspected on each element and then for each <code>ConditionalTemplate</code> a corresponding <code>Value</code> is specified. As the <code>ListView</code> renders each item in the <code>Items</code> array, the <code>ConditionalSelector</code> will be invoked. The <code>Status</code> property on the <code>Item</code> will be inspected and the value compared to the <code>Value</code> of each <code>ConditionalTemplate</code>. If there&#8217;s a match, the corresponding DataTemplate will be returned.</p>



<p>Here&#8217;s a rather uninspiring picture of this sample app running, showing each of the three DataTemplate being returned.</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image-65efc2c647751.png"><img loading="lazy" decoding="async" width="300" height="257" src="https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image-65efc2c647751-300x257.png" alt="" class="wp-image-3182" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image-65efc2c647751-300x257.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image-65efc2c647751.png 304w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>As we&#8217;ve seen in this post it is possible to build a generic template selector that is able to pick between any number of templates based on some conditional value. The only downside with this implementation is that it does leverage reflection at runtime to retrieve the value on the bound object. I&#8217;m sure that it would be possible using source code generation to generate strongly typed code that would replace the reflection based implementation.</p>
<p>The post <a href="https://nicksnettravels.builttoroam.com/conditional-template-selector/">Conditional Template Selector for XAML Applications for Windows and Uno Platform</a> appeared first on <a href="https://nicksnettravels.builttoroam.com">Nick&#039;s .NET Travels</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://nicksnettravels.builttoroam.com/conditional-template-selector/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title>Using ChatGPT and GitHub Copilot to Generate the XAML for your Windows application</title>
		<link>https://nicksnettravels.builttoroam.com/chatgpt-copilot-xaml/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=chatgpt-copilot-xaml</link>
					<comments>https://nicksnettravels.builttoroam.com/chatgpt-copilot-xaml/#comments</comments>
		
		<dc:creator><![CDATA[Nick]]></dc:creator>
		<pubDate>Sun, 03 Mar 2024 15:43:18 +0000</pubDate>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[AI]]></category>
		<category><![CDATA[Copilot]]></category>
		<category><![CDATA[GitHub]]></category>
		<category><![CDATA[Uno Platform]]></category>
		<category><![CDATA[Windows App SDK]]></category>
		<category><![CDATA[Windows UI]]></category>
		<category><![CDATA[WinUI]]></category>
		<category><![CDATA[XAML]]></category>
		<guid isPermaLink="false">https://nicksnettravels.builttoroam.com/?p=3160</guid>

					<description><![CDATA[<p>In this post I&#8217;m going to experiment using ChatGPT and Copilot to help generate the XAML for pages in a Windows application. Since we&#8217;ll be using WinUI and the Windows App SDK, the application can be extended to support other platforms via the&#160;Uno Platform.&#160; ChatGPT We&#8217;ll start by using ChatGPT (in this case ChatGPT v3.5) ... <a title="Using ChatGPT and GitHub Copilot to Generate the XAML for your Windows application" class="read-more" href="https://nicksnettravels.builttoroam.com/chatgpt-copilot-xaml/" aria-label="Read more about Using ChatGPT and GitHub Copilot to Generate the XAML for your Windows application">Read more</a></p>
<p>The post <a href="https://nicksnettravels.builttoroam.com/chatgpt-copilot-xaml/">Using ChatGPT and GitHub Copilot to Generate the XAML for your Windows application</a> appeared first on <a href="https://nicksnettravels.builttoroam.com">Nick&#039;s .NET Travels</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>In this post I&#8217;m going to experiment using ChatGPT and Copilot to help generate the XAML for pages in a Windows application. Since we&#8217;ll be using WinUI and the Windows App SDK, the application can be extended to support other platforms via the&nbsp;<a href="https://platform.uno/dotnettravels-uno">Uno Platform</a>.&nbsp;</p>



<h2 class="wp-block-heading">ChatGPT</h2>



<p>We&#8217;ll start by using ChatGPT (in this case ChatGPT v3.5) and use the following prompt:</p>



<p><em>You&#8217;re a XAML source code generator for building applications using the Windows App SDK and Windows UI. Generate XAML code the a page that shows a Login prompt made up of a username and password and remeber me fields</em></p>



<p>ChatGPT responds with XAML as shown in the following image.</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image-65e4925bee110.png"><img loading="lazy" decoding="async" width="300" height="298" src="https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image-65e4925bee110-300x298.png" alt="" class="wp-image-3162" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image-65e4925bee110-300x298.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image-65e4925bee110-1024x1016.png 1024w, https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image-65e4925bee110-150x150.png 150w, https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image-65e4925bee110-768x762.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image-65e4925bee110-1536x1524.png 1536w, https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image-65e4925bee110.png 1552w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>This can either be added to an existing application as a new page, of in my case I copied everything except the outer <code>Page</code> element and inserted it into the <code>Window</code> of a blank application.</p>



<pre class="hljs" style="display: block; overflow-x: auto; padding: 0.5em; background: rgb(255, 255, 255); color: rgb(0, 0, 0);"><span class="php"><span class="hljs-meta" style="color: rgb(43, 145, 175);">&lt;?</span>xml version=<span class="hljs-string" style="color: rgb(163, 21, 21);">"1.0"</span> encoding=<span class="hljs-string" style="color: rgb(163, 21, 21);">"utf-8"</span><span class="hljs-meta" style="color: rgb(43, 145, 175);">?&gt;</span></span>
<span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">Window</span>
    <span class="hljs-attr" style="color: red;">x:Class</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"App5.MainWindow"</span>
    <span class="hljs-attr" style="color: red;">xmlns</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"http://schemas.microsoft.com/winfx/2006/xaml/presentation"</span>
    <span class="hljs-attr" style="color: red;">xmlns:x</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"http://schemas.microsoft.com/winfx/2006/xaml"</span>
    <span class="hljs-attr" style="color: red;">xmlns:local</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"using:App5"</span>
    <span class="hljs-attr" style="color: red;">xmlns:d</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"http://schemas.microsoft.com/expression/blend/2008"</span>
    <span class="hljs-attr" style="color: red;">xmlns:mc</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"http://schemas.openxmlformats.org/markup-compatibility/2006"</span>
    <span class="hljs-attr" style="color: red;">mc:Ignorable</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"d"</span>&gt;</span>

    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">StackPanel</span> <span class="hljs-attr" style="color: red;">VerticalAlignment</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Center"</span> <span class="hljs-attr" style="color: red;">HorizontalAlignment</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Center"</span>&gt;</span>
        <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">TextBlock</span> <span class="hljs-attr" style="color: red;">Text</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Login"</span> <span class="hljs-attr" style="color: red;">FontSize</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"24"</span> <span class="hljs-attr" style="color: red;">Margin</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"0,0,0,20"</span>/&gt;</span>

        <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">StackPanel</span> <span class="hljs-attr" style="color: red;">Orientation</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Horizontal"</span> <span class="hljs-attr" style="color: red;">Margin</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"0,0,0,10"</span>&gt;</span>
            <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">TextBlock</span> <span class="hljs-attr" style="color: red;">Text</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Username:"</span> <span class="hljs-attr" style="color: red;">VerticalAlignment</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Center"</span> <span class="hljs-attr" style="color: red;">Margin</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"0,0,10,0"</span>/&gt;</span>
            <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">TextBox</span> <span class="hljs-attr" style="color: red;">x:Name</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"UsernameTextBox"</span> <span class="hljs-attr" style="color: red;">PlaceholderText</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Enter your username"</span>/&gt;</span>
        <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">StackPanel</span>&gt;</span>

        <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">StackPanel</span> <span class="hljs-attr" style="color: red;">Orientation</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Horizontal"</span> <span class="hljs-attr" style="color: red;">Margin</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"0,0,0,10"</span>&gt;</span>
            <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">TextBlock</span> <span class="hljs-attr" style="color: red;">Text</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Password:"</span> <span class="hljs-attr" style="color: red;">VerticalAlignment</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Center"</span> <span class="hljs-attr" style="color: red;">Margin</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"0,0,10,0"</span>/&gt;</span>
            <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">PasswordBox</span> <span class="hljs-attr" style="color: red;">x:Name</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"PasswordBox"</span> <span class="hljs-attr" style="color: red;">PlaceholderText</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Enter your password"</span>/&gt;</span>
        <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">StackPanel</span>&gt;</span>

        <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">CheckBox</span> <span class="hljs-attr" style="color: red;">x:Name</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"RememberMeCheckBox"</span> <span class="hljs-attr" style="color: red;">Content</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Remember me"</span> <span class="hljs-attr" style="color: red;">Margin</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"0,0,0,10"</span>/&gt;</span>

        <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;<span class="hljs-name" style="color: rgb(0, 0, 255);">Button</span> <span class="hljs-attr" style="color: red;">Content</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Login"</span> <span class="hljs-attr" style="color: red;">Click</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"LoginButton_Click"</span> <span class="hljs-attr" style="color: red;">Width</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"100"</span> <span class="hljs-attr" style="color: red;">HorizontalAlignment</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Center"</span>/&gt;</span>
    <span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">StackPanel</span>&gt;</span>
<span class="hljs-tag" style="color: rgb(0, 0, 255);">&lt;/<span class="hljs-name" style="color: rgb(0, 0, 255);">Window</span>&gt;</span>
</pre>



<p>I already had the application running, so when I hit save (I also needed to create the <code>LoginButton_Click</code> event handler in the code behind file) it refreshed the UI of the running application.</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image-65e4921ed778a.png"><img loading="lazy" decoding="async" width="283" height="300" src="https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image-65e4921ed778a-283x300.png" alt="" class="wp-image-3161" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image-65e4921ed778a-283x300.png 283w, https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image-65e4921ed778a.png 454w" sizes="auto, (max-width: 283px) 100vw, 283px" /></a></figure>



<h2 class="wp-block-heading">GitHub Copilot for Visual Studio</h2>



<p>To use GitHub Copilot from within Visual Studio you&#8217;ll need to install the extension via the Extension Manager.</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image-65e49810da44a.png"><img loading="lazy" decoding="async" width="300" height="192" src="https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image-65e49810da44a-300x192.png" alt="" class="wp-image-3164" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image-65e49810da44a-300x192.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image-65e49810da44a-1024x656.png 1024w, https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image-65e49810da44a-768x492.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image-65e49810da44a.png 1314w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>Once install, GitHub Copilot will volunteer suggestions as you type. It will also respond to prompts entered via comments. Let&#8217;s see this in action, starting with a blank application.</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image-65e49897eaea4.png"><img loading="lazy" decoding="async" width="300" height="218" src="https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image-65e49897eaea4-300x218.png" alt="" class="wp-image-3165" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image-65e49897eaea4-300x218.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image-65e49897eaea4-1024x745.png 1024w, https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image-65e49897eaea4-768x558.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image-65e49897eaea4.png 1096w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>Let&#8217;s use a similar prompt to the one we used with ChatGPT entered as a XAML comment:</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image-65e498e37d1a7.png"><img loading="lazy" decoding="async" width="300" height="73" src="https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image-65e498e37d1a7-300x73.png" alt="" class="wp-image-3166" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image-65e498e37d1a7-300x73.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image-65e498e37d1a7-1024x250.png 1024w, https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image-65e498e37d1a7-768x187.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image-65e498e37d1a7-1536x375.png 1536w, https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image-65e498e37d1a7.png 1639w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>Press Enter to move to the next line and wait a second or two and GitHub Copilot will kick in and offer a suggestion for XAML</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image-65e4994183122.png"><img loading="lazy" decoding="async" width="300" height="146" src="https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image-65e4994183122-300x146.png" alt="" class="wp-image-3167" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image-65e4994183122-300x146.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image-65e4994183122-1024x500.png 1024w, https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image-65e4994183122-768x375.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image-65e4994183122-1536x749.png 1536w, https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image-65e4994183122.png 1646w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>Press Tab to insert the suggested XAML. Repeat this again to have Copilot suggest the closing <code>Grid </code>tag and then save the file in order to trigger hot reload.</p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image-65e499ca905d7.png"><img loading="lazy" decoding="async" width="300" height="161" src="https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image-65e499ca905d7-300x161.png" alt="" class="wp-image-3168" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image-65e499ca905d7-300x161.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image-65e499ca905d7-1024x550.png 1024w, https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image-65e499ca905d7-768x412.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image-65e499ca905d7-1536x825.png 1536w, https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image-65e499ca905d7.png 1637w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<h2 class="wp-block-heading">Summary</h2>



<p>What was interesting about this experiment was that despite GitHub Copilot being optimised for developer tasks, the generated UI wasn&#8217;t as good as the UI generated using ChatGPT. I wasn&#8217;t able to try v4 of ChatGPT but I can only imagine that the generation has improved even more. </p>



<p>What&#8217;s interesting about this simple eperiment is that is that it shows the potential for generative AI to really accelerate application development.</p>
<p>The post <a href="https://nicksnettravels.builttoroam.com/chatgpt-copilot-xaml/">Using ChatGPT and GitHub Copilot to Generate the XAML for your Windows application</a> appeared first on <a href="https://nicksnettravels.builttoroam.com">Nick&#039;s .NET Travels</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://nicksnettravels.builttoroam.com/chatgpt-copilot-xaml/feed/</wfw:commentRss>
			<slash:comments>4</slash:comments>
		
		
			</item>
		<item>
		<title>Designing and Building Windows Applications using Figma and the Uno Platform</title>
		<link>https://nicksnettravels.builttoroam.com/figma-tools/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=figma-tools</link>
					<comments>https://nicksnettravels.builttoroam.com/figma-tools/#comments</comments>
		
		<dc:creator><![CDATA[Nick]]></dc:creator>
		<pubDate>Sat, 02 Mar 2024 15:55:05 +0000</pubDate>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[Design]]></category>
		<category><![CDATA[Figma]]></category>
		<category><![CDATA[Uno Platform]]></category>
		<category><![CDATA[Windows]]></category>
		<category><![CDATA[Windows App SDK]]></category>
		<category><![CDATA[WinUI]]></category>
		<guid isPermaLink="false">https://nicksnettravels.builttoroam.com/?p=3144</guid>

					<description><![CDATA[<p>Last week, the Uno Platform officially launched their Figma Plugin which works in parity with the Uno Platform Material Toolkit to support both designers and developers with the process of designing applications. If you haven&#8217;t already, check out the announcement post that provides a high level overview of both the plugin and toolkit. In this post we&#8217;ll ... <a title="Designing and Building Windows Applications using Figma and the Uno Platform" class="read-more" href="https://nicksnettravels.builttoroam.com/figma-tools/" aria-label="Read more about Designing and Building Windows Applications using Figma and the Uno Platform">Read more</a></p>
<p>The post <a href="https://nicksnettravels.builttoroam.com/figma-tools/">Designing and Building Windows Applications using Figma and the Uno Platform</a> appeared first on <a href="https://nicksnettravels.builttoroam.com">Nick&#039;s .NET Travels</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>Last week, the <a href="https://platform.uno/dotnettravels-uno">Uno Platform</a> officially launched their <a href="https://www.figma.com/community/plugin/1045528009520465828/uno-platform-figma-to-c-or-xaml">Figma Plugin</a> which works in parity with the <a href="https://www.figma.com/community/file/1110792522046146058/uno-platform-material-toolkit">Uno Platform Material Toolkit</a> to support both designers and developers with the process of designing applications. If you haven&#8217;t already, check out the <a href="https://platform.uno/blog/uno-platform-for-figma-plugin-rtm/">announcement post</a> that provides a high level overview of both the plugin and toolkit. In this post we&#8217;ll dig deeper into both so you can understand why you might want to use these tools for building either a Windows or a cross platform Uno Application.</p>



<h2 class="wp-block-heading">Uno Platform Material Toolkit</h2>



<p>Whilst a lot of the magic of Figma tooling offered by the Uno Platform comes via the plugin, for example the generation of XAML and C# Markup that can be exported, the value of the Material Toolkit shouldn&#8217;t be underestimated. The Uno Platform Material Toolkit isn&#8217;t alone in the Figma community when it comes to design files that provide a starting point for designing applications that use the Material design language. However, what differentiates it, is that the implementation of Material styles has been done in a way that XAML and C# Markup can be generated that is compatible with WinUI and the Uno Platform. The point is, if you&#8217;re looking to use Figma to design a Windows or Uno Platform application, you should start with the Uno Platform Material Toolkit.</p>



<h3 class="wp-block-heading">Example App</h3>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image.png"><img loading="lazy" decoding="async" width="300" height="181" src="https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image-300x181.png" alt="" class="wp-image-3146" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image-300x181.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image-1024x618.png 1024w, https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image-768x463.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image.png 1033w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>The first page in the Uno Platform Material Toolkit in an Example App that shows a number of sample pages of a retail application. This is similiar to the <a href="https://github.com/unoplatform/Uno.Samples/tree/master/reference/Commerce">Commerce sample</a> application that you can find in the Uno.Samples repository.</p>



<p>On the left, you can follow the instructions to install the Uno Platform Figma Plugin, which we&#8217;ll cover in more detail a bit later. If you make changes to the theme/styles, you can return to the Example App and see how the changes are applied.</p>



<h3 class="wp-block-heading">Getting Started</h3>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image-65e341937bb0f.png"><img loading="lazy" decoding="async" width="300" height="185" src="https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image-65e341937bb0f-300x185.png" alt="" class="wp-image-3147" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image-65e341937bb0f-300x185.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image-65e341937bb0f-1024x630.png 1024w, https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image-65e341937bb0f-768x473.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image-65e341937bb0f.png 1209w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>On the Getting Started page you can read through the guidance on how to get the most out of the Uno Platform Material Toolkit. Take the time to read each section and try out things like modifying colors or trying out different fonts.</p>



<h3 class="wp-block-heading">Themes</h3>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="652" src="https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image-65e342ba83d8e-1024x652.png" alt="" class="wp-image-3148" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image-65e342ba83d8e-1024x652.png 1024w, https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image-65e342ba83d8e-300x191.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image-65e342ba83d8e-768x489.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image-65e342ba83d8e-1536x978.png 1536w, https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image-65e342ba83d8e.png 1604w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p>To make changes to the theme used in the Uno Platform Material Toolkit open the Themes page which shows the colors, typography, elevations, icons, app icons and images. These can be accessed individually from the appropriate section, or you can see them in the context on the Preview section.</p>



<h3 class="wp-block-heading">Components</h3>



<figure class="wp-block-image size-medium"><img loading="lazy" decoding="async" width="226" height="300" src="https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image-65e343b10f9bc-226x300.png" alt="" class="wp-image-3149" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image-65e343b10f9bc-226x300.png 226w, https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image-65e343b10f9bc-770x1024.png 770w, https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image-65e343b10f9bc-768x1022.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image-65e343b10f9bc.png 1008w" sizes="auto, (max-width: 226px) 100vw, 226px" /></figure>



<p>The Components page include the standard controls, such as Button and TextBlock, that are used to make up most applications. From the index page, you can quickly jump to the appropriate section for the control your interested in. </p>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image-65e3443d14eee.png"><img loading="lazy" decoding="async" width="272" height="300" src="https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image-65e3443d14eee-272x300.png" alt="" class="wp-image-3150" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image-65e3443d14eee-272x300.png 272w, https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image-65e3443d14eee-927x1024.png 927w, https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image-65e3443d14eee-768x848.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image-65e3443d14eee.png 1218w" sizes="auto, (max-width: 272px) 100vw, 272px" /></a></figure>



<p>As you can see from the Button section shown in the above image, each section not only shows the   control, it also shows all the variants for the control.</p>



<h3 class="wp-block-heading">Templates</h3>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image-65e344c460e03.png"><img loading="lazy" decoding="async" width="207" height="300" src="https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image-65e344c460e03-207x300.png" alt="" class="wp-image-3151" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image-65e344c460e03-207x300.png 207w, https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image-65e344c460e03-706x1024.png 706w, https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image-65e344c460e03-768x1113.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image-65e344c460e03.png 776w" sizes="auto, (max-width: 207px) 100vw, 207px" /></a></figure>



<p>The Templates page provides high level templates for Pages, Cards, Forms, Lists and more. </p>



<h3 class="wp-block-heading">Other Pages</h3>



<p>The remaining pages in the Uno Platform Material Toolkit include the Cover, a Changelog, Feedback and Credits.</p>



<h2 class="wp-block-heading">Uno Platform Figma to C# or XAML Plugin</h2>



<p>The Uno Platform Figma Plugin is a contextually aware plugin that&#8217;s used to preview and export either C# or XAML from a Figma file derived from the Uno Platform Material Toolkit. By this I mean that as you change the selected page and layer you can preview and export the current selection. </p>



<h3 class="wp-block-heading">Preview</h3>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image-65e34666a2393.png"><img loading="lazy" decoding="async" width="300" height="191" src="https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image-65e34666a2393-300x191.png" alt="" class="wp-image-3153" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image-65e34666a2393-300x191.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image-65e34666a2393-1024x654.png 1024w, https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image-65e34666a2393-768x490.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image-65e34666a2393-1536x980.png 1536w, https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image-65e34666a2393.png 1728w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>The first tab in the plugin is the Preview tab where you can see how the currently selected application page will appear when it&#8217;s running inside an Uno Platform application. Because the Figma Plugin is an Uno Platform application running in WASM, the Figma design is exported to XAML and which is then parsed and displayed within the application &#8211; this makes the preview as close as possible to what you would see if you exported the design into a separate Uno Platform application. </p>



<p>The Preview tab also supports switching between Dark and Light themes, as shown in the image above.</p>



<h3 class="wp-block-heading">Export</h3>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image-65e346f42e517.png"><img loading="lazy" decoding="async" width="300" height="191" src="https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image-65e346f42e517-300x191.png" alt="" class="wp-image-3154" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image-65e346f42e517-300x191.png 300w, https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image-65e346f42e517-1024x654.png 1024w, https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image-65e346f42e517-768x490.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image-65e346f42e517-1536x980.png 1536w, https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image-65e346f42e517.png 1728w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></figure>



<p>The Export tab allows for generation of XAML or C# Markup that can be copied into an Uno Platform application (which includes any Windows application built with WinUI and the Windows App SDK).</p>



<h3 class="wp-block-heading">Properties</h3>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image-65e34729b8999.png"><img loading="lazy" decoding="async" width="235" height="300" src="https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image-65e34729b8999-235x300.png" alt="" class="wp-image-3155" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image-65e34729b8999-235x300.png 235w, https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image-65e34729b8999-802x1024.png 802w, https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image-65e34729b8999-768x981.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image-65e34729b8999.png 860w" sizes="auto, (max-width: 235px) 100vw, 235px" /></a></figure>



<p>From the Properies tab it&#8217;s possible to set data binding and other page specific properties. The Application properties can be used to set the namespace used when exporting code.</p>



<h3 class="wp-block-heading">Data Context</h3>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image-65e347506b115.png"><img loading="lazy" decoding="async" width="235" height="300" src="https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image-65e347506b115-235x300.png" alt="" class="wp-image-3156" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image-65e347506b115-235x300.png 235w, https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image-65e347506b115-802x1024.png 802w, https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image-65e347506b115-768x981.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image-65e347506b115.png 861w" sizes="auto, (max-width: 235px) 100vw, 235px" /></a></figure>



<p>In order for the Preview tab to show a meaning full representation of the design, it&#8217;s useful to specify design time data in JSON via the Data Context tab. You can see in this image an array of items with a Key of Products. In the earlier image of the properties, you can see a data binding expression of Products &#8211; this is how the preview shows a list of products.</p>



<h3 class="wp-block-heading">Console</h3>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image-65e3477423eed.png"><img loading="lazy" decoding="async" width="235" height="300" src="https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image-65e3477423eed-235x300.png" alt="" class="wp-image-3157" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image-65e3477423eed-235x300.png 235w, https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image-65e3477423eed-803x1024.png 803w, https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image-65e3477423eed-768x979.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image-65e3477423eed.png 862w" sizes="auto, (max-width: 235px) 100vw, 235px" /></a></figure>



<p>If the Preview or Export tab isn&#8217;t working, it may be necessary to check out the Console to see if there are any errors.</p>



<h3 class="wp-block-heading">Settings</h3>



<figure class="wp-block-image size-medium"><a href="https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image-65e34796c08cf.png"><img loading="lazy" decoding="async" width="235" height="300" src="https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image-65e34796c08cf-235x300.png" alt="" class="wp-image-3158" srcset="https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image-65e34796c08cf-235x300.png 235w, https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image-65e34796c08cf-801x1024.png 801w, https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image-65e34796c08cf-768x982.png 768w, https://wordpressblogimages.builttoroam.com/blogimages/2024/03/image-65e34796c08cf.png 862w" sizes="auto, (max-width: 235px) 100vw, 235px" /></a></figure>



<p>The Settings tab can be used to adjust aspects of the behavior of the plugin. For example, toggling the Binding setting will control whether binding expressions are exported in the XAML or C# Markup.</p>



<h2 class="wp-block-heading">Summary</h2>



<p>In this post we&#8217;ve covered the main screens/tabs of the Uno Platform Material Tookit and the Uno Platform Figma Plugin. Hopefully this will provide you the basis to take a look at these tools and see how you can use them to help you design and build applications for Windows and other platforms using the Uno Platform.</p>
<p>The post <a href="https://nicksnettravels.builttoroam.com/figma-tools/">Designing and Building Windows Applications using Figma and the Uno Platform</a> appeared first on <a href="https://nicksnettravels.builttoroam.com">Nick&#039;s .NET Travels</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://nicksnettravels.builttoroam.com/figma-tools/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
	</channel>
</rss>