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

<channel>
	<title>Cross-Platform &#8211; Xojo Programming Blog</title>
	<atom:link href="https://blog.xojo.com/category/cross-platform/feed/" rel="self" type="application/rss+xml" />
	<link>https://blog.xojo.com</link>
	<description>Blog about the Xojo programming language and IDE</description>
	<lastBuildDate>Thu, 29 Oct 2026 17:03:14 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.11</generator>
	<item>
		<title>DesktopTable Cell Popover</title>
		<link>https://blog.xojo.com/2026/10/29/desktop-table-cell-popover/</link>
		
		<dc:creator><![CDATA[Wayne Golding]]></dc:creator>
		<pubDate>Thu, 29 Oct 2026 16:37:33 +0000</pubDate>
				<category><![CDATA[Desktop]]></category>
		<category><![CDATA[General]]></category>
		<category><![CDATA[DesktopTable]]></category>
		<category><![CDATA[Xojo Programming Language]]></category>
		<guid isPermaLink="false">https://blog.xojo.com/?p=16743</guid>

					<description><![CDATA[In this post, I&#8217;ll show you how to anchor a popover to a specific DesktopTable cell using CellBoundsAt so you can display full cell text&#8230;]]></description>
										<content:encoded><![CDATA[
<p>In this post, I&#8217;ll show you how to anchor a popover to a specific DesktopTable cell using CellBoundsAt so you can display full cell text (even when the cell can&#8217;t fit it) with correct positioning across macOS and Windows.</p>



<p>Popovers anchor to a control, not a location, which has been somewhat tricky to do in the past. DesktopTable has a CellBoundsAt method which returns a Rect containing the selected cell&#8217;s geometry and position relative to the table control’s location on its parent. This allows us to anchor the popover container to an individual cell.</p>



<figure class="wp-block-image size-full"><img fetchpriority="high" decoding="async" width="890" height="626" src="https://blog.xojo.com/wp-content/uploads/2026/10/image.png" alt="" class="wp-image-16744" srcset="https://blog.xojo.com/wp-content/uploads/2026/10/image.png 890w, https://blog.xojo.com/wp-content/uploads/2026/10/image-300x211.png 300w, https://blog.xojo.com/wp-content/uploads/2026/10/image-768x540.png 768w" sizes="(max-width: 890px) 100vw, 890px" /></figure>



<p>This is useful when you need to show the full contents of a cell whose displayed area can’t fit the underlying data.</p>



<p>In this example, the popover container is intentionally simple &#8211; it is a TextArea sized to fill the container.&nbsp; The container is named PopOverContainer. The Window includes a property named AnchorControl As DesktopRectangle that we&#8217;ll use as the popover&#8217;s anchor.</p>



<p>In the Window Opening event, we initialize the anchor rectangle:</p>



<pre class="wp-block-code"><code>Sub Opening() Handles Opening
&nbsp; AnchorControl = New DesktopRectangle
&nbsp; Window1.AddControl(AnchorControl)
&nbsp; AnchorControl.BorderThickness = 0.0
&nbsp; AnchorControl.FillColor = &amp;c000000FF ' Transparent on MacOS, Window background color on Windows

End Sub</code></pre>



<p>This initializes the rectangle that we will anchor the popover to.</p>



<p>Lastly the CellPressed Event Hanlder:</p>



<pre class="wp-block-code"><code>Function CellPressed(row As Integer, column As Integer, x As Integer, y As Integer) Handles CellPressed as Boolean
&nbsp; #Pragma Unused x
&nbsp; #Pragma Unused y
&nbsp; If column &lt;&gt; 1 Then ' We only want the popover to show on Column 1
&nbsp; &nbsp; Return False
&nbsp; End If
&nbsp;&nbsp;
  // Move the Anchor control to the selected cell position.
&nbsp; AnchorControl.Left = me.CellBoundsAt(row, column).Left + me.Left
&nbsp; AnchorControl.Top = me.CellBoundsAt(row, column).Top + me.Top + me.CellBoundsAt(row, column).Height ' I want the popover to anchor to the bottom of the control
&nbsp; AnchorControl.Width = me.CellBoundsAt(row, column).Width
&nbsp; AnchorControl.Height = If(TargetWindows, 0, 1) ' Windows can handle 0 height, MacOS doesn't &nbsp;

  // Now that we have an anchor point at the correct location we can popover

&nbsp; Var poc As New PopOverContainer

&nbsp; poc.TextArea1.Text = me.CellTextAt(row, column)

&nbsp; poc.ShowPopover(AnchorControl, DesktopContainer.DisplaySides.Bottom)
  Return True
End Function</code></pre>



<h3 class="wp-block-heading">Cross-platform Adjustments </h3>



<p>Some adjustments will need to be made for the different ways targets handle transparency.&nbsp; Windows doesn’t visually render transparent controls in the same way macOS does, and macOS may require the anchor control to occupy a space.&nbsp; By setting the anchor height appropriately, we can ensure the popover is positioned correctly on both platforms. </p>



<p><a href="https://blog.xojo.com/wp-content/uploads/2026/10/Table-Cell-Pop-over.xojo_binary_project.zip">Download the project</a>.</p>



<p><em>Wayne Golding has been a Xojo developer since 2005 and is a Xojo MVP. He operates the IT Company <a href="http://www.axisdirect.nz">Axis Direct Ltd </a>which primarily develops applications using Xojo that integrate with Xero www.xero.com. Wayne’s hobby is robotics where he uses Xojo to build applications for his Raspberry Pi, often implementing IoT for remote control.</em></p>



<ul class="wp-block-social-links has-normal-icon-size is-content-justification-center is-layout-flex wp-container-core-social-links-is-layout-16018d1d wp-block-social-links-is-layout-flex"><li class="wp-social-link wp-social-link-facebook  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.facebook.com/goxojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M12 2C6.5 2 2 6.5 2 12c0 5 3.7 9.1 8.4 9.9v-7H7.9V12h2.5V9.8c0-2.5 1.5-3.9 3.8-3.9 1.1 0 2.2.2 2.2.2v2.5h-1.3c-1.2 0-1.6.8-1.6 1.6V12h2.8l-.4 2.9h-2.3v7C18.3 21.1 22 17 22 12c0-5.5-4.5-10-10-10z"></path></svg><span class="wp-block-social-link-label screen-reader-text">Facebook</span></a></li>

<li class="wp-social-link wp-social-link-x  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://x.com/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M13.982 10.622 20.54 3h-1.554l-5.693 6.618L8.745 3H3.5l6.876 10.007L3.5 21h1.554l6.012-6.989L15.868 21h5.245l-7.131-10.378Zm-2.128 2.474-.697-.997-5.543-7.93H8l4.474 6.4.697.996 5.815 8.318h-2.387l-4.745-6.787Z" /></svg><span class="wp-block-social-link-label screen-reader-text">X</span></a></li>

<li class="wp-social-link wp-social-link-linkedin  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.linkedin.com/company/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M19.7,3H4.3C3.582,3,3,3.582,3,4.3v15.4C3,20.418,3.582,21,4.3,21h15.4c0.718,0,1.3-0.582,1.3-1.3V4.3 C21,3.582,20.418,3,19.7,3z M8.339,18.338H5.667v-8.59h2.672V18.338z M7.004,8.574c-0.857,0-1.549-0.694-1.549-1.548 c0-0.855,0.691-1.548,1.549-1.548c0.854,0,1.547,0.694,1.547,1.548C8.551,7.881,7.858,8.574,7.004,8.574z M18.339,18.338h-2.669 v-4.177c0-0.996-0.017-2.278-1.387-2.278c-1.389,0-1.601,1.086-1.601,2.206v4.249h-2.667v-8.59h2.559v1.174h0.037 c0.356-0.675,1.227-1.387,2.526-1.387c2.703,0,3.203,1.779,3.203,4.092V18.338z"></path></svg><span class="wp-block-social-link-label screen-reader-text">LinkedIn</span></a></li>

<li class="wp-social-link wp-social-link-github  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://github.com/topics/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M12,2C6.477,2,2,6.477,2,12c0,4.419,2.865,8.166,6.839,9.489c0.5,0.09,0.682-0.218,0.682-0.484 c0-0.236-0.009-0.866-0.014-1.699c-2.782,0.602-3.369-1.34-3.369-1.34c-0.455-1.157-1.11-1.465-1.11-1.465 c-0.909-0.62,0.069-0.608,0.069-0.608c1.004,0.071,1.532,1.03,1.532,1.03c0.891,1.529,2.341,1.089,2.91,0.833 c0.091-0.647,0.349-1.086,0.635-1.337c-2.22-0.251-4.555-1.111-4.555-4.943c0-1.091,0.39-1.984,1.03-2.682 C6.546,8.54,6.202,7.524,6.746,6.148c0,0,0.84-0.269,2.75,1.025C10.295,6.95,11.15,6.84,12,6.836 c0.85,0.004,1.705,0.114,2.504,0.336c1.909-1.294,2.748-1.025,2.748-1.025c0.546,1.376,0.202,2.394,0.1,2.646 c0.64,0.699,1.026,1.591,1.026,2.682c0,3.841-2.337,4.687-4.565,4.935c0.359,0.307,0.679,0.917,0.679,1.852 c0,1.335-0.012,2.415-0.012,2.741c0,0.269,0.18,0.579,0.688,0.481C19.138,20.161,22,16.416,22,12C22,6.477,17.523,2,12,2z"></path></svg><span class="wp-block-social-link-label screen-reader-text">GitHub</span></a></li>

<li class="wp-social-link wp-social-link-youtube  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.youtube.com/c/XojoInc" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M21.8,8.001c0,0-0.195-1.378-0.795-1.985c-0.76-0.797-1.613-0.801-2.004-0.847c-2.799-0.202-6.997-0.202-6.997-0.202 h-0.009c0,0-4.198,0-6.997,0.202C4.608,5.216,3.756,5.22,2.995,6.016C2.395,6.623,2.2,8.001,2.2,8.001S2,9.62,2,11.238v1.517 c0,1.618,0.2,3.237,0.2,3.237s0.195,1.378,0.795,1.985c0.761,0.797,1.76,0.771,2.205,0.855c1.6,0.153,6.8,0.201,6.8,0.201 s4.203-0.006,7.001-0.209c0.391-0.047,1.243-0.051,2.004-0.847c0.6-0.607,0.795-1.985,0.795-1.985s0.2-1.618,0.2-3.237v-1.517 C22,9.62,21.8,8.001,21.8,8.001z M9.935,14.594l-0.001-5.62l5.404,2.82L9.935,14.594z"></path></svg><span class="wp-block-social-link-label screen-reader-text">YouTube</span></a></li></ul>



<p class="has-text-align-center has-text-color has-link-color wp-elements-a0a2ac26ad214a49dac577734d259176" style="color:#84bd00"><a href="https://xojo.com/download/" target="_blank" rel="noreferrer noopener">Download Xojo</a></p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>WinUI Support Moves to Beta</title>
		<link>https://blog.xojo.com/2026/10/20/winui-support-moves-to-beta/</link>
		
		<dc:creator><![CDATA[William Yu]]></dc:creator>
		<pubDate>Tue, 20 Oct 2026 16:53:54 +0000</pubDate>
				<category><![CDATA[Desktop]]></category>
		<category><![CDATA[General]]></category>
		<category><![CDATA[Learning]]></category>
		<category><![CDATA[Windows]]></category>
		<category><![CDATA[2026r3]]></category>
		<category><![CDATA[WinUI]]></category>
		<guid isPermaLink="false">https://blog.xojo.com/?p=16648</guid>

					<description><![CDATA[We&#8217;ve been making steady progress on our WinUI support for Windows, and we&#8217;re excited to announce that it has now moved from&#160;Experimental to Beta in&#8230;]]></description>
										<content:encoded><![CDATA[
<p>We&#8217;ve been making steady progress on our WinUI support for Windows, and we&#8217;re excited to announce that it has now moved from&nbsp;<strong>Experimental to Beta</strong> in Xojo 2026r3.</p>



<p>There&#8217;s still work to be done, but WinUI has reached an important milestone. We&#8217;re encouraging developers to start testing their existing applications with WinUI and, most importantly, to let us know when you encounter something that doesn&#8217;t work as expected.</p>



<h2 class="wp-block-heading">Menus and Contextual Menus</h2>



<p>One of the biggest additions in this release (Xojo 2026r3) is support for WinUI based Menus and Contextual Menus.</p>



<p>Menus are an essential part of many desktop applications, and bringing them to WinUI makes it possible to build more complete, native-feeling Windows applications with Xojo.</p>



<h2 class="wp-block-heading">Symbol Support</h2>



<p>We&#8217;ve also added support for symbols to a variety of controls, including <code>DesktopPopupMenu</code> and <code>Menus</code>.</p>



<p>Symbols provide a convenient way to add familiar visual indicators and icons to your application&#8217;s interface while taking advantage of the system&#8217;s available symbol resources. This gives you another way to create modern Windows interfaces without having to manage and distribute every image yourself. Note that Symbol support is only available for WinUI, Linux and macOS.</p>



<h2 class="wp-block-heading">Picture.SystemImage&nbsp;Comes to Desktop</h2>



<p>Originally available for iOS projects,&nbsp;<code>Picture.SystemImage</code>&nbsp;is now available on desktop as well. This provides a simple way to access system-provided images and symbols from your Xojo applications.</p>



<p>The list of supported symbols can be found here:</p>



<ul class="wp-block-list">
<li>Windows:&nbsp;<a href="https://learn.microsoft.com/en-us/windows/apps/design/iconography/segoe-fluent-icons-font" target="_blank" rel="noreferrer noopener">https://learn.microsoft.com/en-us/windows/apps/design/iconography/segoe-fluent-icons-font</a></li>



<li>Linux:&nbsp;<a href="https://specifications.freedesktop.org/icon-naming" target="_blank" rel="noreferrer noopener">https://specifications.freedesktop.org/icon-naming</a></li>



<li>macOS:&nbsp;<a href="https://developer.apple.com/design/human-interface-guidelines/sf-symbols" target="_blank" rel="noreferrer noopener">https://developer.apple.com/design/human-interface-guidelines/sf-symbols</a></li>
</ul>



<p>On Windows, symbols are loaded from the Segoe Fluent Icons font (on Windows 10 they are loaded from the Segoe MDL2 Assets), so this feature is supported on both WinUI and non-WinUI Windows targets.</p>



<h2 class="wp-block-heading">Designed with WinUI in Mind</h2>



<p>As we add new functionality and controls, we&#8217;re designing with modern desktop platforms like WinUI in mind from the start. This means not only adding WinUI support to existing controls, but also improving the overall desktop experience where we can.</p>



<p>For example, our new <code><a href="https://documentation.xojo.com/api/user_interface/desktop/desktoptable.html" target="_blank" rel="noreferrer noopener">DesktopTable</a></code> provides a much better WinUI look and feel than the older <code>DesktopListBox</code> control, giving you a more modern foundation for displaying tabular data.</p>



<figure class="wp-block-image size-large"><img decoding="async" width="810" height="701" src="https://blog.xojo.com/wp-content/uploads/2026/10/WinUIHierarchical.png" alt="" class="wp-image-16672" srcset="https://blog.xojo.com/wp-content/uploads/2026/10/WinUIHierarchical.png 810w, https://blog.xojo.com/wp-content/uploads/2026/10/WinUIHierarchical-300x260.png 300w, https://blog.xojo.com/wp-content/uploads/2026/10/WinUIHierarchical-768x665.png 768w" sizes="(max-width: 810px) 100vw, 810px" /></figure>



<figure class="wp-block-image size-large"><img decoding="async" width="934" height="677" src="https://blog.xojo.com/wp-content/uploads/2026/10/WinUITable.png" alt="" class="wp-image-16673" srcset="https://blog.xojo.com/wp-content/uploads/2026/10/WinUITable.png 934w, https://blog.xojo.com/wp-content/uploads/2026/10/WinUITable-300x217.png 300w, https://blog.xojo.com/wp-content/uploads/2026/10/WinUITable-768x557.png 768w" sizes="(max-width: 934px) 100vw, 934px" /></figure>



<p>We&#8217;re also making existing controls take better advantage of the features available on modern platforms. <code><a href="https://documentation.xojo.com/api/user_interface/desktop/desktoppopupmenu.html" target="_blank" rel="noreferrer noopener">PopupMenu</a></code> now makes use of the Icons assigned to its <code>MenuItems</code>, so when building for WinUI, Linux, or macOS, those Icons automatically appear in your <code>PopupMenus</code>.</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="637" height="305" src="https://blog.xojo.com/wp-content/uploads/2026/10/WinUIPopupMenuIcons-1.png" alt="" class="wp-image-16657" srcset="https://blog.xojo.com/wp-content/uploads/2026/10/WinUIPopupMenuIcons-1.png 637w, https://blog.xojo.com/wp-content/uploads/2026/10/WinUIPopupMenuIcons-1-300x144.png 300w" sizes="auto, (max-width: 637px) 100vw, 637px" /></figure>



<p>Even familiar controls are getting an update. <code>SegmentedButtons</code> can now properly receive focus and be navigated between segments using the keyboard.</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="904" height="253" src="https://blog.xojo.com/wp-content/uploads/2026/10/WinUISegmentedButton.png" alt="" class="wp-image-16680" srcset="https://blog.xojo.com/wp-content/uploads/2026/10/WinUISegmentedButton.png 904w, https://blog.xojo.com/wp-content/uploads/2026/10/WinUISegmentedButton-300x84.png 300w, https://blog.xojo.com/wp-content/uploads/2026/10/WinUISegmentedButton-768x215.png 768w" sizes="auto, (max-width: 904px) 100vw, 904px" /></figure>



<p>&nbsp;<code>MessageBox</code>&nbsp;is now dark-mode aware when built with WinUI, allowing it to better match the appearance of your application and the user&#8217;s system settings.</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="593" height="280" src="https://blog.xojo.com/wp-content/uploads/2026/10/WinUIMessageBox.png" alt="" class="wp-image-16654" srcset="https://blog.xojo.com/wp-content/uploads/2026/10/WinUIMessageBox.png 593w, https://blog.xojo.com/wp-content/uploads/2026/10/WinUIMessageBox-300x142.png 300w" sizes="auto, (max-width: 593px) 100vw, 593px" /></figure>



<h2 class="wp-block-heading">From Experimental to Beta</h2>



<p>Moving WinUI support from Experimental to&nbsp;Beta&nbsp;is an important step for Xojo.</p>



<p>Beta means that we believe WinUI is ready for more developers to begin using and testing in real-world applications. It does&nbsp;not&nbsp;mean that every feature is complete or that there aren&#8217;t still issues to address. There is more work ahead, and your feedback will be an important part of getting WinUI ready for production use.</p>



<h2 class="wp-block-heading">Give WinUI a Try</h2>



<p>WinUI represents an important step forward for Xojo on Windows, and we&#8217;re excited about where it is heading.</p>



<p>If you&#8217;ve been waiting to try WinUI, <strong>now is the time</strong>. Start testing your applications, explore the new functionality, and let us know what you discover. Your feedback will help us make Xojo&#8217;s WinUI support a great foundation for building modern Windows applications.</p>



<p><em><em><em>William Yu grew up in Canada learning to program BASIC on a Vic-20. He is Xojo’s resident Windows and Linux engineer, among his many other skills. Some may say he has joined the dark side here in the USA, but he will always be a Canadian at heart.</em></em></em></p>



<ul class="wp-block-social-links has-normal-icon-size is-content-justification-center is-layout-flex wp-container-core-social-links-is-layout-16018d1d wp-block-social-links-is-layout-flex"><li class="wp-social-link wp-social-link-facebook  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.facebook.com/goxojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M12 2C6.5 2 2 6.5 2 12c0 5 3.7 9.1 8.4 9.9v-7H7.9V12h2.5V9.8c0-2.5 1.5-3.9 3.8-3.9 1.1 0 2.2.2 2.2.2v2.5h-1.3c-1.2 0-1.6.8-1.6 1.6V12h2.8l-.4 2.9h-2.3v7C18.3 21.1 22 17 22 12c0-5.5-4.5-10-10-10z"></path></svg><span class="wp-block-social-link-label screen-reader-text">Facebook</span></a></li>

<li class="wp-social-link wp-social-link-x  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://x.com/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M13.982 10.622 20.54 3h-1.554l-5.693 6.618L8.745 3H3.5l6.876 10.007L3.5 21h1.554l6.012-6.989L15.868 21h5.245l-7.131-10.378Zm-2.128 2.474-.697-.997-5.543-7.93H8l4.474 6.4.697.996 5.815 8.318h-2.387l-4.745-6.787Z" /></svg><span class="wp-block-social-link-label screen-reader-text">X</span></a></li>

<li class="wp-social-link wp-social-link-linkedin  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.linkedin.com/company/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M19.7,3H4.3C3.582,3,3,3.582,3,4.3v15.4C3,20.418,3.582,21,4.3,21h15.4c0.718,0,1.3-0.582,1.3-1.3V4.3 C21,3.582,20.418,3,19.7,3z M8.339,18.338H5.667v-8.59h2.672V18.338z M7.004,8.574c-0.857,0-1.549-0.694-1.549-1.548 c0-0.855,0.691-1.548,1.549-1.548c0.854,0,1.547,0.694,1.547,1.548C8.551,7.881,7.858,8.574,7.004,8.574z M18.339,18.338h-2.669 v-4.177c0-0.996-0.017-2.278-1.387-2.278c-1.389,0-1.601,1.086-1.601,2.206v4.249h-2.667v-8.59h2.559v1.174h0.037 c0.356-0.675,1.227-1.387,2.526-1.387c2.703,0,3.203,1.779,3.203,4.092V18.338z"></path></svg><span class="wp-block-social-link-label screen-reader-text">LinkedIn</span></a></li>

<li class="wp-social-link wp-social-link-github  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://github.com/topics/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M12,2C6.477,2,2,6.477,2,12c0,4.419,2.865,8.166,6.839,9.489c0.5,0.09,0.682-0.218,0.682-0.484 c0-0.236-0.009-0.866-0.014-1.699c-2.782,0.602-3.369-1.34-3.369-1.34c-0.455-1.157-1.11-1.465-1.11-1.465 c-0.909-0.62,0.069-0.608,0.069-0.608c1.004,0.071,1.532,1.03,1.532,1.03c0.891,1.529,2.341,1.089,2.91,0.833 c0.091-0.647,0.349-1.086,0.635-1.337c-2.22-0.251-4.555-1.111-4.555-4.943c0-1.091,0.39-1.984,1.03-2.682 C6.546,8.54,6.202,7.524,6.746,6.148c0,0,0.84-0.269,2.75,1.025C10.295,6.95,11.15,6.84,12,6.836 c0.85,0.004,1.705,0.114,2.504,0.336c1.909-1.294,2.748-1.025,2.748-1.025c0.546,1.376,0.202,2.394,0.1,2.646 c0.64,0.699,1.026,1.591,1.026,2.682c0,3.841-2.337,4.687-4.565,4.935c0.359,0.307,0.679,0.917,0.679,1.852 c0,1.335-0.012,2.415-0.012,2.741c0,0.269,0.18,0.579,0.688,0.481C19.138,20.161,22,16.416,22,12C22,6.477,17.523,2,12,2z"></path></svg><span class="wp-block-social-link-label screen-reader-text">GitHub</span></a></li>

<li class="wp-social-link wp-social-link-youtube  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.youtube.com/c/XojoInc" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M21.8,8.001c0,0-0.195-1.378-0.795-1.985c-0.76-0.797-1.613-0.801-2.004-0.847c-2.799-0.202-6.997-0.202-6.997-0.202 h-0.009c0,0-4.198,0-6.997,0.202C4.608,5.216,3.756,5.22,2.995,6.016C2.395,6.623,2.2,8.001,2.2,8.001S2,9.62,2,11.238v1.517 c0,1.618,0.2,3.237,0.2,3.237s0.195,1.378,0.795,1.985c0.761,0.797,1.76,0.771,2.205,0.855c1.6,0.153,6.8,0.201,6.8,0.201 s4.203-0.006,7.001-0.209c0.391-0.047,1.243-0.051,2.004-0.847c0.6-0.607,0.795-1.985,0.795-1.985s0.2-1.618,0.2-3.237v-1.517 C22,9.62,21.8,8.001,21.8,8.001z M9.935,14.594l-0.001-5.62l5.404,2.82L9.935,14.594z"></path></svg><span class="wp-block-social-link-label screen-reader-text">YouTube</span></a></li></ul>



<p class="has-text-align-center has-text-color has-link-color wp-elements-a0a2ac26ad214a49dac577734d259176" style="color:#84bd00"><a href="https://xojo.com/download/" target="_blank" rel="noreferrer noopener">Download Xojo</a></p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>I Asked Claude Code to &#8220;Make Something Wow&#8221; in Xojo Web. Here&#8217;s What It Built.</title>
		<link>https://blog.xojo.com/2026/10/20/i-asked-claude-code-to-make-something-wow-in-xojo-web-heres-what-it-built/</link>
		
		<dc:creator><![CDATA[Ricardo Cruz]]></dc:creator>
		<pubDate>Tue, 20 Oct 2026 16:53:39 +0000</pubDate>
				<category><![CDATA[General]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[2026r3]]></category>
		<category><![CDATA[AI]]></category>
		<category><![CDATA[AI Code Generation]]></category>
		<category><![CDATA[Git]]></category>
		<category><![CDATA[Xojo Web]]></category>
		<guid isPermaLink="false">https://blog.xojo.com/?p=16664</guid>

					<description><![CDATA[Agentic Mode is one of the big additions in 2026r3. It lets Claude Code and other coding agents drive the Xojo IDE. Other posts in&#8230;]]></description>
										<content:encoded><![CDATA[
<p>Agentic Mode is one of the big additions in 2026r3. It lets Claude Code and other coding agents drive the Xojo IDE. Other posts in this series cover things like the IDE picking up file changes from disk. In this one, I want to show you why I think <a href="https://documentation.xojo.com/getting_started/using_the_ide/agentic_mode.html" target="_blank" rel="noreferrer noopener">Agentic Mode</a> is a great fit for Xojo Web projects.</p>



<p>While I&#8217;ve been using Claude Code and I refer to it through this blog post, any other coding agent that knows how to read the AGENTS.md file should work just fine as well. We&#8217;d love to hear your AI stories and we even have <a href="https://forum.xojo.com/c/ai/92" target="_blank" rel="noreferrer noopener">a dedicated forum category for AI related posts</a>.</p>



<p>I&#8217;ve been testing Agentic Mode for a while, and one session stands out. I gave Claude Code an intentionally vague prompt, something like &#8220;make something wow, the more wow, the better&#8221;. This is what Opus 5.5 came with after 11 minutes:</p>



<figure class="wp-block-video"><video height="1322" style="aspect-ratio: 2550 / 1322;" width="2550" controls src="https://blog.xojo.com/wp-content/uploads/2026/10/globe-demo.mp4"></video></figure>



<p>Far from perfect, but still very cool!</p>



<p>It&#8217;s a mission control panel showing a 3D globe with the earthquakes of the last seven days from the USGS feed, the live position and trajectory of the International Space Station, and the day/night line. It also has a command palette. And it&#8217;s multiplayer: every web session joins as a crew member, and you can see each other appear and move around in real time. Click a crew member and you jump to their view.</p>



<p>Let me show you how we got there.</p>



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



<p>There isn&#8217;t much to it, honestly. I created a new Xojo Web project, saved it in the plain text file format, and enabled Agentic Mode.</p>



<p>When you turn Agentic Mode on, the IDE creates an AGENTS.md file in the project folder if there isn&#8217;t one already. That file points to XOJO-CODING.md, which explains to the agent how to work with the IDE. It also links to example projects for each Xojo target, including Web.</p>



<p>There&#8217;s no MCP server involved, no plugin to install. The whole protocol is a couple of text files. When the agent wants to build and run the project, it touches a file called XojoRunProject.txt, and the IDE does the rest. If something doesn&#8217;t compile, the IDE writes the errors to XojoCompileErrors.txt so the agent can read them.</p>



<p>Claude Code read the instructions and followed them perfectly from the very first prompt.</p>



<h2 class="wp-block-heading">A JavaScript app in a Xojo shell? No, thanks</h2>



<p>The first version was impressive, but there was a catch. Claude Code built almost everything in JavaScript. It worked, but what I had was a JavaScript web app inside a Xojo Web shell, and that&#8217;s not really the point.</p>



<p>So I asked it to refine the project, using WebContainers and regular Xojo Web controls as much as possible. This is how the project looks in the IDE afterwards:</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="658" src="https://blog.xojo.com/wp-content/uploads/2026/10/Captura-de-pantalla-2026-10-07-a-las-11.35.24-1024x658.png" alt="" class="wp-image-16666" srcset="https://blog.xojo.com/wp-content/uploads/2026/10/Captura-de-pantalla-2026-10-07-a-las-11.35.24-1024x658.png 1024w, https://blog.xojo.com/wp-content/uploads/2026/10/Captura-de-pantalla-2026-10-07-a-las-11.35.24-300x193.png 300w, https://blog.xojo.com/wp-content/uploads/2026/10/Captura-de-pantalla-2026-10-07-a-las-11.35.24-768x493.png 768w, https://blog.xojo.com/wp-content/uploads/2026/10/Captura-de-pantalla-2026-10-07-a-las-11.35.24-1536x986.png 1536w, https://blog.xojo.com/wp-content/uploads/2026/10/Captura-de-pantalla-2026-10-07-a-las-11.35.24.png 1872w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p>The page is now built from reusable pieces you&#8217;d recognize from any Xojo project: a StatsPanel, a CrewPanel with a CrewRow for each crew member, QuakeCard, LegendPanel, HintBar, a ToastStack for notifications, and so on.</p>



<p>JavaScript didn&#8217;t disappear completely, and that&#8217;s fine. It stayed where it really makes sense. GlobeControl is a WebSDKUIControl wrapping the&nbsp;<a href="https://globe.gl/" target="_blank" rel="noreferrer noopener">Globe.GL</a>&nbsp;library, which handles the 3D globe. Claude Code also wrote a few other Web SDK controls for things that really should happen in the browser, like opening the command palette when you press Cmd+K. You wouldn&#8217;t want a round trip to the server just to show a palette.</p>



<p>If you open the project, you&#8217;ll be able to follow it, and change it, like any other Xojo Web app.</p>



<p>This is my main tip if you try this yourself: tell the agent explicitly that you want a maintainable Xojo app. Otherwise, it will reach for whatever it knows best in order to please you.</p>



<h2 class="wp-block-heading">Compile, Fix, Repeat</h2>



<p>Every now and then, Claude Code wrote something that didn&#8217;t compile. A syntax error here, a wrong type there. The good news is that it saw the error in XojoCompileErrors.txt right away, fixed it and built the project again. I didn&#8217;t have to jump in a single time.</p>



<p>If you&#8217;ve ever copied and pasted code from a chat window into the IDE, then copied the compile error back into the chat, you know how much friction this removes.</p>



<h2 class="wp-block-heading">Testing in a real browser</h2>



<p>This is where it gets interesting for web projects. Code that compiles isn&#8217;t necessarily code that works, and in a web app, the only way to know for sure is to open it in a browser.</p>



<p>With the Claude in Chrome extension, Claude Code can do exactly that. You just need Google Chrome open, with the extension installed and logged in. From there, the agent runs the app, opens it in Chrome, clicks around and tests the project end to end.</p>



<p>When something looks a bit off at runtime, it takes a screenshot of the browser, tweaks the project, runs it again, and keeps looping until it looks right. Since a multiplayer feature needs more than one user, it opened several tabs to check that the crew members showed up for each other, and closed them once it didn&#8217;t need them anymore. And if the Chrome extension isn&#8217;t available for whatever reason (like using other coding agents), it can fall back to Puppeteer and drive a browser on its own.</p>



<p>In practice, this means I could describe a feature, go outside and have a coffee, and come back to find it implemented, tested and polished.</p>



<p>If you&#8217;re using other targets, feel free to ask your coding agent to embed an MCP server and use it to test the app. It will find its way to test it, no matter what. It will ask you to do a final human review on specific new features, but overall, the agent will be on autopilot most of the time.</p>



<h2 class="wp-block-heading">A few rough edges</h2>



<p>This is a promising setup, but it isn&#8217;t perfect yet.</p>



<p>If two or more coding agents try to compile different apps at the same time (and I mean the very same second), the IDE may tell you the compiler is busy, or that it couldn&#8217;t find the debug app. If you are not in front of your computer, you might find the session stuck, waiting for some human help.</p>



<p>The limitations I&#8217;ve found so far were easy to work around, by explaining to Claude Code what to do when it happens. More on that in a moment.</p>



<h2 class="wp-block-heading">Teaching your agent new tricks</h2>



<p>XOJO-CODING.md will keep improving, and we&#8217;ll keep updating the example projects to give coding agents more context. Still, sooner or later you&#8217;ll find something the agent doesn&#8217;t know how to do.</p>



<p>In my case, Claude Code didn&#8217;t know how to encode constants, or how to use folders. It was dropping every single class into the root of the project. It worked, but imagine finding your way around a big project like that.</p>



<p>If your project is under Git, this is really easy to fix. Tell the agent you&#8217;re about to create some nested folders, or a constant with special characters. It will take a look at the repository and ask you to make the change in the IDE and save the project. Once you&#8217;ve done it, tell Claude Code, and it will look at the differences to see how the IDE wrote those files. From there, you can let it refactor the project and move everything into folders.</p>



<p>Then comes the important part: ask the agent to write down what it learned in AGENTS.md. Every new session reads that file, so the next one will already know how the IDE creates project files, and how you like to work. This is also where it added the note about the busy compiler.</p>



<p>If you&#8217;re working on an existing project, it gets even easier. You won&#8217;t need to show the agent how to use folders if your project already uses them, because it will follow what&#8217;s there. The more you use it, the better it gets. And the bigger the project, the easier it is for the agent to add new features in the same way you&#8217;re already working.</p>



<h2 class="wp-block-heading">Try it yourself!</h2>



<p>You can download the Mission Control project here:</p>



<p><a href="https://blog.xojo.com/wp-content/uploads/2026/10/GlobeProjectTest.zip" target="_blank" rel="noreferrer noopener">Download GlobeProjectTest.zip</a></p>



<p>Open it with 2026r3, run it in a couple of browser windows, and watch your crew show up.</p>



<h2 class="wp-block-heading">Working on Several Features at Once with Git Worktrees</h2>



<p>Once you get used to delegating features, you&#8217;ll start wondering why you have to wait for one to finish before starting the next. This is where Git worktrees come in.</p>



<p>A worktree lets you check out several branches of the same repository at once, each one in its own folder. Since every folder has its own copy of the project file, the Xojo IDE just sees them as different projects and opens each one separately. You can have one agent adding a new panel in one worktree, while another one fixes a bug in a second worktree, without stepping on each other&#8217;s toes.</p>



<p>When a feature is ready, review the changes and merge the branch, just like you would with work coming from any other developer on your team. Or even better, ask the agent to do the merge.</p>



<p>A few things to keep in mind. First, each web app needs its own port. If two worktrees try to run their debug apps on the same port, only the first one will start. Ask each agent to use a different debug port in its worktree, and they&#8217;ll be able to run side by side.</p>



<p>Second, commit your AGENTS.md file. That way, every worktree starts with everything your agents have learned so far, and a finding from one worktree can be merged back for the rest. Just don&#8217;t write a specific port number there, or every worktree will inherit the same one. Tell each agent which port to use when you start the session instead.</p>



<p>And third, remember the rough edge I mentioned earlier: if two agents happen to compile at the very same second, the IDE may report the compiler as busy. That&#8217;s exactly the kind of note worth adding to AGENTS.md, so your agents know to wait a moment and try again.</p>



<h2 class="wp-block-heading">Wrapping up</h2>



<p>I didn&#8217;t expect this to work as well as it did. The agent writes the code, the IDE compiles it, Chrome shows the result, and the loop keeps going until the app works. Your job moves from typing code to deciding what to build, and reviewing what comes back.</p>



<p>Learn more about using Agentic Mode in the <a href="https://documentation.xojo.com/getting_started/using_the_ide/agentic_mode.html" target="_blank" rel="noreferrer noopener">Docs</a> and in the <a href="https://documentation.xojo.com/getting_started/quickstarts/ai_quickstart.html" target="_blank" rel="noreferrer noopener">AI QuickStart</a>. I&#8217;d love to see what you build with Agentic Mode. Share some screenshots or recordings in a new forum thread, or send me a private message if you prefer.</p>



<p>Happy coding!</p>



<p><em>Ricardo has always been curious about how things work. Growing up surrounded by computers</em> he became interested in <em>web technologies in the dial-up connections era. Xojo has been his secret weapon and language of preference since 2018. When he’s not online, chances are he will be scuba diving … or crocheting amigurumis. Find Ricardo on Twitter <a href="https://x.com/piradoiv" target="_blank" rel="noreferrer noopener">@piradoiv</a>.</em></p>



<ul class="wp-block-social-links has-normal-icon-size is-content-justification-center is-layout-flex wp-container-core-social-links-is-layout-16018d1d wp-block-social-links-is-layout-flex"><li class="wp-social-link wp-social-link-facebook  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.facebook.com/goxojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M12 2C6.5 2 2 6.5 2 12c0 5 3.7 9.1 8.4 9.9v-7H7.9V12h2.5V9.8c0-2.5 1.5-3.9 3.8-3.9 1.1 0 2.2.2 2.2.2v2.5h-1.3c-1.2 0-1.6.8-1.6 1.6V12h2.8l-.4 2.9h-2.3v7C18.3 21.1 22 17 22 12c0-5.5-4.5-10-10-10z"></path></svg><span class="wp-block-social-link-label screen-reader-text">Facebook</span></a></li>

<li class="wp-social-link wp-social-link-x  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://x.com/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M13.982 10.622 20.54 3h-1.554l-5.693 6.618L8.745 3H3.5l6.876 10.007L3.5 21h1.554l6.012-6.989L15.868 21h5.245l-7.131-10.378Zm-2.128 2.474-.697-.997-5.543-7.93H8l4.474 6.4.697.996 5.815 8.318h-2.387l-4.745-6.787Z" /></svg><span class="wp-block-social-link-label screen-reader-text">X</span></a></li>

<li class="wp-social-link wp-social-link-linkedin  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.linkedin.com/company/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M19.7,3H4.3C3.582,3,3,3.582,3,4.3v15.4C3,20.418,3.582,21,4.3,21h15.4c0.718,0,1.3-0.582,1.3-1.3V4.3 C21,3.582,20.418,3,19.7,3z M8.339,18.338H5.667v-8.59h2.672V18.338z M7.004,8.574c-0.857,0-1.549-0.694-1.549-1.548 c0-0.855,0.691-1.548,1.549-1.548c0.854,0,1.547,0.694,1.547,1.548C8.551,7.881,7.858,8.574,7.004,8.574z M18.339,18.338h-2.669 v-4.177c0-0.996-0.017-2.278-1.387-2.278c-1.389,0-1.601,1.086-1.601,2.206v4.249h-2.667v-8.59h2.559v1.174h0.037 c0.356-0.675,1.227-1.387,2.526-1.387c2.703,0,3.203,1.779,3.203,4.092V18.338z"></path></svg><span class="wp-block-social-link-label screen-reader-text">LinkedIn</span></a></li>

<li class="wp-social-link wp-social-link-github  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://github.com/topics/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M12,2C6.477,2,2,6.477,2,12c0,4.419,2.865,8.166,6.839,9.489c0.5,0.09,0.682-0.218,0.682-0.484 c0-0.236-0.009-0.866-0.014-1.699c-2.782,0.602-3.369-1.34-3.369-1.34c-0.455-1.157-1.11-1.465-1.11-1.465 c-0.909-0.62,0.069-0.608,0.069-0.608c1.004,0.071,1.532,1.03,1.532,1.03c0.891,1.529,2.341,1.089,2.91,0.833 c0.091-0.647,0.349-1.086,0.635-1.337c-2.22-0.251-4.555-1.111-4.555-4.943c0-1.091,0.39-1.984,1.03-2.682 C6.546,8.54,6.202,7.524,6.746,6.148c0,0,0.84-0.269,2.75,1.025C10.295,6.95,11.15,6.84,12,6.836 c0.85,0.004,1.705,0.114,2.504,0.336c1.909-1.294,2.748-1.025,2.748-1.025c0.546,1.376,0.202,2.394,0.1,2.646 c0.64,0.699,1.026,1.591,1.026,2.682c0,3.841-2.337,4.687-4.565,4.935c0.359,0.307,0.679,0.917,0.679,1.852 c0,1.335-0.012,2.415-0.012,2.741c0,0.269,0.18,0.579,0.688,0.481C19.138,20.161,22,16.416,22,12C22,6.477,17.523,2,12,2z"></path></svg><span class="wp-block-social-link-label screen-reader-text">GitHub</span></a></li>

<li class="wp-social-link wp-social-link-youtube  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.youtube.com/c/XojoInc" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M21.8,8.001c0,0-0.195-1.378-0.795-1.985c-0.76-0.797-1.613-0.801-2.004-0.847c-2.799-0.202-6.997-0.202-6.997-0.202 h-0.009c0,0-4.198,0-6.997,0.202C4.608,5.216,3.756,5.22,2.995,6.016C2.395,6.623,2.2,8.001,2.2,8.001S2,9.62,2,11.238v1.517 c0,1.618,0.2,3.237,0.2,3.237s0.195,1.378,0.795,1.985c0.761,0.797,1.76,0.771,2.205,0.855c1.6,0.153,6.8,0.201,6.8,0.201 s4.203-0.006,7.001-0.209c0.391-0.047,1.243-0.051,2.004-0.847c0.6-0.607,0.795-1.985,0.795-1.985s0.2-1.618,0.2-3.237v-1.517 C22,9.62,21.8,8.001,21.8,8.001z M9.935,14.594l-0.001-5.62l5.404,2.82L9.935,14.594z"></path></svg><span class="wp-block-social-link-label screen-reader-text">YouTube</span></a></li></ul>



<p class="has-text-align-center has-text-color has-link-color wp-elements-a0a2ac26ad214a49dac577734d259176" style="color:#84bd00"><a href="https://xojo.com/download/" target="_blank" rel="noreferrer noopener">Download Xojo</a></p>
]]></content:encoded>
					
		
		<enclosure url="https://blog.xojo.com/wp-content/uploads/2026/10/globe-demo.mp4" length="8889006" type="video/mp4" />

			</item>
		<item>
		<title>Xojo Web 2026r3: URL Routing, New Features, and Two Important Changes</title>
		<link>https://blog.xojo.com/2026/10/20/xojo-web-2026r3-url-routing-new-features-and-two-important-changes/</link>
		
		<dc:creator><![CDATA[Ricardo Cruz]]></dc:creator>
		<pubDate>Tue, 20 Oct 2026 16:53:28 +0000</pubDate>
				<category><![CDATA[Web]]></category>
		<category><![CDATA[2026r3]]></category>
		<category><![CDATA[Web 2.0]]></category>
		<category><![CDATA[Web Development]]></category>
		<category><![CDATA[webdev]]></category>
		<category><![CDATA[Xojo Programming Language]]></category>
		<guid isPermaLink="false">https://blog.xojo.com/?p=16660</guid>

					<description><![CDATA[2026r3 brings a bit of everything to Xojo Web: two breaking changes you&#8217;ll want to read about before updating, a new URL router, a few&#8230;]]></description>
										<content:encoded><![CDATA[
<p>2026r3 brings a bit of everything to Xojo Web: two breaking changes you&#8217;ll want to read about before updating, a new URL router, a few small additions that were long overdue, and more than 40 bug fixes.</p>



<h2 class="wp-block-heading">Breaking Changes First</h2>



<p>I&#8217;d rather start with the uncomfortable part, so nobody gets surprised after updating.</p>



<h3 class="wp-block-heading">Unhandled exceptions will now quit your app</h3>



<p>Until now, the web framework was silently swallowing unhandled exceptions, and your app kept running as if nothing had happened. Desktop projects don&#8217;t behave like that. After going back and forth on it internally, we&#8217;ve decided to treat this difference as what it really is: a bug.</p>



<p>Starting with 2026r3, a web app will quit when an exception isn&#8217;t handled, unless you&nbsp;<code>Return True</code>&nbsp;from one of the UnhandledException events.</p>



<p>There are two of them. When something goes wrong inside a session context and you aren&#8217;t catching it in code, Session.UnhandledException fires first. A database call failing after the user presses a WebButton is a typical example. If you&nbsp;<code>Return True</code>&nbsp;there, the app keeps running. If you don&#8217;t, the exception keeps bubbling up and App.UnhandledException fires.</p>



<p>App.UnhandledException is your app&#8217;s last chance, and this is where the behavior changes. If you don&#8217;t&nbsp;<code>Return True</code>there, the app will print the stack trace, hoping it ends up logged somewhere, and quit.</p>



<p>If you really want things to work like before, add a&nbsp;<code>Return True</code>&nbsp;to App.UnhandledException and you&#8217;re done. But I&#8217;d encourage you to use this as an excuse to start paying attention to those exceptions. They are trying to tell you something. At the 2024 MBS Conference, Xojo MVP Jeremy Leroy gave a talk about tracking exceptions with Sentry, and I can&#8217;t recommend it enough:</p>



<figure class="wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio"><div class="wp-block-embed__wrapper">
<iframe loading="lazy" title="MBS Xojo Conference 2024 - Managing exceptions like a pro" width="500" height="281" src="https://www.youtube.com/embed/mxekiMAAzTA?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
</div></figure>



<h3 class="wp-block-heading">Positioning controls by code</h3>



<p>The second change comes from a series of bug fixes around positioning controls programmatically. The web framework had some issues here that made dynamic interfaces more painful than they should have been, and many of you ended up writing workarounds.</p>



<p>Web projects now place controls much closer to how Desktop projects do. The catch is that a workaround in your code may now be compensating for a problem that no longer exists. If you position controls by code, check your layouts after updating and remove the workarounds you don&#8217;t need anymore.</p>



<p>We try really hard to avoid breaking changes. In these two cases, we believe it&#8217;s the right call in the long run.</p>



<h2 class="wp-block-heading">URL Router</h2>



<p>On to the new stuff. The URL router is another piece of the puzzle on our way to SEO friendly web apps. Until now, if you wanted nice URLs, you had to parse them yourself in App.HandleURL, probably fighting with regular expressions along the way.</p>



<p>2026r3 adds a new <a href="https://documentation.xojo.com/api/web/webapplication.html#webapplication-addurlroute" target="_blank" rel="noreferrer noopener">WebApplication.AddURLRoute</a> method. Imagine you are building a blogging system with URLs like this one:</p>



<p><code>/2026/06/25/build-a-threaded-find-in-files-solution/</code></p>



<p>You&#8217;ll need a WebPage to display a single post. Let&#8217;s call it BlogPostWebPage. With that in place, this one-liner in App.Opening is all it takes:</p>



<pre class="wp-block-code"><code>AddURLRoute("/&lt;year:integer&gt;/&lt;month:integer&gt;/&lt;day:integer&gt;/&lt;slug:string&gt;/", TypeOf BlogPostWebPage)</code></pre>



<p>Two things are happening here. The obvious one: when a request matches the route, Xojo Web creates a new BlogPostWebPage instance and shows it. Notice the type next to each parameter name, too. A URL like&nbsp;<code>/hello/06/25/some-post/</code>&nbsp;won&#8217;t match, because &#8220;hello&#8221; isn&#8217;t an integer.</p>



<p>The second one is more subtle, and it&#8217;s where this gets handy. Since the route defines named parameters, you can read them from the BlogPostWebPage.Opening event using Session.URLNamedParameter:</p>



<pre class="wp-block-code"><code>Self.Title = Session.URLNamedParameter("slug")</code></pre>



<p>From there, it&#8217;s just a matter of using the slug to query your database and fill the page with the right post.</p>



<p>This is the first version of the router, and we&#8217;re looking forward to your feedback. If you find something we missed, please open a Bug Report or a Feature Request.</p>



<h2 class="wp-block-heading">WebCanvas.DrawControlInLayoutEditor</h2>



<p>Xojo targets keep borrowing ideas from each other. In the previous release, DesktopCanvas got a new DrawControlInLayoutEditor event, heavily inspired by WebSDKUIControl.DrawControlInLayoutEditor. Now <a href="https://documentation.xojo.com/api/user_interface/web/webcanvas.html#webcanvas" target="_blank" rel="noreferrer noopener">WebCanvas</a> supports it as well, so your canvas-based controls can show a preview of themselves in the Layout Editor instead of an empty box.</p>



<h2 class="wp-block-heading">WebFileUploader Improvements</h2>



<p>Until now, if a user picked the wrong file, the only thing you could offer was clearing the whole uploader and asking them to select everything again. That&#8217;s not great when they&#8217;ve picked ten files and only one of them was wrong.</p>



<p><a href="https://documentation.xojo.com/api/user_interface/web/webfileuploader.html#webfileuploader" target="_blank" rel="noreferrer noopener">WebFileUploader</a> in 2026r3 adds the FileNameAt and RemoveFileAt methods, plus the FileCount and LastFileIndex read-only computed properties. With them, you can let your users change their mind and remove individual files before uploading.</p>



<h2 class="wp-block-heading">WebRectangle.Pressed Event</h2>



<p>Last, but not least, <a href="https://documentation.xojo.com/api/user_interface/web/webrectangle.html#webrectangle" target="_blank" rel="noreferrer noopener">WebRectangle</a> finally has a Pressed event. WebRectangles are commonly used to group other controls, like a card with a title, a picture and a couple of labels, so making the whole group clickable made a lot of sense. Child controls can still have their own Pressed handlers. If none of them handles the press, it keeps bubbling up until it reaches the parent WebRectangle.</p>



<h2 class="wp-block-heading">Bug Fixes &amp; Wrapping Up</h2>



<p>The rest of the web side of this release is mostly bug fixes, more than 40 of them. As boring as that might sound, if just one of them makes your day to day a bit easier, it was worth it.</p>



<p>As usual, make sure to read the full release notes, because there&#8217;s much more in there than fits in a blog post. And thank you for taking the time to read this, test the betas, report bugs, send feature requests and renew your license. It all helps more than you might think.</p>



<p>Happy coding!</p>



<p><em>Ricardo has always been curious about how things work. Growing up surrounded by computers</em> he became interested in <em>web technologies in the dial-up connections era. Xojo has been his secret weapon and language of preference since 2018. When he’s not online, chances are he will be scuba diving … or crocheting amigurumis. Find Ricardo on Twitter <a href="https://x.com/piradoiv" target="_blank" rel="noreferrer noopener">@piradoiv</a>.</em></p>



<ul class="wp-block-social-links has-normal-icon-size is-content-justification-center is-layout-flex wp-container-core-social-links-is-layout-16018d1d wp-block-social-links-is-layout-flex"><li class="wp-social-link wp-social-link-facebook  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.facebook.com/goxojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M12 2C6.5 2 2 6.5 2 12c0 5 3.7 9.1 8.4 9.9v-7H7.9V12h2.5V9.8c0-2.5 1.5-3.9 3.8-3.9 1.1 0 2.2.2 2.2.2v2.5h-1.3c-1.2 0-1.6.8-1.6 1.6V12h2.8l-.4 2.9h-2.3v7C18.3 21.1 22 17 22 12c0-5.5-4.5-10-10-10z"></path></svg><span class="wp-block-social-link-label screen-reader-text">Facebook</span></a></li>

<li class="wp-social-link wp-social-link-x  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://x.com/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M13.982 10.622 20.54 3h-1.554l-5.693 6.618L8.745 3H3.5l6.876 10.007L3.5 21h1.554l6.012-6.989L15.868 21h5.245l-7.131-10.378Zm-2.128 2.474-.697-.997-5.543-7.93H8l4.474 6.4.697.996 5.815 8.318h-2.387l-4.745-6.787Z" /></svg><span class="wp-block-social-link-label screen-reader-text">X</span></a></li>

<li class="wp-social-link wp-social-link-linkedin  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.linkedin.com/company/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M19.7,3H4.3C3.582,3,3,3.582,3,4.3v15.4C3,20.418,3.582,21,4.3,21h15.4c0.718,0,1.3-0.582,1.3-1.3V4.3 C21,3.582,20.418,3,19.7,3z M8.339,18.338H5.667v-8.59h2.672V18.338z M7.004,8.574c-0.857,0-1.549-0.694-1.549-1.548 c0-0.855,0.691-1.548,1.549-1.548c0.854,0,1.547,0.694,1.547,1.548C8.551,7.881,7.858,8.574,7.004,8.574z M18.339,18.338h-2.669 v-4.177c0-0.996-0.017-2.278-1.387-2.278c-1.389,0-1.601,1.086-1.601,2.206v4.249h-2.667v-8.59h2.559v1.174h0.037 c0.356-0.675,1.227-1.387,2.526-1.387c2.703,0,3.203,1.779,3.203,4.092V18.338z"></path></svg><span class="wp-block-social-link-label screen-reader-text">LinkedIn</span></a></li>

<li class="wp-social-link wp-social-link-github  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://github.com/topics/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M12,2C6.477,2,2,6.477,2,12c0,4.419,2.865,8.166,6.839,9.489c0.5,0.09,0.682-0.218,0.682-0.484 c0-0.236-0.009-0.866-0.014-1.699c-2.782,0.602-3.369-1.34-3.369-1.34c-0.455-1.157-1.11-1.465-1.11-1.465 c-0.909-0.62,0.069-0.608,0.069-0.608c1.004,0.071,1.532,1.03,1.532,1.03c0.891,1.529,2.341,1.089,2.91,0.833 c0.091-0.647,0.349-1.086,0.635-1.337c-2.22-0.251-4.555-1.111-4.555-4.943c0-1.091,0.39-1.984,1.03-2.682 C6.546,8.54,6.202,7.524,6.746,6.148c0,0,0.84-0.269,2.75,1.025C10.295,6.95,11.15,6.84,12,6.836 c0.85,0.004,1.705,0.114,2.504,0.336c1.909-1.294,2.748-1.025,2.748-1.025c0.546,1.376,0.202,2.394,0.1,2.646 c0.64,0.699,1.026,1.591,1.026,2.682c0,3.841-2.337,4.687-4.565,4.935c0.359,0.307,0.679,0.917,0.679,1.852 c0,1.335-0.012,2.415-0.012,2.741c0,0.269,0.18,0.579,0.688,0.481C19.138,20.161,22,16.416,22,12C22,6.477,17.523,2,12,2z"></path></svg><span class="wp-block-social-link-label screen-reader-text">GitHub</span></a></li>

<li class="wp-social-link wp-social-link-youtube  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.youtube.com/c/XojoInc" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M21.8,8.001c0,0-0.195-1.378-0.795-1.985c-0.76-0.797-1.613-0.801-2.004-0.847c-2.799-0.202-6.997-0.202-6.997-0.202 h-0.009c0,0-4.198,0-6.997,0.202C4.608,5.216,3.756,5.22,2.995,6.016C2.395,6.623,2.2,8.001,2.2,8.001S2,9.62,2,11.238v1.517 c0,1.618,0.2,3.237,0.2,3.237s0.195,1.378,0.795,1.985c0.761,0.797,1.76,0.771,2.205,0.855c1.6,0.153,6.8,0.201,6.8,0.201 s4.203-0.006,7.001-0.209c0.391-0.047,1.243-0.051,2.004-0.847c0.6-0.607,0.795-1.985,0.795-1.985s0.2-1.618,0.2-3.237v-1.517 C22,9.62,21.8,8.001,21.8,8.001z M9.935,14.594l-0.001-5.62l5.404,2.82L9.935,14.594z"></path></svg><span class="wp-block-social-link-label screen-reader-text">YouTube</span></a></li></ul>



<p class="has-text-align-center has-text-color has-link-color wp-elements-a0a2ac26ad214a49dac577734d259176" style="color:#84bd00"><a href="https://xojo.com/download/" target="_blank" rel="noreferrer noopener">Download Xojo</a></p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>New Features for the iOS Framework</title>
		<link>https://blog.xojo.com/2026/10/20/new-features-for-the-ios-framework/</link>
		
		<dc:creator><![CDATA[Javier Menendez]]></dc:creator>
		<pubDate>Tue, 20 Oct 2026 16:53:15 +0000</pubDate>
				<category><![CDATA[iOS]]></category>
		<category><![CDATA[Mobile]]></category>
		<category><![CDATA[2026r3]]></category>
		<guid isPermaLink="false">https://blog.xojo.com/?p=16490</guid>

					<description><![CDATA[Xojo 2026r3 introduces a bunch of new features and improvements to make your iOS apps shine even more. With updates to the recently added MobileMenuItem&#8230;]]></description>
										<content:encoded><![CDATA[
<p>Xojo 2026r3 introduces a bunch of new features and improvements to make your iOS apps shine even more. With updates to the recently added <a href="#MobilePopupMenu" target="_blank" rel="noreferrer noopener">MobileMenuItem and MobilePopupMenu</a> classes, the <a href="#MobileScreen" target="_blank" rel="noreferrer noopener">MobileScreen</a>, and the addition of an independent <a href="#MobileSearchField" target="_blank" rel="noreferrer noopener">MobileSearch</a> control, you&#8217;ll be able to do more. Xojo 2026r3 also adds the ability to <a href="#mobiledocumentpicker" target="_blank" rel="noreferrer noopener">open documents</a> outside the app sandbox, <a href="#MobilePrinterPicker" target="_blank" rel="noreferrer noopener">print most common file formats</a> using compatible AirPrint printers, <a href="#MobileDocumentViewer" target="_blank" rel="noreferrer noopener">view, edit and save</a> the most common file types (including Microsoft Office Word and Excel), and support <a href="#DynamicType" target="_blank" rel="noreferrer noopener">Dynamic Type</a> on MobileLabel, MobileTextField and MobileTextArea. Continue reading to find out how you can implement these!</p>



<span id="more-16490"></span>



<h3 class="wp-block-heading" id="MobileDocumentPicker">MobileDocumentPicker: Beyond the Sandbox</h3>



<p>Starting with Xojo 2026r3, your iOS apps are able to open and even save files outside the usual folders related to the app sandbox. Using the new <a href="https://documentation.xojo.com/api/user_interface/mobile/mobileprintpicker.html" target="_blank" rel="noreferrer noopener">MobileDocumentPicker</a> class, it is now possible to open any available PDF document saved on the device (or even in iCloud) and display it using the MobilePDFViewer.</p>



<figure class="wp-block-video"><video controls src="https://blog.xojo.com/wp-content/uploads/2026/09/DocumentPicker.mp4"></video></figure>



<p>This also applies when saving files. For example, any PDF documents created using the PDFDocument class, any image, text or any other kind of document file you create in your iOS app can be saved for public availability outside of the sandboxed folders. Once saved, these documents can be opened by other apps installed on the same device, or even automatically synced via iCloud.</p>



<p>It is not necessary to enable any capability in your iOS project, or add entitlements or additional entries to the app&#8217;s .plist file, just use MobileDocumentPicker.Open and MobileDocumentPicker.Save methods.</p>



<h3 class="wp-block-heading" id="MobilePrinterPicker">Printing Arrives to iOS</h3>



<p>In addition to the MobileDocumentPicker, we also added the <a href="https://documentation.xojo.com/api/user_interface/mobile/mobileprintpicker.html" target="_blank" rel="noreferrer noopener">MobilePrinterPicker</a> starting with Xojo 2026r3. This control allows your app to print any of the most common file formats (for example PDF, images, text, html, .Pages and .Numbers) to any printer available on the network that is compatible with the AirPrint technology.</p>



<figure class="wp-block-video"><video controls src="https://blog.xojo.com/wp-content/uploads/2026/09/DocumentPrinter.mp4"></video></figure>



<p>You only need to call the MobilePrinterPicker.Print method, passing along the FolderItem whose content will be printed. The iOS modal dialog will offer options to select the target printer and all of the print settings for that printer, from the page size, to the range of pages to print, enabling duplex printing, color printing, etc.&nbsp;</p>



<h3 class="wp-block-heading" id="MobileDocumentViewer">Viewing Documents</h3>



<p>Now that we are able to access documents beyond the app sandbox and print them, it would be great to have the ability to display the most common document formats in your iOS apps &#8211; plus allow users to edit and save their changes! That is exactly what the new <a href="https://documentation.xojo.com/api/user_interface/mobile/mobiledocumentviewer.html" target="_blank" rel="noreferrer noopener">MobileDocumentViewer</a> does.</p>



<p>The MobileDocumentViewer allows your iOS app to view the following file formats:</p>



<ul class="wp-block-list">
<li><strong>iWork documents</strong>.</li>



<li><strong>Microsoft Office documents</strong>.</li>



<li><strong>Rich text format, or RTF, documents</strong>.</li>



<li><strong>PDF files</strong>.</li>



<li><strong>Images</strong>.</li>



<li><strong>Text files</strong> with a uniform type identifier that conforms to the public.text type.</li>



<li><strong>Comma-separated values, or CSV</strong>, files.</li>



<li><strong>Video</strong> files.</li>
</ul>



<p>And edit (and save) the changes made by the user in the following ones:</p>



<ul class="wp-block-list">
<li><strong>PDF Files</strong> (signing, drawing, rotating pages, adding or deleting pages, adding pages from scan, etc.)</li>



<li><strong>Images</strong> (drawing, cropping, etc.)</li>



<li><strong>Video files</strong> (trimming)</li>
</ul>



<p>You only need to drag the MobileDocumentViewer from the Library into the Tray area of the Screen where it is intended to be used. Calling the Show method on the instance will open the modal view to let users view and navigate among the received array of FolderItem instances of the documents to be shown.</p>



<figure class="wp-block-video"><video controls src="https://blog.xojo.com/wp-content/uploads/2026/09/Screen-Recording-2026-09-17-at-12.28.17.mp4"></video></figure>



<p>To react to the changes made by the user in the compatible document file formats, there is the DocumentSaved event handler, which (once implemented) receives the FolderItem of the document that has been modified.</p>



<h3 class="wp-block-heading" id="MobileSearchField">MobileSearchField</h3>



<p>Available on Desktop and Web targets, the <a href="https://documentation.xojo.com/api/user_interface/mobile/mobilesearchfield.html" target="_blank" rel="noreferrer noopener">MobileSearchField</a> has been added to the Mobile target.</p>



<p>In previous releases, it was possible to do a search or filter data in iOS apps using the iOSMobileTable control. However, there are situations where you may need more than one search control on the same iOS screen; and in some cases, you don&#8217;t need the search to display matching data in an iOSMobileTable.</p>



<p>For those scenarios, you can now add and use as many MobileSearchField controls as your app requires.</p>



<figure class="wp-block-video"><video autoplay controls loop src="https://blog.xojo.com/wp-content/uploads/2026/08/MobileSearchField.mp4"></video></figure>



<p>When using this control, you can not only set the default Hint or Text property values, but also enable a scope bar and set the title names for each scope. Think of the scope bar as a way to let users (and your app) filter results not only by the typed text, but also by a specific category, for example.</p>



<p>The scope bar can be enabled or disabled at runtime via code, as well as each title name displayed by the scope bar.</p>


<div class="wp-block-image">
<figure class="aligncenter"><img loading="lazy" decoding="async" width="588" height="276" src="https://blog.xojo.com/wp-content/uploads/2026/08/SearchScopes.png" alt="" class="wp-image-16492" srcset="https://blog.xojo.com/wp-content/uploads/2026/08/SearchScopes.png 588w, https://blog.xojo.com/wp-content/uploads/2026/08/SearchScopes-300x141.png 300w" sizes="auto, (max-width: 588px) 100vw, 588px" /></figure>
</div>


<p>The main event handlers that you will probably want to implement for this control are:</p>



<ul class="wp-block-list">
<li><strong>SearchPressed()</strong>. Fires when the user taps on the &#8220;Done&#8221; button on the device soft keyboard</li>



<li><strong>ScopeChanged(index As Integer)</strong>. Fires when the user changes the current scope in the scope bar (if enabled for the search field instance</li>



<li><strong>TextChanged()</strong>. Fires every time there is a change in the text field of the SearchField control</li>
</ul>



<h3 class="wp-block-heading" id="iOSMobileTable">iOSMobileTable SearchField</h3>



<p>We also improved how the already available search field for <a href="https://documentation.xojo.com/api/ios/iosmobiletable.html#iosmobiletable" target="_blank" rel="noreferrer noopener">iOSMobileTable</a> behaves, especially when the iOS app is run on iOS 26+.</p>



<ul class="wp-block-list">
<li>If the app uses a MobileTabBar or MobileToolbar, then the associated iOSMobileTable search field will move automatically to the navigation bar section.</li>



<li>When the search field is in the navigation bar section, it will be collapsed by default (displaying only the loupe icon), so it doesn&#8217;t take up extra space on the app screen when the user isn&#8217;t searching. Tapping on the loupe icon will expand the search field for the table, letting the user type. As soon as the search field loses the focus, it will collapse again as the loupe icon.</li>
</ul>



<figure class="wp-block-video"><video autoplay controls loop src="https://blog.xojo.com/wp-content/uploads/2026/08/TableSearchiOS.mp4"></video></figure>



<h3 class="wp-block-heading" id="MobilePopupMenu">MobileMenuItem and MobilePopupMenu Improvements</h3>



<p>Both MobileMenuItem class and MobilePopupMenu were introduced in Xojo 2026r2. In 2026r3, they received a number of improvements.</p>



<h4 class="wp-block-heading">MobileMenuItem</h4>



<ul class="wp-block-list">
<li><strong>Icon property</strong>. It is now possible to use Picture.SystemImage or a Picture directly to assign an icon to each item.</li>



<li><strong>Symbol</strong> <strong>property</strong>. You can now assign an SF Symbol name to this property and it will be used as the item&#8217;s image. You can also assign multiple symbol names separated by semicolons. The first one found will be the one used.<br>An advantage of using Symbol instead of Icon is that it will generate the assigned image at the expected size.</li>



<li><strong>AllowMulticolorSymbol</strong> <strong>property</strong>. When this property is set to True, the assigned symbol will use the Multicolor rendering mode instead of Monochrome.</li>



<li><strong>Separator</strong>. It is now possible to add separators to a menu using the same syntax as on Desktop: New MobileMenuItem(&#8220;-&#8220;).</li>



<li><strong>IntegratedPalette</strong> <strong>display mode</strong>. Starting with Xojo 2026r3, we added the IntegratedPalette to MobileMenuItem.RenderingModes. When used as the display mode on a submenu, it will be integrated into the main menu it is attached to using an horizontal format. This allows creating the kind of menus commonly found in many iOS apps.</li>
</ul>



<p>For example, the following code:</p>



<pre class="wp-block-code"><code>Var horizontalSubmenu As New MobileMenuItem("")
Var firstSubmenu As New MobileMenuItem("Pencil")
firstSubmenu.Tag = "Pencil"
firstSubmenu.Symbol = "pencil"

Var secondSubmenu As New MobileMenuItem("Eraser")
secondSubmenu.Symbol = "eraser"
secondSubmenu.Tag = "Eraser"

Var thirdSubmenu As New MobileMenuItem("Lasso")
thirdSubmenu.Symbol = "lasso"
thirdSubmenu.Tag = "Lasso"

horizontalSubmenu.AddMenu(firstSubmenu)
horizontalSubmenu.AddMenu(secondSubmenu)
horizontalSubmenu.AddMenu(thirdSubmenu)
horizontalSubmenu.DisplayMode = MobileMenuItem.DisplayModes.IntegratedPalette

Var mainMenu As New MobileMenuItem
mainMenu.AddMenu(horizontalSubmenu)

Var firstMain As New MobileMenuItem("Triangle")
firstMain.Symbol = "righttriangle"
firstMain.Tag = "Triangle"
Var secondmain As New MobileMenuItem("Viewer")
secondmain.Symbol = "plus.viewfinder"
secondmain.Tag = "Viewer"

mainMenu.AddMenu(firstMain)
mainMenu.AddMenu(secondmain)
mainMenu.AddMenu(New MobileMenuItem("-"))

Var thirdMain As New MobileMenuItem("Delete")
thirdMain.Symbol = "trash"
thirdMain.Tag = "Delete"
thirdMain.Destructive = True
mainMenu.AddMenu(thirdMain)

Me.Menu = mainMenu
Me.DisplayMenuAsAction = True</code></pre>



<p>will create this menu when displayed:</p>


<div class="wp-block-image">
<figure class="aligncenter"><img loading="lazy" decoding="async" width="578" height="400" src="https://blog.xojo.com/wp-content/uploads/2026/08/Screenshot-2026-08-27-at-15.26.02.png" alt="" class="wp-image-16494" srcset="https://blog.xojo.com/wp-content/uploads/2026/08/Screenshot-2026-08-27-at-15.26.02.png 578w, https://blog.xojo.com/wp-content/uploads/2026/08/Screenshot-2026-08-27-at-15.26.02-300x208.png 300w" sizes="auto, (max-width: 578px) 100vw, 578px" /></figure>
</div>


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



<p>On the MobilePopupMenu side, it received several fixes and improvements. Also, since MobileMenuItem can now handle separators, MobilePopupMenu now includes the AddSeparator method already available in the DesktopPopupMenu counterpart.</p>



<p>And because MobileMenuItem can now handle an Icon or Symbol, you can expect these to be supported when the items are displayed in the popup menu control.</p>



<figure class="wp-block-video"><video autoplay controls loop src="https://blog.xojo.com/wp-content/uploads/2026/08/MobilePopupMenu.mp4"></video></figure>



<h3 class="wp-block-heading">Symbols Everywhere!</h3>



<p>The Symbol and AllowMulticolorSymbol properties were not only added to <a href="https://documentation.xojo.com/api/user_interface/mobile/mobilemenuitem.html#mobilemenuitem">MobileMenuItem</a>, starting with Xojo 2026r3, you will be able to set them for the following controls and classes on iOS:</p>



<ul class="wp-block-list">
<li><a href="https://documentation.xojo.com/api/user_interface/mobile/mobilebutton.html#mobilebutton" target="_blank" rel="noreferrer noopener">MobileButton</a></li>



<li><a href="https://documentation.xojo.com/api/user_interface/mobile/mobiletoolbarbutton.html#mobiletoolbarbutton" target="_blank" rel="noreferrer noopener">MobileToolbarButton</a></li>



<li><a href="https://documentation.xojo.com/api/user_interface/mobile/mobilesegmentedbutton.html#mobilesegmentedbutton" target="_blank" rel="noreferrer noopener">MobileSegmentedButton</a></li>



<li><a href="https://documentation.xojo.com/api/ios/iosmobiletablerowaction.html#iosmobiletablerowaction" target="_blank" rel="noreferrer noopener">iOSMobileTableRowAction</a></li>
</ul>



<figure class="wp-block-image"><img loading="lazy" decoding="async" width="1179" height="2556" src="https://blog.xojo.com/wp-content/uploads/2026/08/Symbols-Action-Row.png" alt="" class="wp-image-16504" srcset="https://blog.xojo.com/wp-content/uploads/2026/08/Symbols-Action-Row.png 1179w, https://blog.xojo.com/wp-content/uploads/2026/08/Symbols-Action-Row-138x300.png 138w, https://blog.xojo.com/wp-content/uploads/2026/08/Symbols-Action-Row-472x1024.png 472w, https://blog.xojo.com/wp-content/uploads/2026/08/Symbols-Action-Row-768x1665.png 768w, https://blog.xojo.com/wp-content/uploads/2026/08/Symbols-Action-Row-709x1536.png 709w, https://blog.xojo.com/wp-content/uploads/2026/08/Symbols-Action-Row-945x2048.png 945w" sizes="auto, (max-width: 1179px) 100vw, 1179px" /></figure>



<p>That means you can now create more visual, modern (and colorful) UI designs for your iOS apps.</p>



<h3 class="wp-block-heading" id="MobileScreen">MobileScreen</h3>



<p>A couple of interesting improvements in this area:</p>



<ul class="wp-block-list">
<li><strong>MobileScreen.Show(makeCurrent As Boolean)</strong> &#8211; When the passed parameter is set to True, the new screen will substitute the current one without changing or being added to the app navigation stack. If the value is set to False, it will behave like the regular Show method when no parent screen is provided.</li>
</ul>



<figure class="wp-block-video"><video autoplay controls loop src="https://blog.xojo.com/wp-content/uploads/2026/08/mobileModalScreen.mp4"></video></figure>



<ul class="wp-block-list">
<li><strong>MobileScreen.ShowModal</strong> &#8211; We added a couple more parameters at the end of the method signature. The first one allows you to set the size of the modal to be shown (Medium, Large, Resizable) using the new ModalPresentationSizes enum. The last parameter, when set to True, will display a grabber widget at the top of the modal so the user better knows they can drag, especially if the modal is set to ModalPresentationSizes.Resizable.</li>
</ul>



<h3 class="wp-block-heading" id="DynamicType">The Arrival of Dynamic Type</h3>



<p>Dynamic Type is an Apple iOS feature that allows the user to set a preferred text size for apps that support it. That way, users can adjust the text shown by labels, text fields, text areas or even the captions on buttons to better fit their visual needs.</p>



<p>You can find this setting under Settings &gt; Accessibility &gt; Display &amp; Text Size &gt; Larger Text. From here, users can choose their preferred text size, and can also enable the Larger Accessibility Sizes switch if they need even bigger text than the standard range offers.</p>



<p>Starting with Xojo 2026r3, we&#8217;ve added a new Boolean property called UseAccessibilityFontSize to the following classes:</p>



<ul class="wp-block-list">
<li><a href="https://documentation.xojo.com/api/user_interface/mobile/mobilebutton.html#mobilebutton" target="_blank" rel="noreferrer noopener">MobileButton</a></li>



<li><a href="https://documentation.xojo.com/api/user_interface/mobile/mobilelabel.html#mobilelabel" target="_blank" rel="noreferrer noopener">MobileLabel</a></li>



<li><a href="https://documentation.xojo.com/api/user_interface/mobile/mobiletextarea.html#mobiletextarea" target="_blank" rel="noreferrer noopener">MobileTextArea</a></li>



<li><a href="https://documentation.xojo.com/api/user_interface/mobile/mobiletextfield.html#mobiletextfield" target="_blank" rel="noreferrer noopener">MobileTextField</a></li>
</ul>



<p>When this property is set to True, the controls will automatically display text at the size the user configured in their iOS Accessibility settings. Note that enabling this property forces the control to use the system font, since Dynamic Type only works with system fonts.</p>



<figure class="wp-block-video"><video autoplay controls loop src="https://blog.xojo.com/wp-content/uploads/2026/08/DynamicText.mp4"></video></figure>



<h4 class="wp-block-heading">Reacting to Dynamic Type Changes</h4>



<p>If you want to use some variations of the system font (for example, Bold), or manually react to user changes for the Dynamic Type settings, then you will find the new AccesibilityFontSizeChanged event handler on the <a href="https://documentation.xojo.com/api/user_interface/mobile/mobilescreen.html#mobilescreen" target="_blank" rel="noreferrer noopener">MobileScreen</a> class useful.</p>



<p>In addition, we added the shared method AccessibilityFontSize to the Font class, so you can retrieve the current Dynamic Type font size set by the user and react accordingly. For example, if you keep the UseAccessibilityFontSize set to False for your controls, this value lets your code apply any needed UI changes.</p>



<h3 class="wp-block-heading">MobileTextArea and MobileTextField</h3>



<p>These controls also received a small but useful feature: when you need to dismiss the keyboard and there is no suitable UI area to tap, the text field or text area can clear its focus and close the keyboard itself.</p>



<figure class="wp-block-video"><video autoplay controls loop src="https://blog.xojo.com/wp-content/uploads/2026/08/MobileTextFieldDone.mp4"></video></figure>



<p>Now, the new Boolean AllowDoneButton property can be set to True to add a &#8220;Done&#8221; button in the associated view of the keyboard itself. This way, once the user has finished typing in the control, they only need to tap the &#8220;Done&#8221; button in the keyboard for it to be closed and the control focus to be cleared.</p>



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



<p>We can&#8217;t wait to see how the new features will make their way into your iOS apps. As you&#8217;ve seen, there are also a good number of improvements you can use to update your existing apps and delight your users even more. Share your comments and creations on the <a href="https://forum.xojo.com" target="_blank" rel="noreferrer noopener">Xojo Forum</a>.</p>



<p><em>Javier Menendez is an engineer at Xojo and has been using Xojo since 1998. He lives in Castellón</em>, <em>Spain and hosts regular Xojo hangouts en español. Ask Javier questions on Twitter at <a href="https://twitter.com/xojoes" target="_blank" rel="noreferrer noopener">@XojoES</a> or on the <a href="https://forum.xojo.com/u/javier_menendez/summary" target="_blank" rel="noreferrer noopener">Xojo Forum</a>.</em></p>



<ul class="wp-block-social-links has-normal-icon-size is-content-justification-center is-layout-flex wp-container-core-social-links-is-layout-16018d1d wp-block-social-links-is-layout-flex"><li class="wp-social-link wp-social-link-facebook  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.facebook.com/goxojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M12 2C6.5 2 2 6.5 2 12c0 5 3.7 9.1 8.4 9.9v-7H7.9V12h2.5V9.8c0-2.5 1.5-3.9 3.8-3.9 1.1 0 2.2.2 2.2.2v2.5h-1.3c-1.2 0-1.6.8-1.6 1.6V12h2.8l-.4 2.9h-2.3v7C18.3 21.1 22 17 22 12c0-5.5-4.5-10-10-10z"></path></svg><span class="wp-block-social-link-label screen-reader-text">Facebook</span></a></li>

<li class="wp-social-link wp-social-link-x  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://x.com/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M13.982 10.622 20.54 3h-1.554l-5.693 6.618L8.745 3H3.5l6.876 10.007L3.5 21h1.554l6.012-6.989L15.868 21h5.245l-7.131-10.378Zm-2.128 2.474-.697-.997-5.543-7.93H8l4.474 6.4.697.996 5.815 8.318h-2.387l-4.745-6.787Z" /></svg><span class="wp-block-social-link-label screen-reader-text">X</span></a></li>

<li class="wp-social-link wp-social-link-linkedin  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.linkedin.com/company/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M19.7,3H4.3C3.582,3,3,3.582,3,4.3v15.4C3,20.418,3.582,21,4.3,21h15.4c0.718,0,1.3-0.582,1.3-1.3V4.3 C21,3.582,20.418,3,19.7,3z M8.339,18.338H5.667v-8.59h2.672V18.338z M7.004,8.574c-0.857,0-1.549-0.694-1.549-1.548 c0-0.855,0.691-1.548,1.549-1.548c0.854,0,1.547,0.694,1.547,1.548C8.551,7.881,7.858,8.574,7.004,8.574z M18.339,18.338h-2.669 v-4.177c0-0.996-0.017-2.278-1.387-2.278c-1.389,0-1.601,1.086-1.601,2.206v4.249h-2.667v-8.59h2.559v1.174h0.037 c0.356-0.675,1.227-1.387,2.526-1.387c2.703,0,3.203,1.779,3.203,4.092V18.338z"></path></svg><span class="wp-block-social-link-label screen-reader-text">LinkedIn</span></a></li>

<li class="wp-social-link wp-social-link-github  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://github.com/topics/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M12,2C6.477,2,2,6.477,2,12c0,4.419,2.865,8.166,6.839,9.489c0.5,0.09,0.682-0.218,0.682-0.484 c0-0.236-0.009-0.866-0.014-1.699c-2.782,0.602-3.369-1.34-3.369-1.34c-0.455-1.157-1.11-1.465-1.11-1.465 c-0.909-0.62,0.069-0.608,0.069-0.608c1.004,0.071,1.532,1.03,1.532,1.03c0.891,1.529,2.341,1.089,2.91,0.833 c0.091-0.647,0.349-1.086,0.635-1.337c-2.22-0.251-4.555-1.111-4.555-4.943c0-1.091,0.39-1.984,1.03-2.682 C6.546,8.54,6.202,7.524,6.746,6.148c0,0,0.84-0.269,2.75,1.025C10.295,6.95,11.15,6.84,12,6.836 c0.85,0.004,1.705,0.114,2.504,0.336c1.909-1.294,2.748-1.025,2.748-1.025c0.546,1.376,0.202,2.394,0.1,2.646 c0.64,0.699,1.026,1.591,1.026,2.682c0,3.841-2.337,4.687-4.565,4.935c0.359,0.307,0.679,0.917,0.679,1.852 c0,1.335-0.012,2.415-0.012,2.741c0,0.269,0.18,0.579,0.688,0.481C19.138,20.161,22,16.416,22,12C22,6.477,17.523,2,12,2z"></path></svg><span class="wp-block-social-link-label screen-reader-text">GitHub</span></a></li>

<li class="wp-social-link wp-social-link-youtube  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.youtube.com/c/XojoInc" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M21.8,8.001c0,0-0.195-1.378-0.795-1.985c-0.76-0.797-1.613-0.801-2.004-0.847c-2.799-0.202-6.997-0.202-6.997-0.202 h-0.009c0,0-4.198,0-6.997,0.202C4.608,5.216,3.756,5.22,2.995,6.016C2.395,6.623,2.2,8.001,2.2,8.001S2,9.62,2,11.238v1.517 c0,1.618,0.2,3.237,0.2,3.237s0.195,1.378,0.795,1.985c0.761,0.797,1.76,0.771,2.205,0.855c1.6,0.153,6.8,0.201,6.8,0.201 s4.203-0.006,7.001-0.209c0.391-0.047,1.243-0.051,2.004-0.847c0.6-0.607,0.795-1.985,0.795-1.985s0.2-1.618,0.2-3.237v-1.517 C22,9.62,21.8,8.001,21.8,8.001z M9.935,14.594l-0.001-5.62l5.404,2.82L9.935,14.594z"></path></svg><span class="wp-block-social-link-label screen-reader-text">YouTube</span></a></li></ul>



<p class="has-text-align-center has-text-color has-link-color wp-elements-a0a2ac26ad214a49dac577734d259176" style="color:#84bd00"><a href="https://xojo.com/download/" target="_blank" rel="noreferrer noopener">Download Xojo</a></p>
]]></content:encoded>
					
		
		<enclosure url="https://blog.xojo.com/wp-content/uploads/2026/09/DocumentPicker.mp4" length="627349" type="video/mp4" />
<enclosure url="https://blog.xojo.com/wp-content/uploads/2026/09/DocumentPrinter.mp4" length="933315" type="video/mp4" />
<enclosure url="https://blog.xojo.com/wp-content/uploads/2026/09/Screen-Recording-2026-09-17-at-12.28.17.mp4" length="1732213" type="video/mp4" />
<enclosure url="https://blog.xojo.com/wp-content/uploads/2026/08/MobileSearchField.mp4" length="985731" type="video/mp4" />
<enclosure url="https://blog.xojo.com/wp-content/uploads/2026/08/TableSearchiOS.mp4" length="97925" type="video/mp4" />
<enclosure url="https://blog.xojo.com/wp-content/uploads/2026/08/MobilePopupMenu.mp4" length="159044" type="video/mp4" />
<enclosure url="https://blog.xojo.com/wp-content/uploads/2026/08/mobileModalScreen.mp4" length="1679597" type="video/mp4" />
<enclosure url="https://blog.xojo.com/wp-content/uploads/2026/08/DynamicText.mp4" length="564798" type="video/mp4" />
<enclosure url="https://blog.xojo.com/wp-content/uploads/2026/08/MobileTextFieldDone.mp4" length="184322" type="video/mp4" />

			</item>
		<item>
		<title>Introducing DesktopTable: A More Capable DesktopListBox</title>
		<link>https://blog.xojo.com/2026/10/20/introducing-desktoptable-a-more-capable-desktoplistbox/</link>
		
		<dc:creator><![CDATA[William Yu]]></dc:creator>
		<pubDate>Tue, 20 Oct 2026 16:52:10 +0000</pubDate>
				<category><![CDATA[Desktop]]></category>
		<category><![CDATA[General]]></category>
		<category><![CDATA[Learning]]></category>
		<category><![CDATA[2026r3]]></category>
		<category><![CDATA[DesktopTable]]></category>
		<category><![CDATA[Listbox]]></category>
		<guid isPermaLink="false">https://blog.xojo.com/?p=16615</guid>

					<description><![CDATA[DesktopTable is a new control introduced in Xojo 2026r3, it is designed as a drop-in replacement for DesktopListBox, while adding a range of features for&#8230;]]></description>
										<content:encoded><![CDATA[
<p>DesktopTable is a new control introduced in Xojo 2026r3, it is designed as a drop-in replacement for DesktopListBox, while adding a range of features for building richer, more capable tables.</p>



<p>Most existing DesktopListBox code will compile with little or no change when transitioning to DesktopTable. At the same time, DesktopTable adds features that previously required custom controls or additional code.</p>



<h2 class="wp-block-heading">What’s New?</h2>



<p>DesktopTable adds support for:</p>



<ul class="wp-block-list">
<li><strong>Frozen columns and rows</strong> — Keep important columns, headers, or totals visible while scrolling</li>
</ul>



<figure class="wp-block-video"><video height="1130" style="aspect-ratio: 1664 / 1130;" width="1664" controls src="https://blog.xojo.com/wp-content/uploads/2026/10/DesktopTable_FrozenColumns.mov"></video></figure>



<ul class="wp-block-list">
<li><strong>Merged cells</strong>&nbsp;— Span cells across rows and columns for titles, groupings, and custom layouts</li>



<li><strong>Sticky section headers</strong>&nbsp;— Keep section headers pinned as their section scrolls</li>



<li><strong>Hidden and reorderable columns</strong>&nbsp;— Hide columns without removing their data, or let users rearrange them</li>



<li><strong>Per-row heights</strong>&nbsp;— Set individual row heights and optionally allow users to resize rows</li>
</ul>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="992" src="https://blog.xojo.com/wp-content/uploads/2026/10/DesktopTable_VariableRowHeights-1024x992.png" alt="" class="wp-image-16627" srcset="https://blog.xojo.com/wp-content/uploads/2026/10/DesktopTable_VariableRowHeights-1024x992.png 1024w, https://blog.xojo.com/wp-content/uploads/2026/10/DesktopTable_VariableRowHeights-300x291.png 300w, https://blog.xojo.com/wp-content/uploads/2026/10/DesktopTable_VariableRowHeights-768x744.png 768w, https://blog.xojo.com/wp-content/uploads/2026/10/DesktopTable_VariableRowHeights.png 1170w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<ul class="wp-block-list">
<li><strong>Insets</strong>&nbsp;— Add space before the first or after the last row</li>



<li><strong>Progress bars, checkboxes, and containers</strong>&nbsp;— Built-in cell types for richer data presentation</li>
</ul>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="714" src="https://blog.xojo.com/wp-content/uploads/2026/10/Screenshot-2026-10-06-at-1.16.33-PM-1024x714.png" alt="" class="wp-image-16636" srcset="https://blog.xojo.com/wp-content/uploads/2026/10/Screenshot-2026-10-06-at-1.16.33-PM-1024x714.png 1024w, https://blog.xojo.com/wp-content/uploads/2026/10/Screenshot-2026-10-06-at-1.16.33-PM-300x209.png 300w, https://blog.xojo.com/wp-content/uploads/2026/10/Screenshot-2026-10-06-at-1.16.33-PM-768x535.png 768w, https://blog.xojo.com/wp-content/uploads/2026/10/Screenshot-2026-10-06-at-1.16.33-PM-1536x1071.png 1536w, https://blog.xojo.com/wp-content/uploads/2026/10/Screenshot-2026-10-06-at-1.16.33-PM.png 1664w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<figure class="wp-block-gallery has-nested-images columns-default is-cropped wp-block-gallery-1 is-layout-flex wp-block-gallery-is-layout-flex">
<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="387" height="755" data-id="16646" src="https://blog.xojo.com/wp-content/uploads/2026/10/Win32ProgressBarCellType-2.png" alt="" class="wp-image-16646" srcset="https://blog.xojo.com/wp-content/uploads/2026/10/Win32ProgressBarCellType-2.png 387w, https://blog.xojo.com/wp-content/uploads/2026/10/Win32ProgressBarCellType-2-154x300.png 154w" sizes="auto, (max-width: 387px) 100vw, 387px" /></figure>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="387" height="785" data-id="16645" src="https://blog.xojo.com/wp-content/uploads/2026/10/WinUIProgressBarCellType-1.png" alt="" class="wp-image-16645" srcset="https://blog.xojo.com/wp-content/uploads/2026/10/WinUIProgressBarCellType-1.png 387w, https://blog.xojo.com/wp-content/uploads/2026/10/WinUIProgressBarCellType-1-148x300.png 148w" sizes="auto, (max-width: 387px) 100vw, 387px" /></figure>
</figure>



<ul class="wp-block-list">
<li><strong>Custom cell controls</strong>&nbsp;— Use&nbsp;<code>CellBoundsAt</code>&nbsp;to position your own controls over cells</li>



<li><strong>Automatic Right-to-Left support</strong>&nbsp;— The table automatically adapts and aligns columns and text for right-to-left languages</li>
</ul>



<figure class="wp-block-gallery has-nested-images columns-default is-cropped wp-block-gallery-2 is-layout-flex wp-block-gallery-is-layout-flex">
<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="777" data-id="16640" src="https://blog.xojo.com/wp-content/uploads/2026/10/Screenshot-2026-10-06-at-1.45.09-PM-1024x777.png" alt="" class="wp-image-16640" srcset="https://blog.xojo.com/wp-content/uploads/2026/10/Screenshot-2026-10-06-at-1.45.09-PM-1024x777.png 1024w, https://blog.xojo.com/wp-content/uploads/2026/10/Screenshot-2026-10-06-at-1.45.09-PM-300x228.png 300w, https://blog.xojo.com/wp-content/uploads/2026/10/Screenshot-2026-10-06-at-1.45.09-PM-768x582.png 768w, https://blog.xojo.com/wp-content/uploads/2026/10/Screenshot-2026-10-06-at-1.45.09-PM.png 1424w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="777" data-id="16639" src="https://blog.xojo.com/wp-content/uploads/2026/10/Screenshot-2026-10-06-at-1.44.23-PM-1024x777.png" alt="" class="wp-image-16639" srcset="https://blog.xojo.com/wp-content/uploads/2026/10/Screenshot-2026-10-06-at-1.44.23-PM-1024x777.png 1024w, https://blog.xojo.com/wp-content/uploads/2026/10/Screenshot-2026-10-06-at-1.44.23-PM-300x228.png 300w, https://blog.xojo.com/wp-content/uploads/2026/10/Screenshot-2026-10-06-at-1.44.23-PM-768x582.png 768w, https://blog.xojo.com/wp-content/uploads/2026/10/Screenshot-2026-10-06-at-1.44.23-PM.png 1424w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>
</figure>



<ul class="wp-block-list">
<li><strong>Virtual data sources</strong>&nbsp;— Work with large datasets without storing every row in the control</li>



<li><strong>CSV and TSV support</strong>&nbsp;— Save and load table data directly</li>



<li><strong>Row swipe actions</strong>&nbsp;— Provide familiar leading and trailing actions on macOS, Windows, and Linux touchpads</li>
</ul>



<figure class="wp-block-video"><video height="1090" style="aspect-ratio: 1424 / 1090;" width="1424" controls src="https://blog.xojo.com/wp-content/uploads/2026/10/DesktopTable_MouseGesture.mov"></video></figure>



<ul class="wp-block-list">
<li><strong>Live column resizing</strong>&nbsp;— Respond while a column is being resized, as well as when resizing finishes</li>



<li><strong>Custom drawing and macOS vibrancy</strong>&nbsp;— More control over the table&#8217;s appearance and behavior</li>
</ul>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="1000" height="878" src="https://blog.xojo.com/wp-content/uploads/2026/10/DesktopTable_Translucent.png" alt="" class="wp-image-16623" srcset="https://blog.xojo.com/wp-content/uploads/2026/10/DesktopTable_Translucent.png 1000w, https://blog.xojo.com/wp-content/uploads/2026/10/DesktopTable_Translucent-300x263.png 300w, https://blog.xojo.com/wp-content/uploads/2026/10/DesktopTable_Translucent-768x674.png 768w" sizes="auto, (max-width: 1000px) 100vw, 1000px" /></figure>



<h2 class="wp-block-heading">Moving from DesktopListBox</h2>



<p>The transition is intentionally straightforward. Change the super of your <code>DesktopListBox</code> control to&nbsp;<code>DesktopTable</code>, build your project, and address the few members that have been renamed.</p>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>DesktopListBox</th><th>DesktopTable</th></tr></thead><tbody><tr><td>HeaderAt</td><td>ColumnHeaderAt</td></tr><tr><td>HasHeader</td><td>HasColumnHeader</td></tr><tr><td>RefreshCell</td><td>RefreshCellAt</td></tr><tr><td>PressHeader</td><td>PressColumnHeaderAt</td></tr></tbody></table></figure>



<p>Most familiar APIs—including&nbsp;<code>AddRow</code>,&nbsp;<code>CellTextAt</code>,&nbsp;<code>ColumnCount</code>,&nbsp;<code>ColumnWidths</code>,&nbsp;<code>RemoveRowAt</code>, and&nbsp;<code>SelectedRowIndex</code>—retain their existing names.</p>



<h2 class="wp-block-heading">A Few Things to Check</h2>



<p>Some behavior is intentionally different. In particular, row reordering with a&nbsp;<code>DataSource</code>&nbsp;or expandable rows requires you to handle&nbsp;<code>DragReorderRows</code>, and row dragging requires&nbsp;<code>DragRow</code>&nbsp;to populate the&nbsp;<code>DragItem</code>&nbsp;and return&nbsp;<code>True</code>.</p>



<p>Sorting also removes merged cells, so applications using merged cells should re-apply their merges after sorting. Frozen rows retain their position and cannot be reordered.</p>



<p><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4a1.png" alt="💡" class="wp-smiley" style="height: 1em; max-height: 1em;" />If you want to improve performance when adding and removing rows, you can set <code>AllowRowAnimation</code> to False.</p>



<h2 class="wp-block-heading">An Enhanced IDE Experience</h2>



<p>We couldn&#8217;t introduce DesktopTable without enhancing the IDE experience as well. Table editing in the IDE is now more intuitive, compared against DesktopListBox, making it easier to edit and work with your tables.</p>



<figure class="wp-block-gallery has-nested-images columns-default is-cropped wp-block-gallery-3 is-layout-flex wp-block-gallery-is-layout-flex">
<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="750" data-id="16631" src="https://blog.xojo.com/wp-content/uploads/2026/10/Screenshot-2026-10-06-at-11.02.18-AM-1024x750.png" alt="" class="wp-image-16631" srcset="https://blog.xojo.com/wp-content/uploads/2026/10/Screenshot-2026-10-06-at-11.02.18-AM-1024x750.png 1024w, https://blog.xojo.com/wp-content/uploads/2026/10/Screenshot-2026-10-06-at-11.02.18-AM-300x220.png 300w, https://blog.xojo.com/wp-content/uploads/2026/10/Screenshot-2026-10-06-at-11.02.18-AM-768x563.png 768w, https://blog.xojo.com/wp-content/uploads/2026/10/Screenshot-2026-10-06-at-11.02.18-AM.png 1228w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /><figcaption class="wp-element-caption">DesktopTable editor</figcaption></figure>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="752" data-id="16632" src="https://blog.xojo.com/wp-content/uploads/2026/10/Screenshot-2026-10-06-at-11.03.53-AM-1024x752.png" alt="" class="wp-image-16632" srcset="https://blog.xojo.com/wp-content/uploads/2026/10/Screenshot-2026-10-06-at-11.03.53-AM-1024x752.png 1024w, https://blog.xojo.com/wp-content/uploads/2026/10/Screenshot-2026-10-06-at-11.03.53-AM-300x220.png 300w, https://blog.xojo.com/wp-content/uploads/2026/10/Screenshot-2026-10-06-at-11.03.53-AM-768x564.png 768w, https://blog.xojo.com/wp-content/uploads/2026/10/Screenshot-2026-10-06-at-11.03.53-AM.png 1220w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /><figcaption class="wp-element-caption">DesktopListBox editor</figcaption></figure>
</figure>



<p>We&#8217;ve also updated the debugger to better handle DesktopTable contents, efficiently loading rows dynamically and allowing you to jump directly to and inspect specific rows without loading the entire table.</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="500" src="https://blog.xojo.com/wp-content/uploads/2026/10/Screenshot-2026-10-06-at-11.14.48-AM-1024x500.png" alt="" class="wp-image-16633" srcset="https://blog.xojo.com/wp-content/uploads/2026/10/Screenshot-2026-10-06-at-11.14.48-AM-1024x500.png 1024w, https://blog.xojo.com/wp-content/uploads/2026/10/Screenshot-2026-10-06-at-11.14.48-AM-300x147.png 300w, https://blog.xojo.com/wp-content/uploads/2026/10/Screenshot-2026-10-06-at-11.14.48-AM-768x375.png 768w, https://blog.xojo.com/wp-content/uploads/2026/10/Screenshot-2026-10-06-at-11.14.48-AM.png 1134w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<h2 class="wp-block-heading">Final Thoughts</h2>



<p>DesktopTable gives existing DesktopListBox applications a familiar starting point while opening the door to considerably richer table interfaces. Stay tuned for more blog posts exploring many of its exciting new features!</p>



<p><em><em><em>William Yu grew up in Canada learning to program BASIC on a Vic-20. He is Xojo’s resident Windows and Linux engineer, among his many other skills. Some may say he has joined the dark side here in the USA, but he will always be a Canadian at heart.</em></em></em></p>



<ul class="wp-block-social-links has-normal-icon-size is-content-justification-center is-layout-flex wp-container-core-social-links-is-layout-16018d1d wp-block-social-links-is-layout-flex"><li class="wp-social-link wp-social-link-facebook  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.facebook.com/goxojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M12 2C6.5 2 2 6.5 2 12c0 5 3.7 9.1 8.4 9.9v-7H7.9V12h2.5V9.8c0-2.5 1.5-3.9 3.8-3.9 1.1 0 2.2.2 2.2.2v2.5h-1.3c-1.2 0-1.6.8-1.6 1.6V12h2.8l-.4 2.9h-2.3v7C18.3 21.1 22 17 22 12c0-5.5-4.5-10-10-10z"></path></svg><span class="wp-block-social-link-label screen-reader-text">Facebook</span></a></li>

<li class="wp-social-link wp-social-link-x  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://x.com/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M13.982 10.622 20.54 3h-1.554l-5.693 6.618L8.745 3H3.5l6.876 10.007L3.5 21h1.554l6.012-6.989L15.868 21h5.245l-7.131-10.378Zm-2.128 2.474-.697-.997-5.543-7.93H8l4.474 6.4.697.996 5.815 8.318h-2.387l-4.745-6.787Z" /></svg><span class="wp-block-social-link-label screen-reader-text">X</span></a></li>

<li class="wp-social-link wp-social-link-linkedin  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.linkedin.com/company/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M19.7,3H4.3C3.582,3,3,3.582,3,4.3v15.4C3,20.418,3.582,21,4.3,21h15.4c0.718,0,1.3-0.582,1.3-1.3V4.3 C21,3.582,20.418,3,19.7,3z M8.339,18.338H5.667v-8.59h2.672V18.338z M7.004,8.574c-0.857,0-1.549-0.694-1.549-1.548 c0-0.855,0.691-1.548,1.549-1.548c0.854,0,1.547,0.694,1.547,1.548C8.551,7.881,7.858,8.574,7.004,8.574z M18.339,18.338h-2.669 v-4.177c0-0.996-0.017-2.278-1.387-2.278c-1.389,0-1.601,1.086-1.601,2.206v4.249h-2.667v-8.59h2.559v1.174h0.037 c0.356-0.675,1.227-1.387,2.526-1.387c2.703,0,3.203,1.779,3.203,4.092V18.338z"></path></svg><span class="wp-block-social-link-label screen-reader-text">LinkedIn</span></a></li>

<li class="wp-social-link wp-social-link-github  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://github.com/topics/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M12,2C6.477,2,2,6.477,2,12c0,4.419,2.865,8.166,6.839,9.489c0.5,0.09,0.682-0.218,0.682-0.484 c0-0.236-0.009-0.866-0.014-1.699c-2.782,0.602-3.369-1.34-3.369-1.34c-0.455-1.157-1.11-1.465-1.11-1.465 c-0.909-0.62,0.069-0.608,0.069-0.608c1.004,0.071,1.532,1.03,1.532,1.03c0.891,1.529,2.341,1.089,2.91,0.833 c0.091-0.647,0.349-1.086,0.635-1.337c-2.22-0.251-4.555-1.111-4.555-4.943c0-1.091,0.39-1.984,1.03-2.682 C6.546,8.54,6.202,7.524,6.746,6.148c0,0,0.84-0.269,2.75,1.025C10.295,6.95,11.15,6.84,12,6.836 c0.85,0.004,1.705,0.114,2.504,0.336c1.909-1.294,2.748-1.025,2.748-1.025c0.546,1.376,0.202,2.394,0.1,2.646 c0.64,0.699,1.026,1.591,1.026,2.682c0,3.841-2.337,4.687-4.565,4.935c0.359,0.307,0.679,0.917,0.679,1.852 c0,1.335-0.012,2.415-0.012,2.741c0,0.269,0.18,0.579,0.688,0.481C19.138,20.161,22,16.416,22,12C22,6.477,17.523,2,12,2z"></path></svg><span class="wp-block-social-link-label screen-reader-text">GitHub</span></a></li>

<li class="wp-social-link wp-social-link-youtube  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.youtube.com/c/XojoInc" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M21.8,8.001c0,0-0.195-1.378-0.795-1.985c-0.76-0.797-1.613-0.801-2.004-0.847c-2.799-0.202-6.997-0.202-6.997-0.202 h-0.009c0,0-4.198,0-6.997,0.202C4.608,5.216,3.756,5.22,2.995,6.016C2.395,6.623,2.2,8.001,2.2,8.001S2,9.62,2,11.238v1.517 c0,1.618,0.2,3.237,0.2,3.237s0.195,1.378,0.795,1.985c0.761,0.797,1.76,0.771,2.205,0.855c1.6,0.153,6.8,0.201,6.8,0.201 s4.203-0.006,7.001-0.209c0.391-0.047,1.243-0.051,2.004-0.847c0.6-0.607,0.795-1.985,0.795-1.985s0.2-1.618,0.2-3.237v-1.517 C22,9.62,21.8,8.001,21.8,8.001z M9.935,14.594l-0.001-5.62l5.404,2.82L9.935,14.594z"></path></svg><span class="wp-block-social-link-label screen-reader-text">YouTube</span></a></li></ul>



<p class="has-text-align-center has-text-color has-link-color wp-elements-a0a2ac26ad214a49dac577734d259176" style="color:#84bd00"><a href="https://xojo.com/download/" target="_blank" rel="noreferrer noopener">Download Xojo</a></p>
]]></content:encoded>
					
		
		<enclosure url="https://blog.xojo.com/wp-content/uploads/2026/10/DesktopTable_FrozenColumns.mov" length="5935964" type="video/quicktime" />
<enclosure url="https://blog.xojo.com/wp-content/uploads/2026/10/DesktopTable_MouseGesture.mov" length="1111294" type="video/quicktime" />

			</item>
		<item>
		<title>Xcode 27 and iOS SDK 27: Debugging iOS Xojo apps</title>
		<link>https://blog.xojo.com/2026/09/15/xcode-27-and-ios-sdk-27-debugging-ios-xojo-apps/</link>
		
		<dc:creator><![CDATA[Javier Menendez]]></dc:creator>
		<pubDate>Tue, 15 Sep 2026 19:31:56 +0000</pubDate>
				<category><![CDATA[iOS]]></category>
		<category><![CDATA[Mobile]]></category>
		<category><![CDATA[Tips]]></category>
		<category><![CDATA[Apple]]></category>
		<category><![CDATA[Xcode]]></category>
		<guid isPermaLink="false">https://blog.xojo.com/?p=16544</guid>

					<description><![CDATA[From time to time Apple&#8217;s updates cause things that used to work to suddenly stop working. That is exactly what happens with the combination of&#8230;]]></description>
										<content:encoded><![CDATA[
<p>From time to time Apple&#8217;s updates cause things that used to work to suddenly stop working. That is exactly what happens with the combination of macOS Golden Gate, Xcode 27 and iOS SDK 27 (all release versions). With this setup, it is not possible to debug Xojo iOS projects on any of the iOS 27.0 Simulators, whether you are using the Simulator app or the new DeviceHub. Continue reading to find how to work around this.</p>



<span id="more-16544"></span>



<p>During internal testing for Xojo 2026r3, we identified this issue and have already fixed it. The workaround below is for users who have the previously described setup but are are running Xojo 2026r2.1 or earlier releases and need to test their iOS projects under any of the iOS 27 Simulators. Note that this issue doesn&#8217;t happen if you debug your iOS projects on a physical device running iOS 27.0.</p>



<h3 class="wp-block-heading">The workaround</h3>



<p>Until Xojo 2026r3 is released, the workaround is simple: just add a new Build Script to your iOS project, placed right before the Sign step, under the Build Settings &gt; iOS section of the Project Navigator:</p>



<p>Then add the following snippet of code to the associated Script Editor:</p>



<pre class="wp-block-code"><code>Var buildLocation As String = CurrentBuildLocation
Var appPackageName As String = CurrentBuildAppName

Var cleanBinaryName As String = ReplaceAll(appPackageName, ".app", "")

Var command As String
command = "cd " + buildLocation + _
" &amp;&amp; cd " + Chr(34) + appPackageName + Chr(34) + _
" &amp;&amp; install_name_tool -change /System/Library/PrivateFrameworks/WebKit.framework/WebKit /System/Library/Frameworks/WebKit.framework/WebKit " + Chr(34) + cleanBinaryName + Chr(34) + _
" &amp;&amp; cd .. " + _
" &amp;&amp; xattr -cr " + Chr(34) + appPackageName + Chr(34) + _
" &amp;&amp; codesign --force --deep --sign - " + Chr(34) + appPackageName + Chr(34)

Var result As String = DoShellCommand(command)</code></pre>



<p>To test it, select Project &gt; Run On and choose any of the available iOS 27.0 Simulators already installed on your Mac as part of the Xcode plus iOS SDK 27 installation process.</p>



<p>If everything goes well, your iOS project will run without issues as it did with previous Xcode and iOS SDK configurations, or even during the beta cycle for Xcode 27.0 and iOS SDK 27.0.</p>



<p><em>Javier Menendez is an engineer at Xojo and has been using Xojo since 1998. He lives in Castellón</em>, <em>Spain and hosts regular Xojo hangouts en español. Ask Javier questions on Twitter at <a href="https://twitter.com/xojoes" target="_blank" rel="noreferrer noopener">@XojoES</a> or on the <a href="https://forum.xojo.com/u/javier_menendez/summary" target="_blank" rel="noreferrer noopener">Xojo Forum</a>.</em></p>



<ul class="wp-block-social-links has-normal-icon-size is-content-justification-center is-layout-flex wp-container-core-social-links-is-layout-16018d1d wp-block-social-links-is-layout-flex"><li class="wp-social-link wp-social-link-facebook  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.facebook.com/goxojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M12 2C6.5 2 2 6.5 2 12c0 5 3.7 9.1 8.4 9.9v-7H7.9V12h2.5V9.8c0-2.5 1.5-3.9 3.8-3.9 1.1 0 2.2.2 2.2.2v2.5h-1.3c-1.2 0-1.6.8-1.6 1.6V12h2.8l-.4 2.9h-2.3v7C18.3 21.1 22 17 22 12c0-5.5-4.5-10-10-10z"></path></svg><span class="wp-block-social-link-label screen-reader-text">Facebook</span></a></li>

<li class="wp-social-link wp-social-link-x  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://x.com/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M13.982 10.622 20.54 3h-1.554l-5.693 6.618L8.745 3H3.5l6.876 10.007L3.5 21h1.554l6.012-6.989L15.868 21h5.245l-7.131-10.378Zm-2.128 2.474-.697-.997-5.543-7.93H8l4.474 6.4.697.996 5.815 8.318h-2.387l-4.745-6.787Z" /></svg><span class="wp-block-social-link-label screen-reader-text">X</span></a></li>

<li class="wp-social-link wp-social-link-linkedin  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.linkedin.com/company/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M19.7,3H4.3C3.582,3,3,3.582,3,4.3v15.4C3,20.418,3.582,21,4.3,21h15.4c0.718,0,1.3-0.582,1.3-1.3V4.3 C21,3.582,20.418,3,19.7,3z M8.339,18.338H5.667v-8.59h2.672V18.338z M7.004,8.574c-0.857,0-1.549-0.694-1.549-1.548 c0-0.855,0.691-1.548,1.549-1.548c0.854,0,1.547,0.694,1.547,1.548C8.551,7.881,7.858,8.574,7.004,8.574z M18.339,18.338h-2.669 v-4.177c0-0.996-0.017-2.278-1.387-2.278c-1.389,0-1.601,1.086-1.601,2.206v4.249h-2.667v-8.59h2.559v1.174h0.037 c0.356-0.675,1.227-1.387,2.526-1.387c2.703,0,3.203,1.779,3.203,4.092V18.338z"></path></svg><span class="wp-block-social-link-label screen-reader-text">LinkedIn</span></a></li>

<li class="wp-social-link wp-social-link-github  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://github.com/topics/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M12,2C6.477,2,2,6.477,2,12c0,4.419,2.865,8.166,6.839,9.489c0.5,0.09,0.682-0.218,0.682-0.484 c0-0.236-0.009-0.866-0.014-1.699c-2.782,0.602-3.369-1.34-3.369-1.34c-0.455-1.157-1.11-1.465-1.11-1.465 c-0.909-0.62,0.069-0.608,0.069-0.608c1.004,0.071,1.532,1.03,1.532,1.03c0.891,1.529,2.341,1.089,2.91,0.833 c0.091-0.647,0.349-1.086,0.635-1.337c-2.22-0.251-4.555-1.111-4.555-4.943c0-1.091,0.39-1.984,1.03-2.682 C6.546,8.54,6.202,7.524,6.746,6.148c0,0,0.84-0.269,2.75,1.025C10.295,6.95,11.15,6.84,12,6.836 c0.85,0.004,1.705,0.114,2.504,0.336c1.909-1.294,2.748-1.025,2.748-1.025c0.546,1.376,0.202,2.394,0.1,2.646 c0.64,0.699,1.026,1.591,1.026,2.682c0,3.841-2.337,4.687-4.565,4.935c0.359,0.307,0.679,0.917,0.679,1.852 c0,1.335-0.012,2.415-0.012,2.741c0,0.269,0.18,0.579,0.688,0.481C19.138,20.161,22,16.416,22,12C22,6.477,17.523,2,12,2z"></path></svg><span class="wp-block-social-link-label screen-reader-text">GitHub</span></a></li>

<li class="wp-social-link wp-social-link-youtube  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.youtube.com/c/XojoInc" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M21.8,8.001c0,0-0.195-1.378-0.795-1.985c-0.76-0.797-1.613-0.801-2.004-0.847c-2.799-0.202-6.997-0.202-6.997-0.202 h-0.009c0,0-4.198,0-6.997,0.202C4.608,5.216,3.756,5.22,2.995,6.016C2.395,6.623,2.2,8.001,2.2,8.001S2,9.62,2,11.238v1.517 c0,1.618,0.2,3.237,0.2,3.237s0.195,1.378,0.795,1.985c0.761,0.797,1.76,0.771,2.205,0.855c1.6,0.153,6.8,0.201,6.8,0.201 s4.203-0.006,7.001-0.209c0.391-0.047,1.243-0.051,2.004-0.847c0.6-0.607,0.795-1.985,0.795-1.985s0.2-1.618,0.2-3.237v-1.517 C22,9.62,21.8,8.001,21.8,8.001z M9.935,14.594l-0.001-5.62l5.404,2.82L9.935,14.594z"></path></svg><span class="wp-block-social-link-label screen-reader-text">YouTube</span></a></li></ul>



<p class="has-text-align-center has-text-color has-link-color wp-elements-a0a2ac26ad214a49dac577734d259176" style="color:#84bd00"><a href="https://xojo.com/download/" target="_blank" rel="noreferrer noopener">Download Xojo</a></p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Postmortem: Developer ID Selector for macOS Apps</title>
		<link>https://blog.xojo.com/2026/09/10/postmortem-developer-id-selector-for-macos-apps/</link>
		
		<dc:creator><![CDATA[Javier Menendez]]></dc:creator>
		<pubDate>Thu, 10 Sep 2026 10:47:00 +0000</pubDate>
				<category><![CDATA[Mac]]></category>
		<category><![CDATA[Security]]></category>
		<category><![CDATA[Tips]]></category>
		<category><![CDATA[Apple]]></category>
		<category><![CDATA[Apple Developer Account]]></category>
		<guid isPermaLink="false">https://blog.xojo.com/?p=16515</guid>

					<description><![CDATA[Some time ago, an edge case involving macOS development certificates came up on the Xojo Forum. Despite the improvements introduced in Xojo 2026r1, I have&#8230;]]></description>
										<content:encoded><![CDATA[
<p>Some time ago, an edge case involving macOS development certificates came up on the <a href="https://forum.xojo.com/t/developer-id-popup-invalid-entry/88762">Xojo Forum</a>. Despite the improvements introduced in Xojo 2026r1, I have to admit that this particular scenario fell outside of what we accounted for. Continue reading to learn more about this issue and its solution.</p>



<span id="more-16515"></span>



<p>The issue the user was dealing with was the Developer ID popup menu showing a different name than expected for the Developer ID Team. Interestingly, this problem didn&#8217;t occur on his second Mac.</p>



<p>As a result, he was not able to select any of the &#8220;Build For&#8221; options, because the remaining developer certificates installed on that Mac were issued under the same Team ID but with a different Company Name.</p>



<p>In this particular case, a couple of X.509 certificates OIDs (think of these as certificate attributes) are worth highlighting:</p>



<ul class="wp-block-list">
<li><strong>2.5.4.11 &#8211; Organizational Unit Name</strong> <strong>(OU)</strong>: This corresponds to the Team ID for Apple Developer Certificates. It is unique and never changes.</li>



<li><strong>2.5.4.10 &#8211; Organization Name (O)</strong>, also known as the Legal Entity or Company Name: This value can be changed from the Apple Developer portal, under Account &gt; Membership Details, but only if your developer program membership is registered as an Organization (not an Individual).</li>
</ul>



<h3 class="wp-block-heading">The underlying problem</h3>



<p>In this particular case, several factors converged:</p>



<ul class="wp-block-list">
<li>The certificate issued under the unexpected Team name had expired long time ago but was still present on that Mac. This part wasn&#8217;t too bad, Xojo can safely ignore expired certificates.</li>



<li>The real issue was that this expired certificate had been installed on that Mac long before the other (correct) certificates using the current Organization Name. Because of this, when Xojo iterated through the installed certificates at the system level, it encountered the expired one <em>first</em> &#8211; and mistakenly used its Organization Name for all certificates sharing the same Team ID. </li>
</ul>



<p>Now that we&#8217;re aware of this behavior, we have fixed it for Xojo 2026r3.</p>



<h3 class="wp-block-heading">The Solution</h3>



<p>Once we identified what was happening, the fix to this particular case was simple: delete the expired, offending certificate from the Keychain Access app on that Mac.</p>



<h3 class="wp-block-heading">The Recipe</h3>



<p>If you run into a similar issue, whether it is trouble selecting a specific Team ID, or missing &#8220;Build For&#8221; options, the best first step is to use the Inspect&#8230; option under the Developer ID popup menu.</p>



<p>The Certificate Inspector lists all installed certificates for every Team in a much simpler way than digging through Keychain Access. It also provides additional details and, when possible, direct actions to resolve some of the most common issues related to managing your Apple Developer Certificates.</p>



<h3 class="wp-block-heading">Reviewing Certificates in More Depth</h3>



<p>Alternatively, or if you are running a Xojo version prior to Xojo 2026r1, you can inspect your certificates manually by running the following command in Terminal:</p>



<pre class="wp-block-code"><code>security find-certificate -a -p | awk '/---BEGIN CERTIFICATE---/{flag=1; print; next} /---END CERTIFICATE---/{print; flag=0; print "---END---"} flag' | while IFS= read -r line; do if &#91; "$line" = "---END---" ]; then echo "$cert" | openssl x509 -noout -subject -enddate 2&gt;/dev/null; cert=""; else cert="$cert$line"$'\n'; fi; done</code></pre>



<p>The output will list, in the Terminal window, all the Apple Developer certificates found on your computer along with some key pieces of information worth inspecting:</p>



<ul class="wp-block-list">
<li><strong>CN (Common Name</strong>): Indicates the certificate type, for example, Development, Developer ID Application, or any other Apple development certificate.</li>



<li><strong>OU (Organizational Unit/Team ID):</strong> Remember, this value never changes for your Apple Developer Program membership.</li>



<li><strong>O (Organization</strong>): The current Organization Name associated with the certificate. This can be changed, but only for Organization-type membership (not Individual).</li>



<li><strong>notAfter</strong>. The expiration date for that certificate.</li>
</ul>



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



<p>This edge case is a good reminder that expired certificates sitting in your Keychain can quietly cause unexpected issues. Thanks to the fix in Xojo 2026r3 and the new Certificate Inspector, spotting and resolving these problems are now much easier.</p>



<p><em>Javier Menendez is an engineer at Xojo and has been using Xojo since 1998. He lives in Castellón</em>, <em>Spain and hosts regular Xojo hangouts en español. Ask Javier questions on Twitter at <a href="https://twitter.com/xojoes" target="_blank" rel="noreferrer noopener">@XojoES</a> or on the <a href="https://forum.xojo.com/u/javier_menendez/summary" target="_blank" rel="noreferrer noopener">Xojo Forum</a>.</em></p>



<ul class="wp-block-social-links has-normal-icon-size is-content-justification-center is-layout-flex wp-container-core-social-links-is-layout-16018d1d wp-block-social-links-is-layout-flex"><li class="wp-social-link wp-social-link-facebook  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.facebook.com/goxojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M12 2C6.5 2 2 6.5 2 12c0 5 3.7 9.1 8.4 9.9v-7H7.9V12h2.5V9.8c0-2.5 1.5-3.9 3.8-3.9 1.1 0 2.2.2 2.2.2v2.5h-1.3c-1.2 0-1.6.8-1.6 1.6V12h2.8l-.4 2.9h-2.3v7C18.3 21.1 22 17 22 12c0-5.5-4.5-10-10-10z"></path></svg><span class="wp-block-social-link-label screen-reader-text">Facebook</span></a></li>

<li class="wp-social-link wp-social-link-x  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://x.com/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M13.982 10.622 20.54 3h-1.554l-5.693 6.618L8.745 3H3.5l6.876 10.007L3.5 21h1.554l6.012-6.989L15.868 21h5.245l-7.131-10.378Zm-2.128 2.474-.697-.997-5.543-7.93H8l4.474 6.4.697.996 5.815 8.318h-2.387l-4.745-6.787Z" /></svg><span class="wp-block-social-link-label screen-reader-text">X</span></a></li>

<li class="wp-social-link wp-social-link-linkedin  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.linkedin.com/company/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M19.7,3H4.3C3.582,3,3,3.582,3,4.3v15.4C3,20.418,3.582,21,4.3,21h15.4c0.718,0,1.3-0.582,1.3-1.3V4.3 C21,3.582,20.418,3,19.7,3z M8.339,18.338H5.667v-8.59h2.672V18.338z M7.004,8.574c-0.857,0-1.549-0.694-1.549-1.548 c0-0.855,0.691-1.548,1.549-1.548c0.854,0,1.547,0.694,1.547,1.548C8.551,7.881,7.858,8.574,7.004,8.574z M18.339,18.338h-2.669 v-4.177c0-0.996-0.017-2.278-1.387-2.278c-1.389,0-1.601,1.086-1.601,2.206v4.249h-2.667v-8.59h2.559v1.174h0.037 c0.356-0.675,1.227-1.387,2.526-1.387c2.703,0,3.203,1.779,3.203,4.092V18.338z"></path></svg><span class="wp-block-social-link-label screen-reader-text">LinkedIn</span></a></li>

<li class="wp-social-link wp-social-link-github  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://github.com/topics/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M12,2C6.477,2,2,6.477,2,12c0,4.419,2.865,8.166,6.839,9.489c0.5,0.09,0.682-0.218,0.682-0.484 c0-0.236-0.009-0.866-0.014-1.699c-2.782,0.602-3.369-1.34-3.369-1.34c-0.455-1.157-1.11-1.465-1.11-1.465 c-0.909-0.62,0.069-0.608,0.069-0.608c1.004,0.071,1.532,1.03,1.532,1.03c0.891,1.529,2.341,1.089,2.91,0.833 c0.091-0.647,0.349-1.086,0.635-1.337c-2.22-0.251-4.555-1.111-4.555-4.943c0-1.091,0.39-1.984,1.03-2.682 C6.546,8.54,6.202,7.524,6.746,6.148c0,0,0.84-0.269,2.75,1.025C10.295,6.95,11.15,6.84,12,6.836 c0.85,0.004,1.705,0.114,2.504,0.336c1.909-1.294,2.748-1.025,2.748-1.025c0.546,1.376,0.202,2.394,0.1,2.646 c0.64,0.699,1.026,1.591,1.026,2.682c0,3.841-2.337,4.687-4.565,4.935c0.359,0.307,0.679,0.917,0.679,1.852 c0,1.335-0.012,2.415-0.012,2.741c0,0.269,0.18,0.579,0.688,0.481C19.138,20.161,22,16.416,22,12C22,6.477,17.523,2,12,2z"></path></svg><span class="wp-block-social-link-label screen-reader-text">GitHub</span></a></li>

<li class="wp-social-link wp-social-link-youtube  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.youtube.com/c/XojoInc" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M21.8,8.001c0,0-0.195-1.378-0.795-1.985c-0.76-0.797-1.613-0.801-2.004-0.847c-2.799-0.202-6.997-0.202-6.997-0.202 h-0.009c0,0-4.198,0-6.997,0.202C4.608,5.216,3.756,5.22,2.995,6.016C2.395,6.623,2.2,8.001,2.2,8.001S2,9.62,2,11.238v1.517 c0,1.618,0.2,3.237,0.2,3.237s0.195,1.378,0.795,1.985c0.761,0.797,1.76,0.771,2.205,0.855c1.6,0.153,6.8,0.201,6.8,0.201 s4.203-0.006,7.001-0.209c0.391-0.047,1.243-0.051,2.004-0.847c0.6-0.607,0.795-1.985,0.795-1.985s0.2-1.618,0.2-3.237v-1.517 C22,9.62,21.8,8.001,21.8,8.001z M9.935,14.594l-0.001-5.62l5.404,2.82L9.935,14.594z"></path></svg><span class="wp-block-social-link-label screen-reader-text">YouTube</span></a></li></ul>



<p class="has-text-align-center has-text-color has-link-color wp-elements-a0a2ac26ad214a49dac577734d259176" style="color:#84bd00"><a href="https://xojo.com/download/" target="_blank" rel="noreferrer noopener">Download Xojo</a></p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Protect Passwords, Tokens, Requests, and Updates with the Crypto Module</title>
		<link>https://blog.xojo.com/2026/09/01/protect-passwords-tokens-requests-and-updates-with-the-crypto-module/</link>
		
		<dc:creator><![CDATA[Gabriel Ludosanu]]></dc:creator>
		<pubDate>Tue, 01 Sep 2026 22:04:00 +0000</pubDate>
				<category><![CDATA[Desktop]]></category>
		<category><![CDATA[Security]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[AES]]></category>
		<category><![CDATA[application security]]></category>
		<category><![CDATA[Crypto]]></category>
		<category><![CDATA[Ed25519]]></category>
		<category><![CDATA[Encryption]]></category>
		<category><![CDATA[Hashing]]></category>
		<category><![CDATA[HMAC]]></category>
		<category><![CDATA[PBKDF2]]></category>
		<guid isPermaLink="false">https://blog.xojo.com/?p=16507</guid>

					<description><![CDATA[The&#160;Crypto&#160;module covers several different jobs. The hard part is usually not finding a function; it is choosing the right one for the problem in front&#8230;]]></description>
										<content:encoded><![CDATA[
<p>The&nbsp;<a href="https://documentation.xojo.com/api/cryptography/crypto.html" target="_blank" rel="noreferrer noopener"><code>Crypto</code></a>&nbsp;module covers several different jobs. The hard part is usually not finding a function; it is choosing the right one for the problem in front of you.</p>



<p>Which function should you use when your app needs to:</p>



<ul class="wp-block-list">
<li>remember a user&#8217;s password,</li>



<li>save an API token in a local settings file,</li>



<li>check that an API request was not changed, or</li>



<li>verify that an update came from you?</li>
</ul>



<pre class="wp-block-preformatted">The examples below answer those questions with small, focused scenarios. They show where each function fits. They are not complete security products.</pre>



<p>A good starting point is:</p>



<ul class="wp-block-list">
<li>Use&nbsp;<a href="https://documentation.xojo.com/api/cryptography/crypto.html#crypto-pbkdf2" target="_blank" rel="noreferrer noopener"><strong>PBKDF2</strong></a>&nbsp;when you need to check a password later.</li>



<li>Use&nbsp;<a href="https://documentation.xojo.com/api/cryptography/crypto.html#crypto-aesencrypt" target="_blank" rel="noreferrer noopener"><strong>AES</strong></a>&nbsp;when you need to hide data that your app must read again.</li>



<li>Use&nbsp;<a href="https://documentation.xojo.com/api/cryptography/crypto.html#crypto-hmac" target="_blank" rel="noreferrer noopener"><strong>HMAC</strong></a>&nbsp;when two trusted systems share a secret and need to detect changed messages.</li>



<li>Use&nbsp;<a href="https://documentation.xojo.com/api/cryptography/crypto.html#crypto-ed25519generatekeypair" target="_blank" rel="noreferrer noopener"><strong>Ed25519</strong></a>&nbsp;when one side signs data and other parties only need to verify it.</li>
</ul>



<h2 class="wp-block-heading" id="example-1-remembering-a-users-password-with-pbkdf2">Example 1: Remembering a user&#8217;s password with PBKDF2</h2>



<p>Imagine a desktop or web app with a login screen. When a user creates an account, you need to save something that lets you check the password later.</p>



<pre class="wp-block-preformatted">Do not save this:&nbsp;correct horse battery staple</pre>



<p>If somebody gets the database, they immediately have the user&#8217;s password. A plain SHA-256 hash is not a good replacement because attackers can calculate fast hashes very quickly and try large lists of common passwords. PBKDF2 is designed for this job. It combines the password with a random salt and repeats the calculation many times.</p>



<pre class="wp-block-code"><code>Var password As String = "correct horse battery staple"
Var salt As String = EncodeHex(Crypto.GenerateRandomBytes(16))
Var iterations As Integer = 100000
Var derived As MemoryBlock = Crypto.PBKDF2(salt, password, iterations, 32, Crypto.HashAlgorithms.SHA2_512)
Var storedHash As String = EncodeHex(derived)</code></pre>



<p>Save&nbsp;<code>salt</code>,&nbsp;<code>iterations</code>, the algorithm name, and&nbsp;<code>storedHash</code>&nbsp;in the user&#8217;s record. The salt does not need to be secret. You need it again when the user logs in.</p>



<pre class="wp-block-code"><code>Var suppliedPassword As String = "correct horse battery staple"
Var calculated As MemoryBlock = Crypto.PBKDF2(salt, suppliedPassword, iterations, 32, Crypto.HashAlgorithms.SHA2_512)
Var calculatedHash As String = EncodeHex(calculated)

If calculatedHash = storedHash Then
  MessageBox("Password accepted")
Else
  MessageBox("Password rejected")
End If</code></pre>



<p>The app never needs to recover the original password. It calculates the value again and compares it with the stored one.</p>



<p>The iteration count in this example is only an example. Test it on the slowest computer you support. Store the count with the hash so you can increase it later and update old records after a successful login.</p>



<p>Use&nbsp;<code>Crypto.GenerateRandomBytes</code>&nbsp;here because the salt must not be predictable. The same function is useful when you need a random token, nonce, or initialization vector.</p>



<h2 class="wp-block-heading" id="example-2-saving-an-api-token-in-an-encrypted-settings-file">Example 2: Saving an API token in an encrypted settings file</h2>



<p>Now imagine a desktop app that lets a user connect to an online service. After the user enters an API token, the app should remember it without saving readable text to its settings file.</p>



<p>This is a job for symmetric encryption. The app uses the same secret key to encrypt and decrypt the value.</p>



<p>AES accepts keys that are 16, 24, or 32 bytes long. The initialization vector is 16 bytes for AES. This example uses a 32-byte key and a new 16-byte IV:</p>



<pre class="wp-block-code"><code>Var secretKey As String = Crypto.GenerateRandomBytes(32)
Var initializationVector As MemoryBlock = Crypto.GenerateRandomBytes(16)
Var apiToken As String = "token-from-the-service"
Var encryptedToken As MemoryBlock = Crypto.AESEncrypt(secretKey, apiToken, Crypto.BlockModes.CBC, initializationVector)</code></pre>



<p>To read the token later:</p>



<pre class="wp-block-code"><code>Var decryptedToken As MemoryBlock = Crypto.AESDecrypt(secretKey, encryptedToken, Crypto.BlockModes.CBC, initializationVector)
Var apiTokenAgain As String = decryptedToken</code></pre>



<p>The IV is not a password and does not need to be secret. Save it with the encrypted value. You need the same IV for decryption.</p>



<p>The key is the difficult part. If you generate a new key every time the app starts, the app cannot decrypt yesterday&#8217;s settings. A real application must store the key in a suitable secret store, derive it from a user-provided secret, or keep the sensitive value on a server. Do not put a production key directly in the source code.</p>



<p>The encrypted record might contain these fields:</p>



<pre class="wp-block-code"><code>version
iv
ciphertext</code></pre>



<p>Store the IV and ciphertext as Base64 or hexadecimal text if the settings format cannot hold binary data. Store a version so you can change the format later.</p>



<p>CBC encryption hides the token, but it does not prove that the ciphertext was not changed. For real data, authenticate the encrypted record as well. With CBC, that means using an encrypt-then-MAC design with a separate MAC key. Another option is a vetted authenticated-encryption library or a service that provides an AEAD mode.</p>



<p>Do not reuse an IV with the same key, and do not use ECB mode for application data.</p>



<h2 class="wp-block-heading" id="example-3-signing-an-api-request-with-hmac">Example 3: Signing an API request with HMAC</h2>



<p>Suppose you control both a client and a server application. The client sends an order to the server, and the server needs to know whether somebody changed the request while it was being sent.</p>



<p>The client and server can share a secret. The client signs the request with HMAC, and the server calculates the same HMAC. If the values differ, the server rejects the request.</p>



<pre class="wp-block-code"><code>Var sharedSecret As String = "replace-this-with-a-real-secret"
Var requestText As String = "POST|/api/orders|1714492800|{""id"":42}"
Var requestData As MemoryBlock = requestText
Var signature As MemoryBlock = Crypto.HMAC(sharedSecret, requestData, Crypto.HashAlgorithms.SHA2_256)
Var signatureText As String = EncodeBase64(signature)</code></pre>



<p>Send&nbsp;<code>requestText</code>&nbsp;and&nbsp;<code>signatureText</code>&nbsp;to the server. The server must build exactly the same text before calculating its own signature. A different separator, line ending, or JSON layout produces a different result.</p>



<p>A signature by itself does not stop somebody from sending the same valid request again. Include a timestamp and reject requests that are too old. For an operation that must only happen once, include a unique request ID and record IDs that the server has already processed.</p>



<p>HMAC is a good fit for two backend services or a controlled client-server arrangement. It is a poor fit when you ship the shared secret inside an untrusted desktop or mobile app. A secret compiled into an app can eventually be extracted.</p>



<h2 class="wp-block-heading" id="example-4-verifying-an-update-with-ed25519">Example 4: Verifying an update with Ed25519</h2>



<p>A different situation comes up when you distribute application updates. The update server should be able to sign a file, but the installed app should only need to verify it. The installed app should not possess a secret that could create fake signatures.</p>



<p>Use a public and private key pair:</p>



<ul class="wp-block-list">
<li>Keep the private key on the signing machine.</li>



<li>Put the public key in the application or distribute it through a trusted channel.</li>
</ul>



<pre class="wp-block-code"><code>Var privateKey As String
Var publicKey As String

If Crypto.ED25519GenerateKeyPair(privateKey, publicKey) Then
  Var updateInfo As String = "version=4.2.1|sha256=..."
  Var signature As MemoryBlock = Crypto.ED25519Sign(updateInfo, privateKey)

  If signature &lt;&gt; Nil And Crypto.ED25519VerifySignature(updateInfo, signature, publicKey) Then
    MessageBox("Update information is authentic")
  End If
End If</code></pre>



<p>In a real updater, verify the signature before trusting the version or downloading the file. The signature does not prove that the update is safe by itself. It proves that the data matches the private key associated with the public key.</p>



<p>Keep the exact bytes stable. If the signing tool adds a line ending but the app removes it before verification, the signature will fail.</p>



<h2 class="wp-block-heading" id="which-function-solves-which-problem">Which function solves which problem?</h2>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th class="has-text-align-left" data-align="left">Problem</th><th class="has-text-align-left" data-align="left">Use</th><th class="has-text-align-left" data-align="left">What you store or send</th></tr></thead><tbody><tr><td>Check a password later</td><td><code>Crypto.PBKDF2</code></td><td>Salt, iteration count, algorithm, derived value</td></tr><tr><td>Create an unpredictable salt or IV</td><td><code>Crypto.GenerateRandomBytes</code></td><td>The salt or IV, when the operation needs it later</td></tr><tr><td>Hide data that your app must decrypt</td><td><code>Crypto.AESEncrypt</code>&nbsp;and&nbsp;<code>Crypto.AESDecrypt</code></td><td>Key, IV, and ciphertext, using a safe storage design</td></tr><tr><td>Detect changes to a shared-secret request</td><td><code>Crypto.HMAC</code></td><td>Message and HMAC value</td></tr><tr><td>Verify data signed by another system</td><td><code>Crypto.ED25519Sign</code>&nbsp;and&nbsp;<code>Crypto.ED25519VerifySignature</code></td><td>Signature and public key</td></tr><tr><td>Create a fixed fingerprint of public data</td><td><code>Crypto.Hash</code></td><td>The expected hash from a trusted source</td></tr></tbody></table></figure>



<p>Start with the problem, not the function name. Ask what the other side needs to do:</p>



<ul class="wp-block-list">
<li>Does it need to check a password? Use PBKDF2.</li>



<li>Does it need to read the original data? Use encryption.</li>



<li>Does it need to detect a changed message and share a secret with the sender? Use HMAC.</li>



<li>Does it need to verify a message without being able to create signatures? Use a public-key signature.</li>
</ul>



<h2 class="wp-block-heading" id="a-short-safety-checklist">A short safety checklist</h2>



<ol class="wp-block-list">
<li>Never store plaintext passwords.</li>



<li>Do not use a fast general-purpose hash as a password-storage scheme.</li>



<li>Do not hard-code production secrets in source code or a desktop application.</li>



<li>Generate salts and IVs with&nbsp;<code>Crypto.GenerateRandomBytes</code>.</li>



<li>Use&nbsp;<code>SHA2_256</code>&nbsp;or stronger for new hashes and HMACs. Avoid MD5 and SHA-1 for new security designs.</li>



<li>Do not treat AES-CBC ciphertext as authenticated unless you add an integrity check.</li>



<li>Keep the exact bytes being signed stable.</li>



<li>Test wrong passwords, wrong keys, changed messages, replayed requests, and corrupted ciphertext.</li>



<li>Check the Xojo compatibility notes for every algorithm you choose.</li>



<li>Use an established format or library instead of inventing a cryptographic protocol.</li>
</ol>



<p>The&nbsp;<code>Crypto</code>&nbsp;module gives you the operations. Your application still has to decide where keys live, what gets signed, how data is formatted, and how keys are replaced. Those decisions determine whether the example can grow into something you can support.</p>



<p><em>Gabriel is a digital marketing enthusiast who loves coding with Xojo to create cool software tools for any platform. He is always eager to learn and share new ideas!</em></p>



<ul class="wp-block-social-links has-normal-icon-size is-content-justification-center is-layout-flex wp-container-core-social-links-is-layout-16018d1d wp-block-social-links-is-layout-flex"><li class="wp-social-link wp-social-link-facebook  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.facebook.com/goxojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M12 2C6.5 2 2 6.5 2 12c0 5 3.7 9.1 8.4 9.9v-7H7.9V12h2.5V9.8c0-2.5 1.5-3.9 3.8-3.9 1.1 0 2.2.2 2.2.2v2.5h-1.3c-1.2 0-1.6.8-1.6 1.6V12h2.8l-.4 2.9h-2.3v7C18.3 21.1 22 17 22 12c0-5.5-4.5-10-10-10z"></path></svg><span class="wp-block-social-link-label screen-reader-text">Facebook</span></a></li>

<li class="wp-social-link wp-social-link-x  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://x.com/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M13.982 10.622 20.54 3h-1.554l-5.693 6.618L8.745 3H3.5l6.876 10.007L3.5 21h1.554l6.012-6.989L15.868 21h5.245l-7.131-10.378Zm-2.128 2.474-.697-.997-5.543-7.93H8l4.474 6.4.697.996 5.815 8.318h-2.387l-4.745-6.787Z" /></svg><span class="wp-block-social-link-label screen-reader-text">X</span></a></li>

<li class="wp-social-link wp-social-link-linkedin  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.linkedin.com/company/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M19.7,3H4.3C3.582,3,3,3.582,3,4.3v15.4C3,20.418,3.582,21,4.3,21h15.4c0.718,0,1.3-0.582,1.3-1.3V4.3 C21,3.582,20.418,3,19.7,3z M8.339,18.338H5.667v-8.59h2.672V18.338z M7.004,8.574c-0.857,0-1.549-0.694-1.549-1.548 c0-0.855,0.691-1.548,1.549-1.548c0.854,0,1.547,0.694,1.547,1.548C8.551,7.881,7.858,8.574,7.004,8.574z M18.339,18.338h-2.669 v-4.177c0-0.996-0.017-2.278-1.387-2.278c-1.389,0-1.601,1.086-1.601,2.206v4.249h-2.667v-8.59h2.559v1.174h0.037 c0.356-0.675,1.227-1.387,2.526-1.387c2.703,0,3.203,1.779,3.203,4.092V18.338z"></path></svg><span class="wp-block-social-link-label screen-reader-text">LinkedIn</span></a></li>

<li class="wp-social-link wp-social-link-github  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://github.com/topics/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M12,2C6.477,2,2,6.477,2,12c0,4.419,2.865,8.166,6.839,9.489c0.5,0.09,0.682-0.218,0.682-0.484 c0-0.236-0.009-0.866-0.014-1.699c-2.782,0.602-3.369-1.34-3.369-1.34c-0.455-1.157-1.11-1.465-1.11-1.465 c-0.909-0.62,0.069-0.608,0.069-0.608c1.004,0.071,1.532,1.03,1.532,1.03c0.891,1.529,2.341,1.089,2.91,0.833 c0.091-0.647,0.349-1.086,0.635-1.337c-2.22-0.251-4.555-1.111-4.555-4.943c0-1.091,0.39-1.984,1.03-2.682 C6.546,8.54,6.202,7.524,6.746,6.148c0,0,0.84-0.269,2.75,1.025C10.295,6.95,11.15,6.84,12,6.836 c0.85,0.004,1.705,0.114,2.504,0.336c1.909-1.294,2.748-1.025,2.748-1.025c0.546,1.376,0.202,2.394,0.1,2.646 c0.64,0.699,1.026,1.591,1.026,2.682c0,3.841-2.337,4.687-4.565,4.935c0.359,0.307,0.679,0.917,0.679,1.852 c0,1.335-0.012,2.415-0.012,2.741c0,0.269,0.18,0.579,0.688,0.481C19.138,20.161,22,16.416,22,12C22,6.477,17.523,2,12,2z"></path></svg><span class="wp-block-social-link-label screen-reader-text">GitHub</span></a></li>

<li class="wp-social-link wp-social-link-youtube  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.youtube.com/c/XojoInc" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M21.8,8.001c0,0-0.195-1.378-0.795-1.985c-0.76-0.797-1.613-0.801-2.004-0.847c-2.799-0.202-6.997-0.202-6.997-0.202 h-0.009c0,0-4.198,0-6.997,0.202C4.608,5.216,3.756,5.22,2.995,6.016C2.395,6.623,2.2,8.001,2.2,8.001S2,9.62,2,11.238v1.517 c0,1.618,0.2,3.237,0.2,3.237s0.195,1.378,0.795,1.985c0.761,0.797,1.76,0.771,2.205,0.855c1.6,0.153,6.8,0.201,6.8,0.201 s4.203-0.006,7.001-0.209c0.391-0.047,1.243-0.051,2.004-0.847c0.6-0.607,0.795-1.985,0.795-1.985s0.2-1.618,0.2-3.237v-1.517 C22,9.62,21.8,8.001,21.8,8.001z M9.935,14.594l-0.001-5.62l5.404,2.82L9.935,14.594z"></path></svg><span class="wp-block-social-link-label screen-reader-text">YouTube</span></a></li></ul>



<p class="has-text-align-center has-text-color has-link-color wp-elements-a0a2ac26ad214a49dac577734d259176" style="color:#84bd00"><a href="https://xojo.com/download/" target="_blank" rel="noreferrer noopener">Download Xojo</a></p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>How to code-sign Windows apps, including an automation script</title>
		<link>https://blog.xojo.com/2026/08/26/how-to-code-sign-windows-apps-including-an-automation-script/</link>
		
		<dc:creator><![CDATA[Gabriel Ludosanu]]></dc:creator>
		<pubDate>Wed, 26 Aug 2026 16:03:14 +0000</pubDate>
				<category><![CDATA[General]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[Windows]]></category>
		<category><![CDATA[azure-artifact]]></category>
		<category><![CDATA[code-signing]]></category>
		<guid isPermaLink="false">https://blog.xojo.com/?p=16459</guid>

					<description><![CDATA[You build a Windows app, zip it up, hand it to a user, and Windows may hit them with&#160;&#8220;Windows protected your PC&#8221;. A clean but&#8230;]]></description>
										<content:encoded><![CDATA[
<p>You build a Windows app, zip it up, hand it to a user, and Windows may hit them with&nbsp;<em>&#8220;Windows protected your PC&#8221;</em>. A clean but unsigned binary has no publisher identity or established SmartScreen reputation, so Windows has little reason to trust it.</p>



<p>This guide walks you through the complete process of signing EXE and DLL files on Windows with&nbsp;<strong>Azure Artifact Signing</strong>.</p>



<p>Here&#8217;s the shape of it, so you know what you&#8217;re signing up for:</p>



<ul class="wp-block-list">
<li><strong>One-time setup (Steps 1–9):</strong>&nbsp;Azure account, portal clicks, and identity validation. This is the slow part. Budget a day to a week for the identity check to clear.</li>



<li><strong>Every build (Step 10):</strong>&nbsp;one script that signs your exe and DLLs in seconds.</li>
</ul>



<p>If you&#8217;ve already done the setup, skip straight to&nbsp;Step 10.</p>



<h2 class="wp-block-heading" id="why-i-picked-azure-artifact-signing">Why I Picked Azure Artifact Signing</h2>



<ul class="wp-block-list">
<li><strong>$9.99/mo</strong>&nbsp;for up to 5,000 signatures (Basic tier), with no USB hardware token to manage.</li>



<li><strong>Fully managed.</strong>&nbsp;Microsoft rotates the certificates daily behind the scenes. You never see or store a private key.</li>



<li><strong>Identity-based publisher reputation.</strong>&nbsp;Public Trust signing ties the signature to your validated identity instead of a certificate you manage yourself. SmartScreen warnings can still appear for first-time or low-volume downloads; signing does not guarantee they will disappear immediately.</li>
</ul>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p><strong>A note on names:</strong>&nbsp;this service was called &#8220;Azure Trusted Signing&#8221; until recently. Same thing, new name. If you see &#8220;Trusted Signing&#8221; in older docs or screenshots, it&#8217;s the same service.</p>
</blockquote>



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



<h2 class="wp-block-heading" id="prerequisites">Prerequisites</h2>



<ol class="wp-block-list">
<li>A Microsoft account (you get one when you sign up with Azure).</li>



<li>A&nbsp;<strong>paid Azure subscription.</strong>&nbsp;<img src="https://s.w.org/images/core/emoji/17.0.2/72x72/26a0.png" alt="⚠" class="wp-smiley" style="height: 1em; max-height: 1em;" /> This is the #1 early blocker: Artifact Signing&nbsp;<strong>does not work on free/trial/sponsored subscriptions.</strong>&nbsp;Upgrade to&nbsp;<strong>pay-as-you-go</strong>&nbsp;first (Cost Management + Billing → your subscription → upgrade) &#8211;&nbsp;<a href="https://azure.microsoft.com/en-us/products/artifact-signing" target="_blank" rel="noreferrer noopener">https://azure.microsoft.com/en-us/products/artifact-signing</a>.</li>
</ol>



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



<h2 class="wp-block-heading" id="step-1--register-the-resource-provider">Step 1 — Register the resource provider</h2>



<p>Quick orientation first: an Azure&nbsp;<strong>subscription</strong>&nbsp;is the billing container for everything you create. Azure charges your services to it, and it also defines where those resources live and who can access them. When you signed up, Azure created one for you automatically (often with a forgettable default name like &#8220;Azure subscription 1&#8221;).</p>



<p>A separate subscription is optional. If you want clean billing and access boundaries for signing, create or dedicate one; otherwise, use your existing paid subscription and keep the signing resources in a dedicated resource group.</p>



<p>Then:</p>



<ol class="wp-block-list">
<li>Portal →&nbsp;<strong>Subscriptions</strong>&nbsp;→ the subscription you chose.</li>



<li>Left menu →&nbsp;<strong>Settings → Resource providers</strong>.</li>



<li>Find&nbsp;<strong><code>Microsoft.CodeSigning</code></strong>&nbsp;→ click the&nbsp;<strong>…</strong>&nbsp;→&nbsp;<strong>Register</strong>. Wait for&nbsp;<strong>Registered</strong>.</li>
</ol>



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



<h2 class="wp-block-heading" id="step-2--create-the-artifact-signing-account">Step 2 — Create the Artifact Signing account</h2>



<p>Keep the signing resources together in the same subscription and a dedicated resource group.</p>



<ol class="wp-block-list">
<li>Portal search →&nbsp;<strong>Artifact Signing Accounts → Create</strong>.</li>



<li><strong>Subscription</strong>: the paid subscription you chose.&nbsp;<strong>Resource group</strong>: new, e.g.&nbsp;<code>rg-artifact-signing</code>.</li>



<li><strong>Account name</strong>: 3–24 alphanumeric, starts with a letter,&nbsp;<strong>globally unique</strong>&nbsp;(no consecutive hyphens). e.g.&nbsp;<code>xojoappsigning</code>.</li>



<li><strong>Region</strong>: pick one you&#8217;ll remember; it determines your signing endpoint.</li>



<li><strong>Pricing</strong>:&nbsp;<strong>Basic</strong>&nbsp;unless you&#8217;ll exceed 5,000 signs/month.</li>



<li>Create, then note the&nbsp;<strong>Account URI</strong>&nbsp;on the overview page. It follows the pattern&nbsp;<code>https://&lt;region-code&gt;.codesigning.azure.net/</code>.</li>
</ol>



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



<h2 class="wp-block-heading" id="step-3--assign-the-identity-verifier-role">Step 3 — Assign the Identity Verifier role</h2>



<p>You need this before the identity-validation button becomes clickable.</p>



<ol class="wp-block-list">
<li>From your Artifact Signing account, left menu →&nbsp;<strong>Access control (IAM)</strong>&nbsp;→&nbsp;<strong>Add role assignment</strong>.</li>



<li>Role:&nbsp;<strong>Artifact Signing Identity Verifier</strong>&nbsp;(use the search field) → assign to&nbsp;<strong>your own user account</strong>.</li>
</ol>



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



<h2 class="wp-block-heading" id="step-4--identity-validation-the-real-gate">Step 4 — Identity validation (the real gate)</h2>



<p>From your Artifact Signing account (the one you created in Step 2), go to the left menu →&nbsp;<strong>Objects → Identity validations</strong>&nbsp;→&nbsp;<strong>New Identity</strong>&nbsp;→&nbsp;<strong>Public</strong>.</p>



<p><strong>Public</strong>&nbsp;is what you want for normal app signing (it&#8217;s what SmartScreen cares about).</p>



<p>Fill in your legal business name, website, emails, business identifier (tax ID / DUNS), and address. Two gotchas that bite everyone:</p>



<ul class="wp-block-list">
<li>The&nbsp;<strong>secondary email must be on the same domain as the primary</strong>.</li>



<li><strong>Individual developers</strong>: the form pulls from your Azure&nbsp;<em>billing account</em>, and its name/address must exactly match your ID.</li>
</ul>



<p><strong>What happens next:</strong>&nbsp;status goes&nbsp;<code>In Progress</code>&nbsp;→&nbsp;<code>Action Required</code>&nbsp;(this is the point when you may have to wait a few hours to days&#8230; In my case, it took only an hour). You&#8217;ll be routed through a third-party verifier (<strong>AU10TIX</strong>). You upload a government ID and a selfie from your phone, then add the resulting&nbsp;<strong>Verified ID to Microsoft Authenticator</strong>&nbsp;and share it back (another hour or so).</p>



<p><strong>Timeline:</strong>&nbsp;officially 1–20 business days; in practice often hours to a few days. If it stalls, re-submit with a different identifier (tax ID instead of DUNS) and make sure your company name/address match your documents&nbsp;<em>exactly</em>.</p>



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



<h2 class="wp-block-heading" id="step-5--create-the-certificate-profile">Step 5 — Create the certificate profile</h2>



<ol class="wp-block-list">
<li>From your Artifact Signing account, left menu →&nbsp;<strong>Objects → Certificate profiles</strong>&nbsp;→&nbsp;<strong>Create</strong>.</li>



<li>Type:&nbsp;<strong>Public Trust</strong>.</li>



<li>Name it (5–100 chars), then pick your completed identity validation under&nbsp;<strong>Verified CN and O</strong>.</li>



<li>Create. You never see or hold the certificate. It&#8217;s rotated daily behind the scenes. The public cert is embedded in every file you sign.</li>
</ol>



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



<h2 class="wp-block-heading" id="step-6--assign-the-certificate-profile-signer-role">Step 6 — Assign the Certificate Profile Signer role</h2>



<p>This is the role that lets you actually sign. Because we&#8217;re using the Azure CLI, it goes on&nbsp;<strong>your user</strong>. No app registration is needed (this is a separate/alternative process, but we&#8217;re not talking about that in this article).</p>



<ol class="wp-block-list">
<li>From your Artifact Signing account, left menu →&nbsp;<strong>Access control (IAM)</strong>&nbsp;→&nbsp;<strong>Add role assignment</strong>.</li>



<li>Role:&nbsp;<strong>Artifact Signing Certificate Profile Signer</strong>&nbsp;→ assign to&nbsp;<strong>your own user account</strong>.</li>
</ol>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>Give role assignments a few minutes to propagate. If you try signing immediately and hit a 403, wait ~5 minutes and retry.</p>
</blockquote>



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



<h2 class="wp-block-heading" id="step-7--install-the-signing-tools">Step 7 — Install the signing tools</h2>



<p>First, the <strong>Azure CLI</strong>: <code>winget install Microsoft.AzureCLI</code></p>



<p><em>You’ll use it in Step 9 to authenticate with Azure.</em></p>



<p><strong>SignTool</strong>&nbsp;comes with the Windows SDK. Install it with: <code>winget install --id Microsoft.WindowsSDK --exact</code></p>



<p><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/26a0.png" alt="⚠" class="wp-smiley" style="height: 1em; max-height: 1em;" />&nbsp;Run this to find the newest x64&nbsp;signtool.exe:<br><code>Get-ChildItem "C:\Program Files (x86)\Windows Kits\10\bin" -Recurse -Filter signtool.exe | Where-Object { $_.FullName -match '\\x64\\signtool\.exe$' } | Sort-Object FullName -Descending | Select-Object -First 1 -ExpandProperty FullName</code></p>



<p><em>Note the path down.</em></p>



<p><strong>.NET 8 runtime</strong>&nbsp;(x64).</p>



<p><strong>Microsoft Visual C++ Redistributable</strong>.</p>



<p><strong>Artifact Signing Client Tools</strong>:<code>winget install -e --id Microsoft.Azure.ArtifactSigningClientTools</code><br>This installs&nbsp;<code>Azure.CodeSigning.Dlib.dll</code>&nbsp;(the plugin signtool uses to talk to Azure).</p>



<p><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/26a0.png" alt="⚠" class="wp-smiley" style="height: 1em; max-height: 1em;" />&nbsp;Locate the actual dll path after install:<br><code>Get-ChildItem -Path "C:\Program Files","$env:LOCALAPPDATA" -Recurse -Filter Azure.CodeSigning.Dlib.dll -ErrorAction SilentlyContinue | Select-Object -First 1 -ExpandProperty FullName</code></p>



<p><em>Note the path down.</em></p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>If&nbsp;<code>signtool</code>&nbsp;gives you &#8220;command not found&#8221;, that&#8217;s normal; it&#8217;s not on PATH. Use the full path, or add&nbsp;<code>...\10\&lt;version&gt;\x64</code>&nbsp;to your PATH.</p>
</blockquote>



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



<h2 class="wp-block-heading" id="step-8--create-the-metadata-file">Step 8 — Create the metadata file</h2>



<p>This is a small JSON with three values. Name it anything you like, e.g.&nbsp;<code>artifact-code-signing.json</code>:</p>



<pre class="wp-block-code"><code>{
	"Endpoint": "https://&lt;region-code&gt;.codesigning.azure.net",
	"CodeSigningAccountName": "xojoappsigning",
	"CertificateProfileName": "...."
}</code></pre>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>This JSON file will be used a lot, so save it somewhere safe.</p>
</blockquote>



<ul class="wp-block-list">
<li><strong>Endpoint</strong>&nbsp;= your account URI (region-specific; must match where the account + profile live, or you get a 403).</li>



<li><strong>CodeSigningAccountName</strong>&nbsp;= the Artifact Signing account name from Step 2.</li>



<li><strong>CertificateProfileName</strong>&nbsp;= the certificate profile name you created in Step 5.</li>
</ul>



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



<h2 class="wp-block-heading" id="step-9--authenticate-with-the-azure-cli">Step 9 — Authenticate with the Azure CLI</h2>



<pre class="wp-block-code"><code>az login</code></pre>



<p>This opens your browser; sign in with the Microsoft account tied to your Azure subscription. When signtool runs, the dlib picks up your logged-in Azure CLI session automatically.</p>



<p>If you have multiple Azure subscriptions, point the CLI at the right one, then confirm it took:</p>



<pre class="wp-block-code"><code>az account set --subscription "&lt;your subscription id&gt;"
az account show --query name -o tsv</code></pre>



<p>The second command should print your code-signing subscription&#8217;s name. If you also have multiple Microsoft tenants (a personal account&nbsp;<em>and</em>&nbsp;a work account, for example), log straight into the right one:</p>



<pre class="wp-block-code"><code>az login --tenant "&lt;tenant id&gt;"</code></pre>



<p>You may occasionally need to re-run&nbsp;<code>az login</code>&nbsp;after long idle periods.</p>



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



<h2 class="wp-block-heading" id="step-10--sign-your-xojo-app">Step 10 — Sign your Xojo app</h2>



<p>Just remember, you need to&nbsp;<strong>sign the compiled application after each new build</strong>.</p>



<h3 class="wp-block-heading" id="what-to-sign-and-skip">What to sign (and skip)</h3>



<p>Your Xojo Windows build folder looks roughly like this. Sign the binaries you build or distribute under your publisher identity; leave Xojo, Microsoft, and other vendor-signed dependencies alone.</p>



<pre class="wp-block-code"><code>Windows 64 bit/
└── YourApp/
    ├── YourApp.exe              ← sign
    ├── &lt;your own DLLs&gt;          ← sign
    ├── XojoGUIFramework64.dll   ← skip, Xojo provides signed DLLs
    ├── YourApp Libs/            ← skip, Xojo provides signed DLLs
    ├── msvcp140.dll, vcruntime*.dll …  ← skip (Microsoft runtime)
    └── YourApp.exe.WebView2/    ← skip (WebView2 cache)
</code></pre>



<h3 class="wp-block-heading" id="the-script">The script</h3>



<p>Save this as&nbsp;<code>sign.ps1</code>, next to the Xojo project, update the paths at the top, and run it from PowerShell:</p>



<pre class="wp-block-code"><code>$ErrorActionPreference = "Stop"

$Signtool    = "C:\...\signtool.exe"                            <em># path from Step 7</em>
$Dlib        = "C:\...\Azure.CodeSigning.Dlib.dll"              <em># path from Step 7</em>
$Metadata    = "C:\...\artifact-code-signing.json"              <em># from Step 8</em>
$BuildFolder = "F:\...\YourApp"                                 <em># folder containing YourApp.exe</em>

<em># Installer (Inno Setup) — optional. Set $EnableInno to $false to skip this part.</em>
$EnableInno  = $true
$InnoSetup   = "C:\Program Files (x86)\Inno Setup 6\ISCC.exe"
$IssScript   = "F:\...\YourAppSetup.iss"                        <em># your Inno Setup script</em>
$Installer   = "F:\...\YourAppSetup.exe"                        <em># output from the .iss</em>

<em># Sign binaries you build or distribute under your publisher identity.</em>
<em># Leave Xojo, Microsoft, and other vendor-signed dependencies alone.</em>
$FilesToSign = @(
    "$BuildFolder\YourApp.exe"
    "$BuildFolder\MyPlugin.dll"
    <em># add any other files you own here, one per line</em>
)

function Invoke-SigningCommand {
    param(&#91;string&#91;]]$Arguments)

    &amp; $Signtool @Arguments
    if ($LASTEXITCODE -ne 0) {
        throw "SignTool failed with exit code $LASTEXITCODE."
    }
}

foreach ($f in $FilesToSign) {
    Invoke-SigningCommand @(
        "sign", "/v", "/fd", "SHA256",
        "/tr", "http://timestamp.acs.microsoft.com", "/td", "SHA256",
        "/dlib", $Dlib, "/dmdf", $Metadata,
        $f
    )
}

if ($EnableInno) {
    <em># Build a fresh installer, then sign it.</em>
    &amp; $InnoSetup $IssScript
    if ($LASTEXITCODE -ne 0) {
        throw "Inno Setup failed with exit code $LASTEXITCODE."
    }

    Invoke-SigningCommand @(
        "sign", "/v", "/fd", "SHA256",
        "/tr", "http://timestamp.acs.microsoft.com", "/td", "SHA256",
        "/dlib", $Dlib, "/dmdf", $Metadata,
        $Installer
    )
}</code></pre>



<p>What the flags mean:</p>



<ul class="wp-block-list">
<li><code>/tr http://timestamp.acs.microsoft.com</code>: the timestamp server. The&nbsp;<code>http://</code>&nbsp;(not https) is intentional.</li>



<li><code>/fd SHA256</code>&nbsp;and&nbsp;<code>/td SHA256</code>: SHA-256 for the file and the timestamp.</li>



<li><code>/dlib</code>: the Azure plugin from Step 7.&nbsp;<code>/dmdf</code>: your metadata JSON from Step 8.</li>
</ul>



<h3 class="wp-block-heading" id="confirm-it-worked">Confirm it worked</h3>



<p>Two checks:</p>



<ol class="wp-block-list">
<li><strong>Signtool:</strong><code>$Signtool verify /v /pa "$BuildFolder\YourApp.exe" </code>You want to see&nbsp;<code>Successfully verified</code>.</li>



<li><strong>Or:</strong>&nbsp;right-click&nbsp;<code>YourApp.exe</code>&nbsp;→&nbsp;<strong>Properties → Digital Signatures</strong>&nbsp;→ your org name should be listed.</li>
</ol>



<h3 class="wp-block-heading" id="rules-of-thumb">Rules of thumb</h3>



<ul class="wp-block-list">
<li><strong>Sign after every build.</strong>&nbsp;Each new&nbsp;<code>.exe</code>&nbsp;is a fresh unsigned binary.</li>



<li><strong>Sign before you zip.</strong>&nbsp;Sign the files,&nbsp;<em>then</em>&nbsp;package them. Signing inside a zip does nothing.</li>
</ul>



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



<h2 class="wp-block-heading" id="troubleshooting">Troubleshooting</h2>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th class="has-text-align-left" data-align="left">Symptom</th><th class="has-text-align-left" data-align="left">Fix</th></tr></thead><tbody><tr><td><code>signtool: command not found</code></td><td>Use the full SDK path; it&#8217;s not on PATH</td></tr><tr><td><code>No certificates were found</code></td><td>dlib path wrong, or x86/x64 mismatch between signtool and dlib</td></tr><tr><td><code>403 Forbidden</code></td><td>Signer role on the wrong account, wrong account name in JSON, or endpoint/region mismatch</td></tr><tr><td><code>SignTool Error: An unexpected internal error</code></td><td>Update signtool to ≥ 10.0.22621.755; check .NET 8 + VC++ redist</td></tr><tr><td>Signing appeared to succeed, but no signature is visible</td><td>Run&nbsp;<code>signtool verify /v /pa &lt;file&gt;</code>; its exit code and&nbsp;<code>Successfully verified</code>&nbsp;output are authoritative. Explorer&#8217;s Digital Signatures tab is not available for every file type.</td></tr></tbody></table></figure>



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



<h2 class="wp-block-heading" id="recap">Recap</h2>



<p><strong>One time (Steps 1–9):</strong>&nbsp;register the&nbsp;<code>Microsoft.CodeSigning</code>&nbsp;provider → create the account → assign the Identity Verifier role → complete identity validation (slow&#8217;ish) → create the certificate profile → assign the Signer role → install tools → write the metadata JSON →&nbsp;<code>az login</code>.</p>



<p><strong>Every build (Step 10):</strong>&nbsp;run&nbsp;<code>sign.ps1</code>.</p>



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



<h2 class="wp-block-heading" id="the-bottom-line">The bottom line</h2>



<p>Azure Artifact Signing is a low-cost managed option for signing Windows apps, and Azure CLI authentication means local builds do not need a stored signing private key. The setup has some Azure bureaucracy, and identity validation is the slow part. After that, it is one script per build.</p>



<h4 class="wp-block-heading">Related discussion</h4>



<p>For an alternative approach that automates Xojo application signing and Inno Setup installer creation, see Jürg Otter’s Xojo Forum topic, <a href="https://forum.xojo.com/t/windows-code-signing-installer-creation-with-innosetup/84732" target="_blank" rel="noreferrer noopener">Windows Code Signing &amp; Installer Creation with Inno Setup</a>. The topic includes Jürg’s open-source code, which supports both Azure Artifact Signing and traditional <code>.pfx</code> certificates.</p>



<p><em>Gabriel is a digital marketing enthusiast who loves coding with Xojo to create cool software tools for any platform. He is always eager to learn and share new ideas!</em></p>



<ul class="wp-block-social-links has-normal-icon-size is-content-justification-center is-layout-flex wp-container-core-social-links-is-layout-16018d1d wp-block-social-links-is-layout-flex"><li class="wp-social-link wp-social-link-facebook  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.facebook.com/goxojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M12 2C6.5 2 2 6.5 2 12c0 5 3.7 9.1 8.4 9.9v-7H7.9V12h2.5V9.8c0-2.5 1.5-3.9 3.8-3.9 1.1 0 2.2.2 2.2.2v2.5h-1.3c-1.2 0-1.6.8-1.6 1.6V12h2.8l-.4 2.9h-2.3v7C18.3 21.1 22 17 22 12c0-5.5-4.5-10-10-10z"></path></svg><span class="wp-block-social-link-label screen-reader-text">Facebook</span></a></li>

<li class="wp-social-link wp-social-link-x  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://x.com/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M13.982 10.622 20.54 3h-1.554l-5.693 6.618L8.745 3H3.5l6.876 10.007L3.5 21h1.554l6.012-6.989L15.868 21h5.245l-7.131-10.378Zm-2.128 2.474-.697-.997-5.543-7.93H8l4.474 6.4.697.996 5.815 8.318h-2.387l-4.745-6.787Z" /></svg><span class="wp-block-social-link-label screen-reader-text">X</span></a></li>

<li class="wp-social-link wp-social-link-linkedin  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.linkedin.com/company/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M19.7,3H4.3C3.582,3,3,3.582,3,4.3v15.4C3,20.418,3.582,21,4.3,21h15.4c0.718,0,1.3-0.582,1.3-1.3V4.3 C21,3.582,20.418,3,19.7,3z M8.339,18.338H5.667v-8.59h2.672V18.338z M7.004,8.574c-0.857,0-1.549-0.694-1.549-1.548 c0-0.855,0.691-1.548,1.549-1.548c0.854,0,1.547,0.694,1.547,1.548C8.551,7.881,7.858,8.574,7.004,8.574z M18.339,18.338h-2.669 v-4.177c0-0.996-0.017-2.278-1.387-2.278c-1.389,0-1.601,1.086-1.601,2.206v4.249h-2.667v-8.59h2.559v1.174h0.037 c0.356-0.675,1.227-1.387,2.526-1.387c2.703,0,3.203,1.779,3.203,4.092V18.338z"></path></svg><span class="wp-block-social-link-label screen-reader-text">LinkedIn</span></a></li>

<li class="wp-social-link wp-social-link-github  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://github.com/topics/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M12,2C6.477,2,2,6.477,2,12c0,4.419,2.865,8.166,6.839,9.489c0.5,0.09,0.682-0.218,0.682-0.484 c0-0.236-0.009-0.866-0.014-1.699c-2.782,0.602-3.369-1.34-3.369-1.34c-0.455-1.157-1.11-1.465-1.11-1.465 c-0.909-0.62,0.069-0.608,0.069-0.608c1.004,0.071,1.532,1.03,1.532,1.03c0.891,1.529,2.341,1.089,2.91,0.833 c0.091-0.647,0.349-1.086,0.635-1.337c-2.22-0.251-4.555-1.111-4.555-4.943c0-1.091,0.39-1.984,1.03-2.682 C6.546,8.54,6.202,7.524,6.746,6.148c0,0,0.84-0.269,2.75,1.025C10.295,6.95,11.15,6.84,12,6.836 c0.85,0.004,1.705,0.114,2.504,0.336c1.909-1.294,2.748-1.025,2.748-1.025c0.546,1.376,0.202,2.394,0.1,2.646 c0.64,0.699,1.026,1.591,1.026,2.682c0,3.841-2.337,4.687-4.565,4.935c0.359,0.307,0.679,0.917,0.679,1.852 c0,1.335-0.012,2.415-0.012,2.741c0,0.269,0.18,0.579,0.688,0.481C19.138,20.161,22,16.416,22,12C22,6.477,17.523,2,12,2z"></path></svg><span class="wp-block-social-link-label screen-reader-text">GitHub</span></a></li>

<li class="wp-social-link wp-social-link-youtube  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.youtube.com/c/XojoInc" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M21.8,8.001c0,0-0.195-1.378-0.795-1.985c-0.76-0.797-1.613-0.801-2.004-0.847c-2.799-0.202-6.997-0.202-6.997-0.202 h-0.009c0,0-4.198,0-6.997,0.202C4.608,5.216,3.756,5.22,2.995,6.016C2.395,6.623,2.2,8.001,2.2,8.001S2,9.62,2,11.238v1.517 c0,1.618,0.2,3.237,0.2,3.237s0.195,1.378,0.795,1.985c0.761,0.797,1.76,0.771,2.205,0.855c1.6,0.153,6.8,0.201,6.8,0.201 s4.203-0.006,7.001-0.209c0.391-0.047,1.243-0.051,2.004-0.847c0.6-0.607,0.795-1.985,0.795-1.985s0.2-1.618,0.2-3.237v-1.517 C22,9.62,21.8,8.001,21.8,8.001z M9.935,14.594l-0.001-5.62l5.404,2.82L9.935,14.594z"></path></svg><span class="wp-block-social-link-label screen-reader-text">YouTube</span></a></li></ul>



<p class="has-text-align-center has-text-color has-link-color wp-elements-a0a2ac26ad214a49dac577734d259176" style="color:#84bd00"><a href="https://xojo.com/download/" target="_blank" rel="noreferrer noopener">Download Xojo</a></p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Quick Tip: Place limits on MobileImagePicker</title>
		<link>https://blog.xojo.com/2026/08/20/quick-tip-place-limits-on-mobileimagepicker/</link>
		
		<dc:creator><![CDATA[Javier Menendez]]></dc:creator>
		<pubDate>Thu, 20 Aug 2026 10:00:00 +0000</pubDate>
				<category><![CDATA[Android]]></category>
		<category><![CDATA[iOS]]></category>
		<category><![CDATA[Learning]]></category>
		<category><![CDATA[Mobile]]></category>
		<category><![CDATA[Tips]]></category>
		<category><![CDATA[MobileImagePicker]]></category>
		<guid isPermaLink="false">https://blog.xojo.com/?p=16441</guid>

					<description><![CDATA[The MobileImagePicker class has been around for while. It lets users take photos using a device&#8217;s available cameras and choose images from the device gallery.&#8230;]]></description>
										<content:encoded><![CDATA[<p>The MobileImagePicker class has been around for while. It lets users take photos using a device&#8217;s available cameras and choose images from the device gallery.<span id="more-16441"></span></p>


<p>The class has been improved through several Xojo releases, offering more options and modernizing its look and feel to match recent iOS releases. In this post, let&#8217;s talk about using one of those small but useful improvements to MobileImagePicker with Xojo 2026r2, the <code>SelectionLimit</code> property.</p>



<p>On previous releases, when using the <a href="https://documentation.xojo.com/api/user_interface/mobile/mobileimagepicker.html#mobileimagepicker"><code>MobileImagePicker</code></a> to select pictures from the device gallery (using <code>MobileImagePicker.Sources.Photos</code>), the user was allowed to choose as many pictures as they wanted to…&nbsp;but maybe that was not what your app logic expected!</p>



<p>Now you can use <code>MobileImagePicker.SelectionLimit</code> to set that expectation, so the user must comply with the limits your app needs.</p>



<p>If the logic of any of your existing apps allows the user to select as many pictures as they want, then there is nothing you need to do, the existing code will continue to work as expected. That is because the default value of the <code>MobileImagePicker.SelectionLimit</code> is 0. Or if you want to be more explicit, you can set the property to <code>MobileImagePicker.UnlimitedSelection</code>.</p>



<p>When setting the <code>MobileImagePicker.SelectionLimit</code> property to any other value, the iOS modal dialog will display that limit to the user so they know exactly what is expected.</p>



<p>Do you want to see it in action? Open the iOS &gt; ImagePicker example project from the IDE. Once opened, select the <code>Pressed</code> event handler from the Button1 item in the project navigator to access the associated Code Editor. Then, modify the existing code like this:</p>



<pre class="wp-block-code"><code>ImagePicker.Source = MobileImagePicker.Sources.Photos
ImagePicker.SelectionLimit = 2
ImagePicker.Show()</code></pre>



<p>We set the maximum limit of selected images to two. Run the app in the simulator, click on the Pick Pictures button, and the following modal will be shown, allowing you to choose a maximum of two images:</p>



<p><img loading="lazy" decoding="async" class="alignnone size-full wp-image-16442" src="https://blog.xojo.com/wp-content/uploads/2026/08/Simulator-Screenshot-iPhone-14-Pro-2026-08-17-at-11.08.51.png" alt="" width="1179" height="1323" srcset="https://blog.xojo.com/wp-content/uploads/2026/08/Simulator-Screenshot-iPhone-14-Pro-2026-08-17-at-11.08.51.png 1179w, https://blog.xojo.com/wp-content/uploads/2026/08/Simulator-Screenshot-iPhone-14-Pro-2026-08-17-at-11.08.51-267x300.png 267w, https://blog.xojo.com/wp-content/uploads/2026/08/Simulator-Screenshot-iPhone-14-Pro-2026-08-17-at-11.08.51-913x1024.png 913w, https://blog.xojo.com/wp-content/uploads/2026/08/Simulator-Screenshot-iPhone-14-Pro-2026-08-17-at-11.08.51-768x862.png 768w" sizes="auto, (max-width: 1179px) 100vw, 1179px" /></p>


<h2>In summary</h2>
<p>Alongside the big features highlighted in each Xojo release, there are a lot of other improvements and helpful additions. Take a look at the full list of updates in the <a href="https://documentation.xojo.com/resources/release_notes/2026r2.html">Release Notes</a>.</p>


<p><em>Javier Menendez is an engineer at Xojo and has been using Xojo since 1998. He lives in Castellón</em>, <em>Spain and hosts regular Xojo hangouts en español. Ask Javier questions on Twitter at <a href="https://twitter.com/xojoes" target="_blank" rel="noreferrer noopener">@XojoES</a> or on the <a href="https://forum.xojo.com/u/javier_menendez/summary" target="_blank" rel="noreferrer noopener">Xojo Forum</a>.</em></p>



<ul class="wp-block-social-links has-normal-icon-size is-content-justification-center is-layout-flex wp-container-core-social-links-is-layout-16018d1d wp-block-social-links-is-layout-flex"><li class="wp-social-link wp-social-link-facebook  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.facebook.com/goxojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M12 2C6.5 2 2 6.5 2 12c0 5 3.7 9.1 8.4 9.9v-7H7.9V12h2.5V9.8c0-2.5 1.5-3.9 3.8-3.9 1.1 0 2.2.2 2.2.2v2.5h-1.3c-1.2 0-1.6.8-1.6 1.6V12h2.8l-.4 2.9h-2.3v7C18.3 21.1 22 17 22 12c0-5.5-4.5-10-10-10z"></path></svg><span class="wp-block-social-link-label screen-reader-text">Facebook</span></a></li>

<li class="wp-social-link wp-social-link-x  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://x.com/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M13.982 10.622 20.54 3h-1.554l-5.693 6.618L8.745 3H3.5l6.876 10.007L3.5 21h1.554l6.012-6.989L15.868 21h5.245l-7.131-10.378Zm-2.128 2.474-.697-.997-5.543-7.93H8l4.474 6.4.697.996 5.815 8.318h-2.387l-4.745-6.787Z" /></svg><span class="wp-block-social-link-label screen-reader-text">X</span></a></li>

<li class="wp-social-link wp-social-link-linkedin  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.linkedin.com/company/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M19.7,3H4.3C3.582,3,3,3.582,3,4.3v15.4C3,20.418,3.582,21,4.3,21h15.4c0.718,0,1.3-0.582,1.3-1.3V4.3 C21,3.582,20.418,3,19.7,3z M8.339,18.338H5.667v-8.59h2.672V18.338z M7.004,8.574c-0.857,0-1.549-0.694-1.549-1.548 c0-0.855,0.691-1.548,1.549-1.548c0.854,0,1.547,0.694,1.547,1.548C8.551,7.881,7.858,8.574,7.004,8.574z M18.339,18.338h-2.669 v-4.177c0-0.996-0.017-2.278-1.387-2.278c-1.389,0-1.601,1.086-1.601,2.206v4.249h-2.667v-8.59h2.559v1.174h0.037 c0.356-0.675,1.227-1.387,2.526-1.387c2.703,0,3.203,1.779,3.203,4.092V18.338z"></path></svg><span class="wp-block-social-link-label screen-reader-text">LinkedIn</span></a></li>

<li class="wp-social-link wp-social-link-github  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://github.com/topics/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M12,2C6.477,2,2,6.477,2,12c0,4.419,2.865,8.166,6.839,9.489c0.5,0.09,0.682-0.218,0.682-0.484 c0-0.236-0.009-0.866-0.014-1.699c-2.782,0.602-3.369-1.34-3.369-1.34c-0.455-1.157-1.11-1.465-1.11-1.465 c-0.909-0.62,0.069-0.608,0.069-0.608c1.004,0.071,1.532,1.03,1.532,1.03c0.891,1.529,2.341,1.089,2.91,0.833 c0.091-0.647,0.349-1.086,0.635-1.337c-2.22-0.251-4.555-1.111-4.555-4.943c0-1.091,0.39-1.984,1.03-2.682 C6.546,8.54,6.202,7.524,6.746,6.148c0,0,0.84-0.269,2.75,1.025C10.295,6.95,11.15,6.84,12,6.836 c0.85,0.004,1.705,0.114,2.504,0.336c1.909-1.294,2.748-1.025,2.748-1.025c0.546,1.376,0.202,2.394,0.1,2.646 c0.64,0.699,1.026,1.591,1.026,2.682c0,3.841-2.337,4.687-4.565,4.935c0.359,0.307,0.679,0.917,0.679,1.852 c0,1.335-0.012,2.415-0.012,2.741c0,0.269,0.18,0.579,0.688,0.481C19.138,20.161,22,16.416,22,12C22,6.477,17.523,2,12,2z"></path></svg><span class="wp-block-social-link-label screen-reader-text">GitHub</span></a></li>

<li class="wp-social-link wp-social-link-youtube  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.youtube.com/c/XojoInc" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M21.8,8.001c0,0-0.195-1.378-0.795-1.985c-0.76-0.797-1.613-0.801-2.004-0.847c-2.799-0.202-6.997-0.202-6.997-0.202 h-0.009c0,0-4.198,0-6.997,0.202C4.608,5.216,3.756,5.22,2.995,6.016C2.395,6.623,2.2,8.001,2.2,8.001S2,9.62,2,11.238v1.517 c0,1.618,0.2,3.237,0.2,3.237s0.195,1.378,0.795,1.985c0.761,0.797,1.76,0.771,2.205,0.855c1.6,0.153,6.8,0.201,6.8,0.201 s4.203-0.006,7.001-0.209c0.391-0.047,1.243-0.051,2.004-0.847c0.6-0.607,0.795-1.985,0.795-1.985s0.2-1.618,0.2-3.237v-1.517 C22,9.62,21.8,8.001,21.8,8.001z M9.935,14.594l-0.001-5.62l5.404,2.82L9.935,14.594z"></path></svg><span class="wp-block-social-link-label screen-reader-text">YouTube</span></a></li></ul>



<p class="has-text-align-center has-text-color has-link-color wp-elements-a0a2ac26ad214a49dac577734d259176" style="color:#84bd00"><a href="https://xojo.com/download/" target="_blank" rel="noreferrer noopener">Download Xojo</a></p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Change the Font Across Your Entire Application</title>
		<link>https://blog.xojo.com/2026/07/20/change-the-font-across-your-entire-application/</link>
		
		<dc:creator><![CDATA[Gabriel Ludosanu]]></dc:creator>
		<pubDate>Mon, 20 Jul 2026 12:26:28 +0000</pubDate>
				<category><![CDATA[Desktop]]></category>
		<category><![CDATA[Fun]]></category>
		<category><![CDATA[Tips]]></category>
		<category><![CDATA[Cross-Platform Development]]></category>
		<category><![CDATA[DesktopContainer]]></category>
		<category><![CDATA[DesktopWindow]]></category>
		<category><![CDATA[FontName]]></category>
		<guid isPermaLink="false">https://blog.xojo.com/?p=16426</guid>

					<description><![CDATA[While working on one of my Xojo projects, I needed a quick way to change the font used by the controls across the entire application.&#8230;]]></description>
										<content:encoded><![CDATA[
<p>While working on one of my Xojo projects, I needed a quick way to change the font used by the controls across the entire application.</p>



<p>Opening every window and updating each control individually works, but it gets tedious quickly, especially when testing different fonts or adding new UI elements. So I created a small module that applies a font to all supported controls in a <code>DesktopWindow</code>, including controls placed inside <code>DesktopContainer</code> instances.</p>



<pre class="wp-block-code"><code>Module AppWideFont
  Public Sub SetFont(Extends window As DesktopWindow, fontName As String)
    ApplyFontTo(window.Controls, fontName)
  End Sub

  Protected Function GetMonospaceFont() As String
    #If TargetWindows
      Return "Cascadia Mono"
    #ElseIf TargetMacOS
      Return "Menlo"
    #ElseIf TargetLinux
      Return "DejaVu Sans Mono"
    #Else
      Return "Courier New"
    #EndIf
  End Function

  Private Sub ApplyFontTo(controls As Iterable, fontName As String)
    For Each c As Object In controls
      If c IsA DesktopContainer Then
        ApplyFontTo(DesktopContainer(c).Controls, fontName)
      End If
      
      Select Case c
      Case IsA DesktopLabel
        DesktopLabel(c).FontName = fontName
      Case IsA DesktopTextField
        DesktopTextField(c).FontName = fontName
      Case IsA DesktopTextArea
        DesktopTextArea(c).FontName = fontName
      Case IsA DesktopListBox
        DesktopListBox(c).FontName = fontName
      Case IsA DesktopButton
        DesktopButton(c).FontName = fontName
      Case IsA DesktopCheckBox
        DesktopCheckBox(c).FontName = fontName
      Case IsA DesktopRadioButton
        DesktopRadioButton(c).FontName = fontName
      Case IsA DesktopPopupMenu
        DesktopPopupMenu(c).FontName = fontName
      End Select
    Next
  End Sub

End Module</code></pre>



<p>The&nbsp;<code>SetFont</code>&nbsp;method is an extension method, so I can call it directly on any&nbsp;<code>DesktopWindow</code>.</p>



<p>For example, in a window’s&nbsp;<code>Opening</code>&nbsp;event:</p>



<pre class="wp-block-code"><code><strong>Self</strong>.<strong>SetFont</strong>("Arial")</code></pre>



<p>Or, if I want to use a monospace font:</p>



<pre class="wp-block-code"><code><strong>Self</strong>.<strong>SetFont</strong>(AppWideFont.GetMonospaceFont)</code></pre>



<p>The&nbsp;<code>GetMonospaceFont</code>&nbsp;function is just a simple additional helper that returns a suitable monospace font for Windows, macOS, or Linux.</p>



<p>The module uses the window’s&nbsp;<code>Controls</code>&nbsp;collection and recursively checks any&nbsp;<code>DesktopContainer</code>&nbsp;controls, so I only need one line of code per window. It currently handles labels, text fields, text areas, list boxes, buttons, checkboxes, radio buttons, and popup menus.</p>



<p>If I add another control type later, I can extend the&nbsp;<code>Select Case</code>&nbsp;statement with another branch.</p>



<p>This saved me from repeatedly changing font settings throughout the project and gave me one central place to control the application’s typography.</p>



<p><em>Gabriel is a digital marketing enthusiast who loves coding with Xojo to create cool software tools for any platform. He is always eager to learn and share new ideas!</em></p>



<ul class="wp-block-social-links has-normal-icon-size is-content-justification-center is-layout-flex wp-container-core-social-links-is-layout-16018d1d wp-block-social-links-is-layout-flex"><li class="wp-social-link wp-social-link-facebook  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.facebook.com/goxojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M12 2C6.5 2 2 6.5 2 12c0 5 3.7 9.1 8.4 9.9v-7H7.9V12h2.5V9.8c0-2.5 1.5-3.9 3.8-3.9 1.1 0 2.2.2 2.2.2v2.5h-1.3c-1.2 0-1.6.8-1.6 1.6V12h2.8l-.4 2.9h-2.3v7C18.3 21.1 22 17 22 12c0-5.5-4.5-10-10-10z"></path></svg><span class="wp-block-social-link-label screen-reader-text">Facebook</span></a></li>

<li class="wp-social-link wp-social-link-x  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://x.com/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M13.982 10.622 20.54 3h-1.554l-5.693 6.618L8.745 3H3.5l6.876 10.007L3.5 21h1.554l6.012-6.989L15.868 21h5.245l-7.131-10.378Zm-2.128 2.474-.697-.997-5.543-7.93H8l4.474 6.4.697.996 5.815 8.318h-2.387l-4.745-6.787Z" /></svg><span class="wp-block-social-link-label screen-reader-text">X</span></a></li>

<li class="wp-social-link wp-social-link-linkedin  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.linkedin.com/company/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M19.7,3H4.3C3.582,3,3,3.582,3,4.3v15.4C3,20.418,3.582,21,4.3,21h15.4c0.718,0,1.3-0.582,1.3-1.3V4.3 C21,3.582,20.418,3,19.7,3z M8.339,18.338H5.667v-8.59h2.672V18.338z M7.004,8.574c-0.857,0-1.549-0.694-1.549-1.548 c0-0.855,0.691-1.548,1.549-1.548c0.854,0,1.547,0.694,1.547,1.548C8.551,7.881,7.858,8.574,7.004,8.574z M18.339,18.338h-2.669 v-4.177c0-0.996-0.017-2.278-1.387-2.278c-1.389,0-1.601,1.086-1.601,2.206v4.249h-2.667v-8.59h2.559v1.174h0.037 c0.356-0.675,1.227-1.387,2.526-1.387c2.703,0,3.203,1.779,3.203,4.092V18.338z"></path></svg><span class="wp-block-social-link-label screen-reader-text">LinkedIn</span></a></li>

<li class="wp-social-link wp-social-link-github  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://github.com/topics/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M12,2C6.477,2,2,6.477,2,12c0,4.419,2.865,8.166,6.839,9.489c0.5,0.09,0.682-0.218,0.682-0.484 c0-0.236-0.009-0.866-0.014-1.699c-2.782,0.602-3.369-1.34-3.369-1.34c-0.455-1.157-1.11-1.465-1.11-1.465 c-0.909-0.62,0.069-0.608,0.069-0.608c1.004,0.071,1.532,1.03,1.532,1.03c0.891,1.529,2.341,1.089,2.91,0.833 c0.091-0.647,0.349-1.086,0.635-1.337c-2.22-0.251-4.555-1.111-4.555-4.943c0-1.091,0.39-1.984,1.03-2.682 C6.546,8.54,6.202,7.524,6.746,6.148c0,0,0.84-0.269,2.75,1.025C10.295,6.95,11.15,6.84,12,6.836 c0.85,0.004,1.705,0.114,2.504,0.336c1.909-1.294,2.748-1.025,2.748-1.025c0.546,1.376,0.202,2.394,0.1,2.646 c0.64,0.699,1.026,1.591,1.026,2.682c0,3.841-2.337,4.687-4.565,4.935c0.359,0.307,0.679,0.917,0.679,1.852 c0,1.335-0.012,2.415-0.012,2.741c0,0.269,0.18,0.579,0.688,0.481C19.138,20.161,22,16.416,22,12C22,6.477,17.523,2,12,2z"></path></svg><span class="wp-block-social-link-label screen-reader-text">GitHub</span></a></li>

<li class="wp-social-link wp-social-link-youtube  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.youtube.com/c/XojoInc" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M21.8,8.001c0,0-0.195-1.378-0.795-1.985c-0.76-0.797-1.613-0.801-2.004-0.847c-2.799-0.202-6.997-0.202-6.997-0.202 h-0.009c0,0-4.198,0-6.997,0.202C4.608,5.216,3.756,5.22,2.995,6.016C2.395,6.623,2.2,8.001,2.2,8.001S2,9.62,2,11.238v1.517 c0,1.618,0.2,3.237,0.2,3.237s0.195,1.378,0.795,1.985c0.761,0.797,1.76,0.771,2.205,0.855c1.6,0.153,6.8,0.201,6.8,0.201 s4.203-0.006,7.001-0.209c0.391-0.047,1.243-0.051,2.004-0.847c0.6-0.607,0.795-1.985,0.795-1.985s0.2-1.618,0.2-3.237v-1.517 C22,9.62,21.8,8.001,21.8,8.001z M9.935,14.594l-0.001-5.62l5.404,2.82L9.935,14.594z"></path></svg><span class="wp-block-social-link-label screen-reader-text">YouTube</span></a></li></ul>



<p class="has-text-align-center has-text-color has-link-color wp-elements-a0a2ac26ad214a49dac577734d259176" style="color:#84bd00"><a href="https://xojo.com/download/" target="_blank" rel="noreferrer noopener">Download Xojo</a></p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Xojo Web in 2026r2: Faster, Smarter, SEO-Ready</title>
		<link>https://blog.xojo.com/2026/07/08/xojo-web-in-2026r2-faster-smarter-seo-ready/</link>
		
		<dc:creator><![CDATA[Ricardo Cruz]]></dc:creator>
		<pubDate>Wed, 08 Jul 2026 15:40:00 +0000</pubDate>
				<category><![CDATA[Web]]></category>
		<category><![CDATA[2026r2]]></category>
		<category><![CDATA[Web 2.0]]></category>
		<category><![CDATA[Web Development]]></category>
		<category><![CDATA[webdev]]></category>
		<category><![CDATA[Xojo Programming Language]]></category>
		<guid isPermaLink="false">https://blog.xojo.com/?p=16392</guid>

					<description><![CDATA[Performance has taken a great leap forward, SEO support lands properly this time around, and there are a handful of quality-of-life improvements that will make&#8230;]]></description>
										<content:encoded><![CDATA[
<p>Performance has taken a great leap forward, SEO support lands properly this time around, and there are a handful of quality-of-life improvements that will make your daily coding a bit smoother. Let&#8217;s dig in.</p>



<h2 class="wp-block-heading">Performance: Beyond 13,000 Requests Per Second</h2>



<p>If you have been following the web framework&#8217;s performance numbers over the releases, you know they have been steadily improving. In 2024r2, benchmarks were sitting at around 8-9k requests per second. In 2026r2, we are beyond 13k. That is a significant jump, and it comes from a fundamental change in how the framework handles connections under the hood.</p>



<p>Xojo Web is essentially a Console project built on top of&nbsp;<code>ServerSocket</code>&nbsp;and&nbsp;<code>TCPSocket</code>. Previously, each incoming connection would spawn a new&nbsp;<code>Thread</code>, process the request, and then that thread would be destroyed. In 2026r2, threads are created when the&nbsp;<code>TCPSocket</code>&nbsp;is created, before the connection even arrives. When a request comes in, the thread is already there, sleeping, waiting. No need to spin one up from scratch. And when a&nbsp;<code>TCPSocket</code>&nbsp;can be reused, so can its thread, meaning fewer kernel calls and less overhead overall.</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="586" src="https://blog.xojo.com/wp-content/uploads/2026/06/Captura-de-pantalla-2026-06-24-a-las-12.18.06-1024x586.png" alt="" class="wp-image-16394" srcset="https://blog.xojo.com/wp-content/uploads/2026/06/Captura-de-pantalla-2026-06-24-a-las-12.18.06-1024x586.png 1024w, https://blog.xojo.com/wp-content/uploads/2026/06/Captura-de-pantalla-2026-06-24-a-las-12.18.06-300x172.png 300w, https://blog.xojo.com/wp-content/uploads/2026/06/Captura-de-pantalla-2026-06-24-a-las-12.18.06-768x440.png 768w, https://blog.xojo.com/wp-content/uploads/2026/06/Captura-de-pantalla-2026-06-24-a-las-12.18.06-1536x880.png 1536w, https://blog.xojo.com/wp-content/uploads/2026/06/Captura-de-pantalla-2026-06-24-a-las-12.18.06-2048x1173.png 2048w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p>That said, even with a 50% increase in this benchmark, most developers won&#8217;t notice a big difference. When the application has to deal with frequent database queries, for example, shaving a few milliseconds off request handling is a drop in the bucket. But where it does matter, it matters a lot. If your application is a plain REST API serving data for a mobile app with thousands of concurrent users, or when it is deployed to a constrained environment like a Raspberry Pi, this kind of improvement can make a real difference.</p>



<h2 class="wp-block-heading">SEO Improvements Done Right</h2>



<p>In 2026r1 we introduced the ability to call&nbsp;<code>WebPage.Show</code>&nbsp;from within the&nbsp;<code>HandleURL</code>&nbsp;event, which opened the door for serving pages to search engine crawlers. It worked, but it came with a significant cost: even for users who were not using this feature at all, benchmark numbers dropped from 7-8k requests per second down to 1-2k. That was not acceptable (pushing us to review the overall web framework performance on this release), and it also introduced edge cases for codebases that expected&nbsp;<code>HandleURL</code>&nbsp;to run without any session context active, because creating a session context on top of an existing one is not allowed.</p>



<p>In 2026r2, this is fixed properly. The performance penalty is gone for everyone. If you want to use&nbsp;<code>WebPage.Show</code>&nbsp;from&nbsp;<code>HandleURL</code>&nbsp;for SEO purposes, you now opt in explicitly by creating a&nbsp;<code>WebSessionContext</code>&nbsp;instance yourself, passing the <code>request</code>parameter, before calling&nbsp;<code>Show</code>. It is a small step, but it makes the intent clear and keeps things safe for everyone else.</p>



<p><code>WebSessionContext</code> has a new <code>Constructor</code>, accepting a <code>request As WebRequest</code> parameter.</p>



<p>We are not stopping here. SEO is important, and we are already working on a proper URL router to make these workflows easier and more capable. Stay tuned!</p>



<h2 class="wp-block-heading">DatabaseConnection Gets a PerSession Mode</h2>



<p>If you use a&nbsp;<a href="https://documentation.xojo.com/topics/databases/connecting_to_a_database.html" target="_blank" rel="noreferrer noopener">Database Connection</a>&nbsp;in your web project, you are probably familiar with how they work: you add one to your project in the Navigator, give it a name, say&nbsp;<code>MyDatabaseConnection</code>, and then you reference it by that name anywhere in your code to run queries.</p>



<p>By default, that connection behaves like a singleton. Every session in your web app shares the same&nbsp;<code>MyDatabaseConnection</code>instance. For most read-only usage that is fine, but the moment you start using transactions, you can run into trouble. One session&#8217;s transaction can interfere with another&#8217;s, or worse, data from one session can leak into another&#8217;s results.</p>



<p>The new&nbsp;<code>PerSession</code>&nbsp;property in 2026r2 solves this at design time. When you enable it in the Inspector,&nbsp;<code>MyDatabaseConnection</code>stops being a shared instance. Instead, each session gets its own connection, created lazily the first time that session needs it, and automatically destroyed when the session ends. Your code does not change, you still write&nbsp;<code>MyDatabaseConnection.SelectSQL(...)</code>&nbsp;as you always have, but now you can be confident each session is operating in complete isolation.</p>



<h2 class="wp-block-heading">WebGraphics Gets DrawPath and FillPath</h2>



<p><code>WebGraphics</code>&nbsp;now supports&nbsp;<code>DrawPath</code>&nbsp;and&nbsp;<code>FillPath</code>, bringing it in line with what Desktop and Mobile targets have had for a while. If you have been writing custom drawing code for other targets using&nbsp;<code>Graphics.DrawPath</code>&nbsp;or&nbsp;<code>Graphics.FillPath</code>, that code can now be reused in your web projects without modification.</p>



<p>This is exactly the kind of cross-target parity that makes Xojo powerful. Check the&nbsp;<a href="https://documentation.xojo.com/api/graphics/webgraphics.html" target="_blank" rel="noreferrer noopener">WebGraphics documentation</a>&nbsp;for the full details on how paths work.</p>



<h2 class="wp-block-heading">WebImageViewer: Goodbye, Flicker</h2>



<p>A small but welcome fix. When updating the&nbsp;<code>Picture</code>&nbsp;property on a&nbsp;<code>WebImageViewer</code>, previous versions would show a brief but noticeable blink, the image would disappear for a few milliseconds before the new one appeared. In 2026r2, the new image is shown directly. No blink, no flicker. It just works.</p>



<h2 class="wp-block-heading">Wrapping Up</h2>



<p>As usual, 2026r2 also includes a solid round of bug fixes across the web framework. Check the&nbsp;<a href="https://documentation.xojo.com/resources/release_notes/2026r2.html" target="_blank" rel="noreferrer noopener">full release notes</a>&nbsp;for the complete list. This is a release that delivers on multiple fronts: raw performance, correctness, cross-target parity, and laying better groundwork for SEO. The thread handling changes alone make this a compelling update for anyone running Xojo web apps under load. And with a proper URL router on the horizon, the SEO story is only going to get better.</p>



<p>Happy coding!</p>



<p><em>Ricardo has always been curious about how things work. Growing up surrounded by computers</em> he became interested in <em>web technologies in the dial-up connections era. Xojo has been his secret weapon and language of preference since 2018. When he’s not online, chances are he will be scuba diving … or crocheting amigurumis. Find Ricardo on Twitter <a href="https://x.com/piradoiv" target="_blank" rel="noreferrer noopener">@piradoiv</a>.</em></p>



<ul class="wp-block-social-links has-normal-icon-size is-content-justification-center is-layout-flex wp-container-core-social-links-is-layout-16018d1d wp-block-social-links-is-layout-flex"><li class="wp-social-link wp-social-link-facebook  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.facebook.com/goxojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M12 2C6.5 2 2 6.5 2 12c0 5 3.7 9.1 8.4 9.9v-7H7.9V12h2.5V9.8c0-2.5 1.5-3.9 3.8-3.9 1.1 0 2.2.2 2.2.2v2.5h-1.3c-1.2 0-1.6.8-1.6 1.6V12h2.8l-.4 2.9h-2.3v7C18.3 21.1 22 17 22 12c0-5.5-4.5-10-10-10z"></path></svg><span class="wp-block-social-link-label screen-reader-text">Facebook</span></a></li>

<li class="wp-social-link wp-social-link-x  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://x.com/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M13.982 10.622 20.54 3h-1.554l-5.693 6.618L8.745 3H3.5l6.876 10.007L3.5 21h1.554l6.012-6.989L15.868 21h5.245l-7.131-10.378Zm-2.128 2.474-.697-.997-5.543-7.93H8l4.474 6.4.697.996 5.815 8.318h-2.387l-4.745-6.787Z" /></svg><span class="wp-block-social-link-label screen-reader-text">X</span></a></li>

<li class="wp-social-link wp-social-link-linkedin  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.linkedin.com/company/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M19.7,3H4.3C3.582,3,3,3.582,3,4.3v15.4C3,20.418,3.582,21,4.3,21h15.4c0.718,0,1.3-0.582,1.3-1.3V4.3 C21,3.582,20.418,3,19.7,3z M8.339,18.338H5.667v-8.59h2.672V18.338z M7.004,8.574c-0.857,0-1.549-0.694-1.549-1.548 c0-0.855,0.691-1.548,1.549-1.548c0.854,0,1.547,0.694,1.547,1.548C8.551,7.881,7.858,8.574,7.004,8.574z M18.339,18.338h-2.669 v-4.177c0-0.996-0.017-2.278-1.387-2.278c-1.389,0-1.601,1.086-1.601,2.206v4.249h-2.667v-8.59h2.559v1.174h0.037 c0.356-0.675,1.227-1.387,2.526-1.387c2.703,0,3.203,1.779,3.203,4.092V18.338z"></path></svg><span class="wp-block-social-link-label screen-reader-text">LinkedIn</span></a></li>

<li class="wp-social-link wp-social-link-github  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://github.com/topics/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M12,2C6.477,2,2,6.477,2,12c0,4.419,2.865,8.166,6.839,9.489c0.5,0.09,0.682-0.218,0.682-0.484 c0-0.236-0.009-0.866-0.014-1.699c-2.782,0.602-3.369-1.34-3.369-1.34c-0.455-1.157-1.11-1.465-1.11-1.465 c-0.909-0.62,0.069-0.608,0.069-0.608c1.004,0.071,1.532,1.03,1.532,1.03c0.891,1.529,2.341,1.089,2.91,0.833 c0.091-0.647,0.349-1.086,0.635-1.337c-2.22-0.251-4.555-1.111-4.555-4.943c0-1.091,0.39-1.984,1.03-2.682 C6.546,8.54,6.202,7.524,6.746,6.148c0,0,0.84-0.269,2.75,1.025C10.295,6.95,11.15,6.84,12,6.836 c0.85,0.004,1.705,0.114,2.504,0.336c1.909-1.294,2.748-1.025,2.748-1.025c0.546,1.376,0.202,2.394,0.1,2.646 c0.64,0.699,1.026,1.591,1.026,2.682c0,3.841-2.337,4.687-4.565,4.935c0.359,0.307,0.679,0.917,0.679,1.852 c0,1.335-0.012,2.415-0.012,2.741c0,0.269,0.18,0.579,0.688,0.481C19.138,20.161,22,16.416,22,12C22,6.477,17.523,2,12,2z"></path></svg><span class="wp-block-social-link-label screen-reader-text">GitHub</span></a></li>

<li class="wp-social-link wp-social-link-youtube  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.youtube.com/c/XojoInc" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M21.8,8.001c0,0-0.195-1.378-0.795-1.985c-0.76-0.797-1.613-0.801-2.004-0.847c-2.799-0.202-6.997-0.202-6.997-0.202 h-0.009c0,0-4.198,0-6.997,0.202C4.608,5.216,3.756,5.22,2.995,6.016C2.395,6.623,2.2,8.001,2.2,8.001S2,9.62,2,11.238v1.517 c0,1.618,0.2,3.237,0.2,3.237s0.195,1.378,0.795,1.985c0.761,0.797,1.76,0.771,2.205,0.855c1.6,0.153,6.8,0.201,6.8,0.201 s4.203-0.006,7.001-0.209c0.391-0.047,1.243-0.051,2.004-0.847c0.6-0.607,0.795-1.985,0.795-1.985s0.2-1.618,0.2-3.237v-1.517 C22,9.62,21.8,8.001,21.8,8.001z M9.935,14.594l-0.001-5.62l5.404,2.82L9.935,14.594z"></path></svg><span class="wp-block-social-link-label screen-reader-text">YouTube</span></a></li></ul>



<p class="has-text-align-center has-text-color has-link-color wp-elements-a0a2ac26ad214a49dac577734d259176" style="color:#84bd00"><a href="https://xojo.com/download/" target="_blank" rel="noreferrer noopener">Download Xojo</a></p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Improved macOS App Debugging Experience</title>
		<link>https://blog.xojo.com/2026/07/08/improved-macos-apps-debugging-experience/</link>
		
		<dc:creator><![CDATA[Javier Menendez]]></dc:creator>
		<pubDate>Wed, 08 Jul 2026 13:47:00 +0000</pubDate>
				<category><![CDATA[Learning]]></category>
		<category><![CDATA[Mac]]></category>
		<category><![CDATA[Tips]]></category>
		<category><![CDATA[2026r2]]></category>
		<category><![CDATA[Debugging]]></category>
		<category><![CDATA[Hardened Runtime]]></category>
		<category><![CDATA[Mac App Store]]></category>
		<category><![CDATA[macOS]]></category>
		<category><![CDATA[Sandboxing]]></category>
		<guid isPermaLink="false">https://blog.xojo.com/?p=16345</guid>

					<description><![CDATA[During the last few Xojo releases we have been improving the signing options for macOS apps, making it easier to meet Apple&#8217;s requirements both for&#8230;]]></description>
										<content:encoded><![CDATA[
<p>During the last few Xojo releases we have been improving the signing options for macOS apps, making it easier to meet Apple&#8217;s requirements both for direct distribution of your apps or for Mac App Store distribution. Still, there remained a discrepancy when debugging from the IDE: sandboxing, hardened runtime and the use of entitlements and provisioning profiles were not applied, so there could be a difference between the app you debug and the real behavior of the distributed app.</p>



<span id="more-16345"></span>



<p>The good news is starting with Xojo 2026r2, your debugged macOS apps will exhibit the same behavior your users expect when the app is distributed. For example, if you use sandboxing and hardened runtime, these will be applied. Thus, all the regular operations dealing with files will occur in the sandboxed environment and will meet the settings made under the Build Settings > macOS > Sign > Sandbox panel. This same applies when hardened runtime is selected.</p>


<div class="wp-block-image">
<figure class="aligncenter"><img loading="lazy" decoding="async" width="2504" height="1804" src="https://blog.xojo.com/wp-content/uploads/2026/06/Screenshot-2026-06-23-at-1.46.11-PM.png" alt="" class="wp-image-16346" srcset="https://blog.xojo.com/wp-content/uploads/2026/06/Screenshot-2026-06-23-at-1.46.11-PM.png 2504w, https://blog.xojo.com/wp-content/uploads/2026/06/Screenshot-2026-06-23-at-1.46.11-PM-300x216.png 300w, https://blog.xojo.com/wp-content/uploads/2026/06/Screenshot-2026-06-23-at-1.46.11-PM-1024x738.png 1024w, https://blog.xojo.com/wp-content/uploads/2026/06/Screenshot-2026-06-23-at-1.46.11-PM-768x553.png 768w, https://blog.xojo.com/wp-content/uploads/2026/06/Screenshot-2026-06-23-at-1.46.11-PM-1536x1107.png 1536w, https://blog.xojo.com/wp-content/uploads/2026/06/Screenshot-2026-06-23-at-1.46.11-PM-2048x1475.png 2048w" sizes="auto, (max-width: 2504px) 100vw, 2504px" /></figure>
</div>


<p>In addition, especially for more advanced macOS apps that need to use entitlements and provisioning profiles, these will also be applied when the app is Run / Debug from the Xojo IDE. In this case, make sure to select the Build For > Development Certificate required for signing the app.</p>



<h2 class="wp-block-heading">Debugging with Entitlements in Action</h2>



<p>In order to show how convenient it is to debug macOS apps with entitlements and provisioning profiles applied to them, let&#8217;s make use of one of the small improvements also introduced in Xojo 2026r2: synced KeyChain Passwords. For this to work you will need to have iCloud > Passwords enabled under System Settings > Apple Account > iCloud.</p>



<p>The first step is to create the development provisioning profile from Apple&#8217;s developer portal (specifically for keychain-access-groups), download it and add it to the project using a Copy Build step, making sure that Contents Folder is selected as the destination for the copied file.</p>


<div class="wp-block-image">
<figure class="aligncenter"><img loading="lazy" decoding="async" width="1320" height="652" src="https://blog.xojo.com/wp-content/uploads/2026/06/KeyChainAccessGroup.png" alt="" class="wp-image-16347" srcset="https://blog.xojo.com/wp-content/uploads/2026/06/KeyChainAccessGroup.png 1320w, https://blog.xojo.com/wp-content/uploads/2026/06/KeyChainAccessGroup-300x148.png 300w, https://blog.xojo.com/wp-content/uploads/2026/06/KeyChainAccessGroup-1024x506.png 1024w, https://blog.xojo.com/wp-content/uploads/2026/06/KeyChainAccessGroup-768x379.png 768w" sizes="auto, (max-width: 1320px) 100vw, 1320px" /></figure>
</div>

<div class="wp-block-image">
<figure class="aligncenter"><img loading="lazy" decoding="async" width="1536" height="508" src="https://blog.xojo.com/wp-content/uploads/2026/06/Screenshot-2026-06-23-at-12.55.23-PM.png" alt="" class="wp-image-16348" srcset="https://blog.xojo.com/wp-content/uploads/2026/06/Screenshot-2026-06-23-at-12.55.23-PM.png 1536w, https://blog.xojo.com/wp-content/uploads/2026/06/Screenshot-2026-06-23-at-12.55.23-PM-300x99.png 300w, https://blog.xojo.com/wp-content/uploads/2026/06/Screenshot-2026-06-23-at-12.55.23-PM-1024x339.png 1024w, https://blog.xojo.com/wp-content/uploads/2026/06/Screenshot-2026-06-23-at-12.55.23-PM-768x254.png 768w" sizes="auto, (max-width: 1536px) 100vw, 1536px" /></figure>
</div>


<p><br></p>



<p>Then, we need to create the associated entitlements file using your favourite text editor for that. Make sure it looks like this for the purpose of this example (you will need to change all the references to the app bundle ID and the Developer ID so these match yours):</p>



<pre class="wp-block-preformatted">&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"&gt;
&lt;plist version="1.0"&gt;
&lt;dict&gt;
	&lt;key&gt;keychain-access-groups&lt;/key&gt;
	&lt;array&gt;
		&lt;string&gt;BW7PU32485.*&lt;/string&gt;
	&lt;/array&gt;
	&lt;key&gt;com.apple.application-identifier&lt;/key&gt;
	&lt;string&gt;BW7PU32485.com.aprendexojo.Cheese&lt;/string&gt;
&lt;/dict&gt;
&lt;/plist&gt;
</pre>



<p>Once created and saved using the &#8220;.entitlements&#8221; extension, add it to Build Settings > macOS > Sign > User Entitlements.</p>



<h3 class="wp-block-heading">Creating a Synced Password</h3>



<p>After adding a button to the default project Window, implement the Pressed event handler and add this fragment of code into the associated Code Editor:</p>



<pre class="wp-block-preformatted">Var newItem As KeychainItem

If System.KeychainCount &gt; 0 Then

  newItem = New KeychainItem
  newItem.Label = "This is a Label"
  newItem.Description = "This is a description"
  newItem.ServiceName = "MyApplication"
  newItem.AccountName = "XojoTest"
  newItem.Comment = "This is a comment"
  
  ' Assign a password to the item
  ' Passing True as the third parameter means we want this one
  ' to be created / saved under the iCloud keychain,
  ' so it will be automatically synced with other Macs using
  ' the same iCloud user account.
  
  System.Keychain.AddPassword(newItem, "SecretPassword", true)
Else
  System.Beep
  MessageBox("You don't have a key chain.")
End If

Exception e As KeychainException
  MessageBox("Keychain error: " + e.Message)
</pre>



<p>Run the app from the IDE (you can enable both sandboxing and hardened runtime too if you wish), click the button  and it will behave the same way it will when deployed. If you open Keychain Access app, select the iCloud entry in the Keychain window sidebar, and select then the Passwords option you will see the new added password from the debugged app.</p>


<div class="wp-block-image">
<figure class="aligncenter"><img loading="lazy" decoding="async" width="1676" height="1290" src="https://blog.xojo.com/wp-content/uploads/2026/06/Screenshot-2026-06-23-at-1.29.31-PM.png" alt="" class="wp-image-16349" srcset="https://blog.xojo.com/wp-content/uploads/2026/06/Screenshot-2026-06-23-at-1.29.31-PM.png 1676w, https://blog.xojo.com/wp-content/uploads/2026/06/Screenshot-2026-06-23-at-1.29.31-PM-300x231.png 300w, https://blog.xojo.com/wp-content/uploads/2026/06/Screenshot-2026-06-23-at-1.29.31-PM-1024x788.png 1024w, https://blog.xojo.com/wp-content/uploads/2026/06/Screenshot-2026-06-23-at-1.29.31-PM-768x591.png 768w, https://blog.xojo.com/wp-content/uploads/2026/06/Screenshot-2026-06-23-at-1.29.31-PM-1536x1182.png 1536w" sizes="auto, (max-width: 1676px) 100vw, 1676px" /></figure>
</div>


<p>Obviously, if you have more than a Mac using the same user iCloud account, you wil be able to see how that password will be synced and added to its Keychain too after a few seconds.</p>



<figure class="wp-block-image"><img loading="lazy" decoding="async" width="1818" height="1276" src="https://blog.xojo.com/wp-content/uploads/2026/06/Screenshot-2026-06-23-at-13.52.52.png" alt="" class="wp-image-16351" srcset="https://blog.xojo.com/wp-content/uploads/2026/06/Screenshot-2026-06-23-at-13.52.52.png 1818w, https://blog.xojo.com/wp-content/uploads/2026/06/Screenshot-2026-06-23-at-13.52.52-300x211.png 300w, https://blog.xojo.com/wp-content/uploads/2026/06/Screenshot-2026-06-23-at-13.52.52-1024x719.png 1024w, https://blog.xojo.com/wp-content/uploads/2026/06/Screenshot-2026-06-23-at-13.52.52-768x539.png 768w, https://blog.xojo.com/wp-content/uploads/2026/06/Screenshot-2026-06-23-at-13.52.52-1536x1078.png 1536w" sizes="auto, (max-width: 1818px) 100vw, 1818px" /></figure>



<p>All in all, this means two things:</p>



<ol class="wp-block-list">
<li>macOS debugged apps exhibit the same behavior expected when these are deployed, which means that you will be able to debug them in more real conditions.</li>



<li>The new ability to create synced passwords is quite convenient for those macOS apps making use of these, so your users won&#8217;t be required to create them again on each of their Macs or create different ones on each Mac they own.</li>
</ol>



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



<p>As we saw, setting sandboxing, hardened runtime, using entitlements and even provisioning profiles in you macOS apps during the debugging process now avoids conditional compilation branches, and provides a closer experience to the final (distributed) app, and even makes it easier to detect bugs in the code.</p>



<p><em>Javier Menendez is an engineer at Xojo and has been using Xojo since 1998. He lives in Castellón</em>, <em>Spain and hosts regular Xojo hangouts en español. Ask Javier questions on Twitter at <a href="https://twitter.com/xojoes" target="_blank" rel="noreferrer noopener">@XojoES</a> or on the <a href="https://forum.xojo.com/u/javier_menendez/summary" target="_blank" rel="noreferrer noopener">Xojo Forum</a>.</em></p>



<ul class="wp-block-social-links has-normal-icon-size is-content-justification-center is-layout-flex wp-container-core-social-links-is-layout-16018d1d wp-block-social-links-is-layout-flex"><li class="wp-social-link wp-social-link-facebook  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.facebook.com/goxojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M12 2C6.5 2 2 6.5 2 12c0 5 3.7 9.1 8.4 9.9v-7H7.9V12h2.5V9.8c0-2.5 1.5-3.9 3.8-3.9 1.1 0 2.2.2 2.2.2v2.5h-1.3c-1.2 0-1.6.8-1.6 1.6V12h2.8l-.4 2.9h-2.3v7C18.3 21.1 22 17 22 12c0-5.5-4.5-10-10-10z"></path></svg><span class="wp-block-social-link-label screen-reader-text">Facebook</span></a></li>

<li class="wp-social-link wp-social-link-x  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://x.com/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M13.982 10.622 20.54 3h-1.554l-5.693 6.618L8.745 3H3.5l6.876 10.007L3.5 21h1.554l6.012-6.989L15.868 21h5.245l-7.131-10.378Zm-2.128 2.474-.697-.997-5.543-7.93H8l4.474 6.4.697.996 5.815 8.318h-2.387l-4.745-6.787Z" /></svg><span class="wp-block-social-link-label screen-reader-text">X</span></a></li>

<li class="wp-social-link wp-social-link-linkedin  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.linkedin.com/company/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M19.7,3H4.3C3.582,3,3,3.582,3,4.3v15.4C3,20.418,3.582,21,4.3,21h15.4c0.718,0,1.3-0.582,1.3-1.3V4.3 C21,3.582,20.418,3,19.7,3z M8.339,18.338H5.667v-8.59h2.672V18.338z M7.004,8.574c-0.857,0-1.549-0.694-1.549-1.548 c0-0.855,0.691-1.548,1.549-1.548c0.854,0,1.547,0.694,1.547,1.548C8.551,7.881,7.858,8.574,7.004,8.574z M18.339,18.338h-2.669 v-4.177c0-0.996-0.017-2.278-1.387-2.278c-1.389,0-1.601,1.086-1.601,2.206v4.249h-2.667v-8.59h2.559v1.174h0.037 c0.356-0.675,1.227-1.387,2.526-1.387c2.703,0,3.203,1.779,3.203,4.092V18.338z"></path></svg><span class="wp-block-social-link-label screen-reader-text">LinkedIn</span></a></li>

<li class="wp-social-link wp-social-link-github  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://github.com/topics/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M12,2C6.477,2,2,6.477,2,12c0,4.419,2.865,8.166,6.839,9.489c0.5,0.09,0.682-0.218,0.682-0.484 c0-0.236-0.009-0.866-0.014-1.699c-2.782,0.602-3.369-1.34-3.369-1.34c-0.455-1.157-1.11-1.465-1.11-1.465 c-0.909-0.62,0.069-0.608,0.069-0.608c1.004,0.071,1.532,1.03,1.532,1.03c0.891,1.529,2.341,1.089,2.91,0.833 c0.091-0.647,0.349-1.086,0.635-1.337c-2.22-0.251-4.555-1.111-4.555-4.943c0-1.091,0.39-1.984,1.03-2.682 C6.546,8.54,6.202,7.524,6.746,6.148c0,0,0.84-0.269,2.75,1.025C10.295,6.95,11.15,6.84,12,6.836 c0.85,0.004,1.705,0.114,2.504,0.336c1.909-1.294,2.748-1.025,2.748-1.025c0.546,1.376,0.202,2.394,0.1,2.646 c0.64,0.699,1.026,1.591,1.026,2.682c0,3.841-2.337,4.687-4.565,4.935c0.359,0.307,0.679,0.917,0.679,1.852 c0,1.335-0.012,2.415-0.012,2.741c0,0.269,0.18,0.579,0.688,0.481C19.138,20.161,22,16.416,22,12C22,6.477,17.523,2,12,2z"></path></svg><span class="wp-block-social-link-label screen-reader-text">GitHub</span></a></li>

<li class="wp-social-link wp-social-link-youtube  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.youtube.com/c/XojoInc" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M21.8,8.001c0,0-0.195-1.378-0.795-1.985c-0.76-0.797-1.613-0.801-2.004-0.847c-2.799-0.202-6.997-0.202-6.997-0.202 h-0.009c0,0-4.198,0-6.997,0.202C4.608,5.216,3.756,5.22,2.995,6.016C2.395,6.623,2.2,8.001,2.2,8.001S2,9.62,2,11.238v1.517 c0,1.618,0.2,3.237,0.2,3.237s0.195,1.378,0.795,1.985c0.761,0.797,1.76,0.771,2.205,0.855c1.6,0.153,6.8,0.201,6.8,0.201 s4.203-0.006,7.001-0.209c0.391-0.047,1.243-0.051,2.004-0.847c0.6-0.607,0.795-1.985,0.795-1.985s0.2-1.618,0.2-3.237v-1.517 C22,9.62,21.8,8.001,21.8,8.001z M9.935,14.594l-0.001-5.62l5.404,2.82L9.935,14.594z"></path></svg><span class="wp-block-social-link-label screen-reader-text">YouTube</span></a></li></ul>



<p class="has-text-align-center has-text-color has-link-color wp-elements-a0a2ac26ad214a49dac577734d259176" style="color:#84bd00"><a href="https://xojo.com/download/" target="_blank" rel="noreferrer noopener">Download Xojo</a></p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>iOS Framework Improvements</title>
		<link>https://blog.xojo.com/2026/07/08/ios-framework-improvements/</link>
		
		<dc:creator><![CDATA[Javier Menendez]]></dc:creator>
		<pubDate>Wed, 08 Jul 2026 13:46:00 +0000</pubDate>
				<category><![CDATA[iOS]]></category>
		<category><![CDATA[2026r2]]></category>
		<category><![CDATA[Apple]]></category>
		<category><![CDATA[Xojo Programming Language]]></category>
		<guid isPermaLink="false">https://blog.xojo.com/?p=16304</guid>

					<description><![CDATA[The iOS Framework has received a number of additions and improvements in Xojo 2026r2. Some of them will be mandatory for your existing iOS apps&#8230;]]></description>
										<content:encoded><![CDATA[
<p>The iOS Framework has received a number of additions and improvements in Xojo 2026r2. Some of them will be mandatory for your existing iOS apps created with Xojo, while others are targeted to improve your iOS apps&#8217; UI designs and functionality. Let&#8217;s talk about them!</p>



<span id="more-16304"></span>



<h2 class="wp-block-heading">Behind the Scenes…</h2>



<p>Let&#8217;s start with a non-visible change, but a major and important one. In fact, this responds to one of Apple&#8217;s requirements for iOS apps:</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>&#8220;In the next major release following iOS 26, UIScene lifecycle will be required when building with the latest SDK; otherwise, your app won’t launch.&#8221;</p>
</blockquote>



<p>Xojo has made the necessary underlying changes in the iOS Framework, and starting with Xojo 2026r2, all iOS apps are compiled/built so they can be run and published meeting this requirement.</p>



<p>What does this mean for you in practice? For any existing Xojo iOS projects, all you need to do is rebuild them with the current version of Xojo. This guarantees that the apps implement the required UIScene lifecycle and can be run without issues both on the iOS simulators and real iOS devices using iOS 26+.</p>



<h2 class="wp-block-heading">MobilePopupMenu Arrives to iOS</h2>



<p>Until now, making simple selections in iOS projects required a complex UI design involving navigation to different screens, the use of tables, containers, etc.&nbsp;Starting with Xojo 2026r2, we have simplified everything with the new MobilePopupMenu control.</p>



<figure class="wp-block-video"><video autoplay controls src="https://blog.xojo.com/wp-content/uploads/2026/06/Simulator-Screen-Recording-iPhone-17-2026-06-08-at-10.29.10.mp4"></video></figure>



<p>In fact, the feature also uses a newly added class for the displayed menu entries: MobileMenuItem (more on this a bit later). It is also possible to add new entries to the menu as text, if you prefer. No matter how entries are added to the PopupMenuControl&#8217;s menu, the underlying items are MobileMenuItem instances, and these are the ones received in the SelectionChanged event handler.</p>



<p>You can populate the MobilePopupMenu entries at design time via the associated Inspector Panel, and select the default SelectedRowIndex value. Of course, you can do the same at runtime and change the control&#8217;s menu entries as you would with the equivalent control on Desktop.</p>



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



<p>This new class added to the iOS Framework lets you create menu entries for the MobilePopupMenu, as well as for the newly added Menu properties on MobileButton and MobileToolbarButton.</p>



<p>Like its Desktop counterpart, it is possible to create hierarchical menu entries and assign icons to each item. What is specific to MobileMenuItem on iOS are the Destructive (Boolean) and DisplayMode (Enum) properties. When a MobileMenuItem instance is set to Destructive, it will be displayed as such under the iOS Design Guidelines, giving users a clear visual clue about the potentially destructive action.</p>



<p>The DisplayMode property can be set as Regular (the usual dropdown displaying of a menu) or as Palette. With Palette, child entries are presented in a smaller palette with horizontal navigation, which is especially recommended for tight UI designs where options are shown as icons.</p>



<p>If a MobileMenuItem is set to a MobilePopupMenu, it will not display the icons for the menu entries and will discard any  child hierarchies (submenus), as is also the case for DesktopPopupMenu and WebPopupMenu. On the other hand, MobileButton and MobileToolbarButton are able to support submenus and will display the associated icons for every menu entry.</p>



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



<p>As previously noted, this control has new properties related to displaying a menu. It is possible to set the menu (MobileMenuItem instance) at runtime, and the behavior is controlled by the DisplayMenuAsAction (Boolean) property.</p>



<figure class="wp-block-video"><video autoplay controls src="https://blog.xojo.com/wp-content/uploads/2026/06/Screen-Recording-2026-06-08-at-10.40.58.mp4"></video></figure>



<p>When DisplayMenuAsAction is set to False (the default), the Button fires its Pressed event as usual, and the menu is displayed only after a long press on the button. The menu selection made by the user will be received through the new MenuItemSelected(menu As MobileMenuItem) event handler that can be implemented on the button instance itself. All in all, this provides a good way for the button to react to two different user interactions.</p>



<p>If the DisplayMenuAsAction property is set to True, the associated menu is presented when the button is pressed. In this case, the Pressed event handler will not fire, only its MenuItemSelected (menu as MobileMenuItem) handler will fire after the user makes a selection in the menu.</p>



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



<p>MobileToolbarButton also has the new Menu and DisplayMenuAsAction properties, and these behave in the same way as described above. The main difference is that, in this case, the MenuItemSelected event handler needs to be implemented in the containing Screen instance for the NavigationBar to which the MobileToolbarButton has been added, just as the pre-existing ToolbarButtonPressed event handler was.</p>



<figure class="wp-block-video"><video autoplay controls preload="auto" src="https://blog.xojo.com/wp-content/uploads/2026/06/Screen-Recording-2026-06-08-at-10.52.00.mp4"></video></figure>



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



<p>In addition to the support of menus, MobileToolbarButton also got the ability to display badges. This is useful in order to simplify many mobile apps UI designs.</p>



<figure class="wp-block-video"><video autoplay controls src="https://blog.xojo.com/wp-content/uploads/2026/06/Screen-Recording-2026-06-08-at-10.57.49.mp4"></video></figure>



<p>The information shown in the badge is set through the MobileToolbarButton.BadgeText property. If this property is set to  an empty string, the badge will not be displayed. In addition, there are other properties you can use to customize the badge&#8217;s appearance:</p>



<ul class="wp-block-list">
<li><strong>BadgeColor As ColorGroup</strong>. Set the background color for the badge.</li>



<li><strong>BadgeTextColor As ColorGroup</strong>. Set the color for the text displayed in the badge.</li>



<li><strong>BadgeTextFont As Font</strong>. Set the font, style and font size to be used by the text in the badge.</li>
</ul>



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



<p>The new iOS Scenes based lifecycle will keep your apps in compliance with the requirement from Apple for future iOS releases beyond iOS 26, and we hope you will find the new menu items useful additions to simplify your iOS UI designs.</p>



<p>We are interested to know more about how you use these features, and invite you to share your iOS stuff on the <a href="https://forum.xojo.com/c/targets/ios/37">Xojo Forum</a> iOS channel!</p>



<p>Special thanks to Xojo MVP Jérèmie Leroy, he is always pushing and helping improve Xojo&#8217;s iOS support. </p>



<p><em>Javier Menendez is an engineer at Xojo and has been using Xojo since 1998. He lives in Castellón</em>, <em>Spain and hosts regular Xojo hangouts en español. Ask Javier questions on Twitter at <a href="https://twitter.com/xojoes" target="_blank" rel="noreferrer noopener">@XojoES</a> or on the <a href="https://forum.xojo.com/u/javier_menendez/summary" target="_blank" rel="noreferrer noopener">Xojo Forum</a>.</em></p>



<ul class="wp-block-social-links has-normal-icon-size is-content-justification-center is-layout-flex wp-container-core-social-links-is-layout-16018d1d wp-block-social-links-is-layout-flex"><li class="wp-social-link wp-social-link-facebook  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.facebook.com/goxojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M12 2C6.5 2 2 6.5 2 12c0 5 3.7 9.1 8.4 9.9v-7H7.9V12h2.5V9.8c0-2.5 1.5-3.9 3.8-3.9 1.1 0 2.2.2 2.2.2v2.5h-1.3c-1.2 0-1.6.8-1.6 1.6V12h2.8l-.4 2.9h-2.3v7C18.3 21.1 22 17 22 12c0-5.5-4.5-10-10-10z"></path></svg><span class="wp-block-social-link-label screen-reader-text">Facebook</span></a></li>

<li class="wp-social-link wp-social-link-x  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://x.com/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M13.982 10.622 20.54 3h-1.554l-5.693 6.618L8.745 3H3.5l6.876 10.007L3.5 21h1.554l6.012-6.989L15.868 21h5.245l-7.131-10.378Zm-2.128 2.474-.697-.997-5.543-7.93H8l4.474 6.4.697.996 5.815 8.318h-2.387l-4.745-6.787Z" /></svg><span class="wp-block-social-link-label screen-reader-text">X</span></a></li>

<li class="wp-social-link wp-social-link-linkedin  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.linkedin.com/company/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M19.7,3H4.3C3.582,3,3,3.582,3,4.3v15.4C3,20.418,3.582,21,4.3,21h15.4c0.718,0,1.3-0.582,1.3-1.3V4.3 C21,3.582,20.418,3,19.7,3z M8.339,18.338H5.667v-8.59h2.672V18.338z M7.004,8.574c-0.857,0-1.549-0.694-1.549-1.548 c0-0.855,0.691-1.548,1.549-1.548c0.854,0,1.547,0.694,1.547,1.548C8.551,7.881,7.858,8.574,7.004,8.574z M18.339,18.338h-2.669 v-4.177c0-0.996-0.017-2.278-1.387-2.278c-1.389,0-1.601,1.086-1.601,2.206v4.249h-2.667v-8.59h2.559v1.174h0.037 c0.356-0.675,1.227-1.387,2.526-1.387c2.703,0,3.203,1.779,3.203,4.092V18.338z"></path></svg><span class="wp-block-social-link-label screen-reader-text">LinkedIn</span></a></li>

<li class="wp-social-link wp-social-link-github  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://github.com/topics/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M12,2C6.477,2,2,6.477,2,12c0,4.419,2.865,8.166,6.839,9.489c0.5,0.09,0.682-0.218,0.682-0.484 c0-0.236-0.009-0.866-0.014-1.699c-2.782,0.602-3.369-1.34-3.369-1.34c-0.455-1.157-1.11-1.465-1.11-1.465 c-0.909-0.62,0.069-0.608,0.069-0.608c1.004,0.071,1.532,1.03,1.532,1.03c0.891,1.529,2.341,1.089,2.91,0.833 c0.091-0.647,0.349-1.086,0.635-1.337c-2.22-0.251-4.555-1.111-4.555-4.943c0-1.091,0.39-1.984,1.03-2.682 C6.546,8.54,6.202,7.524,6.746,6.148c0,0,0.84-0.269,2.75,1.025C10.295,6.95,11.15,6.84,12,6.836 c0.85,0.004,1.705,0.114,2.504,0.336c1.909-1.294,2.748-1.025,2.748-1.025c0.546,1.376,0.202,2.394,0.1,2.646 c0.64,0.699,1.026,1.591,1.026,2.682c0,3.841-2.337,4.687-4.565,4.935c0.359,0.307,0.679,0.917,0.679,1.852 c0,1.335-0.012,2.415-0.012,2.741c0,0.269,0.18,0.579,0.688,0.481C19.138,20.161,22,16.416,22,12C22,6.477,17.523,2,12,2z"></path></svg><span class="wp-block-social-link-label screen-reader-text">GitHub</span></a></li>

<li class="wp-social-link wp-social-link-youtube  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.youtube.com/c/XojoInc" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M21.8,8.001c0,0-0.195-1.378-0.795-1.985c-0.76-0.797-1.613-0.801-2.004-0.847c-2.799-0.202-6.997-0.202-6.997-0.202 h-0.009c0,0-4.198,0-6.997,0.202C4.608,5.216,3.756,5.22,2.995,6.016C2.395,6.623,2.2,8.001,2.2,8.001S2,9.62,2,11.238v1.517 c0,1.618,0.2,3.237,0.2,3.237s0.195,1.378,0.795,1.985c0.761,0.797,1.76,0.771,2.205,0.855c1.6,0.153,6.8,0.201,6.8,0.201 s4.203-0.006,7.001-0.209c0.391-0.047,1.243-0.051,2.004-0.847c0.6-0.607,0.795-1.985,0.795-1.985s0.2-1.618,0.2-3.237v-1.517 C22,9.62,21.8,8.001,21.8,8.001z M9.935,14.594l-0.001-5.62l5.404,2.82L9.935,14.594z"></path></svg><span class="wp-block-social-link-label screen-reader-text">YouTube</span></a></li></ul>



<p class="has-text-align-center has-text-color has-link-color wp-elements-a0a2ac26ad214a49dac577734d259176" style="color:#84bd00"><a href="https://xojo.com/download/" target="_blank" rel="noreferrer noopener">Download Xojo</a></p>
]]></content:encoded>
					
		
		<enclosure url="https://blog.xojo.com/wp-content/uploads/2026/06/Simulator-Screen-Recording-iPhone-17-2026-06-08-at-10.29.10.mp4" length="150151" type="video/mp4" />
<enclosure url="https://blog.xojo.com/wp-content/uploads/2026/06/Screen-Recording-2026-06-08-at-10.40.58.mp4" length="406127" type="video/mp4" />
<enclosure url="https://blog.xojo.com/wp-content/uploads/2026/06/Screen-Recording-2026-06-08-at-10.52.00.mp4" length="327878" type="video/mp4" />
<enclosure url="https://blog.xojo.com/wp-content/uploads/2026/06/Screen-Recording-2026-06-08-at-10.57.49.mp4" length="76573" type="video/mp4" />

			</item>
		<item>
		<title>DesktopHTMLViewer Adds WebView2 Support on Windows</title>
		<link>https://blog.xojo.com/2026/07/08/desktophtmlviewer-adds-webview2-support-on-windows/</link>
		
		<dc:creator><![CDATA[William Yu]]></dc:creator>
		<pubDate>Wed, 08 Jul 2026 13:46:00 +0000</pubDate>
				<category><![CDATA[Desktop]]></category>
		<category><![CDATA[General]]></category>
		<category><![CDATA[Learning]]></category>
		<category><![CDATA[Tips]]></category>
		<category><![CDATA[Windows]]></category>
		<category><![CDATA[2026r2]]></category>
		<category><![CDATA[CEF]]></category>
		<category><![CDATA[DesktopHTMLViewer]]></category>
		<category><![CDATA[WebView2]]></category>
		<guid isPermaLink="false">https://blog.xojo.com/?p=16355</guid>

					<description><![CDATA[In Xojo 2026r2, developers targeting Windows now have a new option for&#160;DesktopHTMLViewer: support for Microsoft Edge WebView2. This is an important change for those who&#8230;]]></description>
										<content:encoded><![CDATA[
<p>In Xojo 2026r2, developers targeting Windows now have a new option for&nbsp;DesktopHTMLViewer: support for Microsoft Edge WebView2.</p>



<p>This is an important change for those who want modern web rendering on Windows without the large deployment footprint required by the Chromium Embedded Framework (CEF).</p>



<h2 class="wp-block-heading">Why WebView2 Matters</h2>



<p>Until now, Windows HTML rendering in&nbsp;DesktopHTMLViewer&nbsp;has primarily relied on CEF. While CEF provides excellent compatibility and a consistent Chromium-based rendering engine, it also comes with a substantial deployment cost. Including the required CEF runtime files can add well over 200 MB to an application&#8217;s distribution size.</p>



<p>Using CEF also means applications are tied to specific Chromium and CEF versions bundled with the app itself. Keeping current requires continuously rebuilding and redistributing newer CEF releases as Chromium evolves and security updates are released.</p>



<p>WebView2 changes that equation considerably.</p>



<p>Because WebView2 uses the Microsoft Edge rendering engine already present on many modern Windows systems, applications can avoid bundling a large embedded Chromium runtime entirely. Security and changes to WebView2 are handled through the operating system via Windows Update, rather than requiring applications to ship and maintain their own browser engine updates.</p>



<h2 class="wp-block-heading">WebView2 Runtime Requirements</h2>



<p>One important consideration is that WebView2 may require the Microsoft Edge WebView2 Runtime to be installed on the target system.</p>



<h3 class="wp-block-heading">Windows 11</h3>



<p>Most Windows 11 systems already include WebView2 as part of the operating system, so no additional installation is usually necessary.</p>



<h3 class="wp-block-heading">Windows 10</h3>



<p>Many Windows 10 systems already have the runtime installed because Microsoft distributes it through Edge and Microsoft 365 updates. However, older or managed systems may still require a separate runtime installation.</p>



<p>Applications that depend on WebView2 should verify runtime availability during installation and, if it is not present, either prompt the user or provide a link to download and install the required runtime.</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f449.png" alt="👉" class="wp-smiley" style="height: 1em; max-height: 1em;" /> You can also check&nbsp;<code>DesktopHTMLViewer.IsAvailable</code>&nbsp;at runtime to determine whether WebView2 is available.</p>
</blockquote>



<p>Microsoft provides the runtime here:<br><a href="https://developer.microsoft.com/en-us/microsoft-edge/webview2/" target="_blank" rel="noreferrer noopener">https://developer.microsoft.com/en-us/microsoft-edge/webview2/</a></p>



<h2 class="wp-block-heading">WinUI Targets Use WebView2 by Default</h2>



<p>For WinUI desktop targets, WebView2 is now the default (and only) HTML rendering engine for the DesktopHTMLViewer. In addition, any new projects created in Xojo 2026r2 or later will default to using the WebView2 engine whenever a&nbsp;DesktopHTMLViewer&nbsp;is added to the layout.</p>



<h3 class="wp-block-heading">Enabling WebView2 in older projects or non-WinUI Windows targets</h3>



<p>For traditional Windows desktop targets that are not using WinUI, you can still opt into WebView2 support by enabling the <strong>HTMLViewer uses WebView2</strong> option in the Advanced Windows build setting in the IDE:</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="692" src="https://blog.xojo.com/wp-content/uploads/2026/06/HTMLViewerUsersWebView2-1024x692.png" alt="" class="wp-image-16364" srcset="https://blog.xojo.com/wp-content/uploads/2026/06/HTMLViewerUsersWebView2-1024x692.png 1024w, https://blog.xojo.com/wp-content/uploads/2026/06/HTMLViewerUsersWebView2-300x203.png 300w, https://blog.xojo.com/wp-content/uploads/2026/06/HTMLViewerUsersWebView2-768x519.png 768w, https://blog.xojo.com/wp-content/uploads/2026/06/HTMLViewerUsersWebView2.png 1504w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p>When enabled,&nbsp;DesktopHTMLViewer&nbsp;will use WebView2 instead of CEF for HTML rendering.</p>



<p>This gives you the flexibility to choose between:</p>



<ul class="wp-block-list">
<li>smaller deployment size with WebView2, or</li>



<li>fully self-contained deployment with CEF</li>
</ul>



<p>depending on the needs of your application and target audience. However, moving forward we will be transitioning away from CEF entirely, and it is likely that we will no longer support or update our CEF based HTMLViewer in future releases.</p>



<h2 class="wp-block-heading">Differences from CEF</h2>



<p>Although both CEF and WebView2 are Chromium-based technologies, there are some behavioral differences you should be aware of:</p>



<ul class="wp-block-list">
<li>You may notice some subtle differences in how WebView2 returns results for JSON.Stringify when executed using ExecuteJavaScriptSync. i.e. the result coming back may be quoted.</li>



<li>executeInXojoSync is supported, but it uses JavaScript Promises to simulate synchronous behavior, so existing code may need to be updated to use async/await. Example:&nbsp;<code>const result = await executeInXojoSync("addNumbers", 2, 3);</code></li>



<li>A WebView2-specific cache folder is created alongside the executable. If that directory is not writable, the cache folder is instead created in the user&#8217;s local AppData directory.</li>
</ul>



<h2 class="wp-block-heading">Final Thoughts</h2>



<p>The addition of WebView2 support for&nbsp;DesktopHTMLViewer&nbsp;is a major improvement for Windows desktop deployment in Xojo, and reducing runtime size by hundreds of megabytes while still delivering modern Chromium-based rendering is a significant win.</p>



<p>Those who require rendering consistency or offline/self-contained deployments may still prefer CEF, but WebView2 offers an excellent modern alternative that better matches the direction of the Windows platform itself.</p>



<p>For now, you can choose between either engine depending on your needs, but moving forward we believe WebView2 is the preferred path on Windows. Happy browsing!</p>



<p><em><em><em>William Yu grew up in Canada learning to program BASIC on a Vic-20. He is Xojo’s resident Windows and Linux engineer, among his many other skills. Some may say he has joined the dark side here in the USA, but he will always be a Canadian at heart.</em></em></em></p>



<ul class="wp-block-social-links has-normal-icon-size is-content-justification-center is-layout-flex wp-container-core-social-links-is-layout-16018d1d wp-block-social-links-is-layout-flex"><li class="wp-social-link wp-social-link-facebook  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.facebook.com/goxojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M12 2C6.5 2 2 6.5 2 12c0 5 3.7 9.1 8.4 9.9v-7H7.9V12h2.5V9.8c0-2.5 1.5-3.9 3.8-3.9 1.1 0 2.2.2 2.2.2v2.5h-1.3c-1.2 0-1.6.8-1.6 1.6V12h2.8l-.4 2.9h-2.3v7C18.3 21.1 22 17 22 12c0-5.5-4.5-10-10-10z"></path></svg><span class="wp-block-social-link-label screen-reader-text">Facebook</span></a></li>

<li class="wp-social-link wp-social-link-x  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://x.com/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M13.982 10.622 20.54 3h-1.554l-5.693 6.618L8.745 3H3.5l6.876 10.007L3.5 21h1.554l6.012-6.989L15.868 21h5.245l-7.131-10.378Zm-2.128 2.474-.697-.997-5.543-7.93H8l4.474 6.4.697.996 5.815 8.318h-2.387l-4.745-6.787Z" /></svg><span class="wp-block-social-link-label screen-reader-text">X</span></a></li>

<li class="wp-social-link wp-social-link-linkedin  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.linkedin.com/company/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M19.7,3H4.3C3.582,3,3,3.582,3,4.3v15.4C3,20.418,3.582,21,4.3,21h15.4c0.718,0,1.3-0.582,1.3-1.3V4.3 C21,3.582,20.418,3,19.7,3z M8.339,18.338H5.667v-8.59h2.672V18.338z M7.004,8.574c-0.857,0-1.549-0.694-1.549-1.548 c0-0.855,0.691-1.548,1.549-1.548c0.854,0,1.547,0.694,1.547,1.548C8.551,7.881,7.858,8.574,7.004,8.574z M18.339,18.338h-2.669 v-4.177c0-0.996-0.017-2.278-1.387-2.278c-1.389,0-1.601,1.086-1.601,2.206v4.249h-2.667v-8.59h2.559v1.174h0.037 c0.356-0.675,1.227-1.387,2.526-1.387c2.703,0,3.203,1.779,3.203,4.092V18.338z"></path></svg><span class="wp-block-social-link-label screen-reader-text">LinkedIn</span></a></li>

<li class="wp-social-link wp-social-link-github  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://github.com/topics/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M12,2C6.477,2,2,6.477,2,12c0,4.419,2.865,8.166,6.839,9.489c0.5,0.09,0.682-0.218,0.682-0.484 c0-0.236-0.009-0.866-0.014-1.699c-2.782,0.602-3.369-1.34-3.369-1.34c-0.455-1.157-1.11-1.465-1.11-1.465 c-0.909-0.62,0.069-0.608,0.069-0.608c1.004,0.071,1.532,1.03,1.532,1.03c0.891,1.529,2.341,1.089,2.91,0.833 c0.091-0.647,0.349-1.086,0.635-1.337c-2.22-0.251-4.555-1.111-4.555-4.943c0-1.091,0.39-1.984,1.03-2.682 C6.546,8.54,6.202,7.524,6.746,6.148c0,0,0.84-0.269,2.75,1.025C10.295,6.95,11.15,6.84,12,6.836 c0.85,0.004,1.705,0.114,2.504,0.336c1.909-1.294,2.748-1.025,2.748-1.025c0.546,1.376,0.202,2.394,0.1,2.646 c0.64,0.699,1.026,1.591,1.026,2.682c0,3.841-2.337,4.687-4.565,4.935c0.359,0.307,0.679,0.917,0.679,1.852 c0,1.335-0.012,2.415-0.012,2.741c0,0.269,0.18,0.579,0.688,0.481C19.138,20.161,22,16.416,22,12C22,6.477,17.523,2,12,2z"></path></svg><span class="wp-block-social-link-label screen-reader-text">GitHub</span></a></li>

<li class="wp-social-link wp-social-link-youtube  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.youtube.com/c/XojoInc" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M21.8,8.001c0,0-0.195-1.378-0.795-1.985c-0.76-0.797-1.613-0.801-2.004-0.847c-2.799-0.202-6.997-0.202-6.997-0.202 h-0.009c0,0-4.198,0-6.997,0.202C4.608,5.216,3.756,5.22,2.995,6.016C2.395,6.623,2.2,8.001,2.2,8.001S2,9.62,2,11.238v1.517 c0,1.618,0.2,3.237,0.2,3.237s0.195,1.378,0.795,1.985c0.761,0.797,1.76,0.771,2.205,0.855c1.6,0.153,6.8,0.201,6.8,0.201 s4.203-0.006,7.001-0.209c0.391-0.047,1.243-0.051,2.004-0.847c0.6-0.607,0.795-1.985,0.795-1.985s0.2-1.618,0.2-3.237v-1.517 C22,9.62,21.8,8.001,21.8,8.001z M9.935,14.594l-0.001-5.62l5.404,2.82L9.935,14.594z"></path></svg><span class="wp-block-social-link-label screen-reader-text">YouTube</span></a></li></ul>



<p class="has-text-align-center has-text-color has-link-color wp-elements-a0a2ac26ad214a49dac577734d259176" style="color:#84bd00"><a href="https://xojo.com/download/" target="_blank" rel="noreferrer noopener">Download Xojo</a></p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>New DesktopToolbar Enhancements</title>
		<link>https://blog.xojo.com/2026/07/08/new-desktoptoolbar-enhancements/</link>
		
		<dc:creator><![CDATA[William Yu]]></dc:creator>
		<pubDate>Wed, 08 Jul 2026 13:45:00 +0000</pubDate>
				<category><![CDATA[Cross-Platform]]></category>
		<category><![CDATA[Desktop]]></category>
		<category><![CDATA[General]]></category>
		<category><![CDATA[Learning]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[Mac]]></category>
		<category><![CDATA[Tips]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[Windows]]></category>
		<category><![CDATA[2026r2]]></category>
		<category><![CDATA[DesktopToolbar]]></category>
		<category><![CDATA[Symbols]]></category>
		<category><![CDATA[Toolbar]]></category>
		<guid isPermaLink="false">https://blog.xojo.com/?p=16368</guid>

					<description><![CDATA[The latest updates to DesktopToolbar add new options that make toolbars easier to customize across all platforms, along with support for WinUI on Windows. These&#8230;]]></description>
										<content:encoded><![CDATA[
<p>The latest updates to DesktopToolbar add new options that make toolbars easier to customize across all platforms, along with support for WinUI on Windows.</p>



<p>These changes focus on two main areas:</p>



<ul class="wp-block-list">
<li>Expanded button symbol support in&nbsp;DesktopToolbarButton</li>



<li>New layout and presentation control via toolbar style options</li>
</ul>



<h2 class="wp-block-heading">Smarter Icon Handling with Symbols</h2>



<p>A key addition is the new <code>Symbol</code> property on DesktopToolbarButton. It lets you provide a single string containing multiple symbol names separated by semicolons. Each platform will then check that list and use the first symbol it recognizes.</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f449.png" alt="👉" class="wp-smiley" style="height: 1em; max-height: 1em;" /> The Symbol feature is only supported on Windows when using the WinUI target.</p>



<p><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f449.png" alt="👉" class="wp-smiley" style="height: 1em; max-height: 1em;" /> AllowMulticolorSymbol was added for macOS. When enabled, the OS may render toolbar symbols using multicolor variants where available, instead of enforcing monochrome styling.</p>
</blockquote>



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



<pre class="wp-block-code"><code>home.Symbol = "house.fill;home;go-home"
home.AllowMulticolorSymbol = True
back.Symbol = "chevron.left;back;go-previous"
forward.Symbol = "chevron.right;forward;go-forward"
search.Symbol = "magnifyingglass;find;system-search"</code></pre>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-9d6595d7 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-vertically-aligned-center is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:33.34%"><div class="wp-block-image">
<figure class="aligncenter size-full"><img loading="lazy" decoding="async" width="684" height="542" src="https://blog.xojo.com/wp-content/uploads/2026/06/ToolbarMacOS.png" alt="" class="wp-image-16372" style="aspect-ratio:1.2620603364382037;object-fit:cover" srcset="https://blog.xojo.com/wp-content/uploads/2026/06/ToolbarMacOS.png 684w, https://blog.xojo.com/wp-content/uploads/2026/06/ToolbarMacOS-300x238.png 300w" sizes="auto, (max-width: 684px) 100vw, 684px" /></figure>
</div></div>



<div class="wp-block-column is-vertically-aligned-center is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:33.34%"><div class="wp-block-image">
<figure class="aligncenter size-full"><img loading="lazy" decoding="async" width="822" height="394" src="https://blog.xojo.com/wp-content/uploads/2026/06/ToolbarLinux2-1.png" alt="" class="wp-image-16378" srcset="https://blog.xojo.com/wp-content/uploads/2026/06/ToolbarLinux2-1.png 822w, https://blog.xojo.com/wp-content/uploads/2026/06/ToolbarLinux2-1-300x144.png 300w, https://blog.xojo.com/wp-content/uploads/2026/06/ToolbarLinux2-1-768x368.png 768w" sizes="auto, (max-width: 822px) 100vw, 822px" /></figure>
</div></div>



<div class="wp-block-column is-vertically-aligned-center is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:33.33%"><div class="wp-block-image">
<figure class="aligncenter size-full"><img loading="lazy" decoding="async" width="589" height="296" src="https://blog.xojo.com/wp-content/uploads/2026/06/ToolbarWindows.png" alt="" class="wp-image-16374" srcset="https://blog.xojo.com/wp-content/uploads/2026/06/ToolbarWindows.png 589w, https://blog.xojo.com/wp-content/uploads/2026/06/ToolbarWindows-300x151.png 300w" sizes="auto, (max-width: 589px) 100vw, 589px" /></figure>
</div></div>
</div>



<h3 class="wp-block-heading">How it works</h3>



<p>Instead of relying only on a static icon, the toolbar now attempts to resolve a&nbsp;<em>symbol first</em>. If a symbol is found, it is used in preference to any icon.</p>



<p>The lookup order is:</p>



<ol class="wp-block-list">
<li>First matching symbol in the list</li>



<li>If none resolve, fallback to the standard icon (if one is set)</li>
</ol>



<p>This allows you to provide multiple symbolic names as a fallback chain, improving cross-theme and cross-platform reliability.</p>



<h3 class="wp-block-heading">Where to find the list of supported symbols</h3>



<p>WinUI:&nbsp;<a href="https://learn.microsoft.com/en-us/uwp/api/windows.ui.xaml.controls.symbol" rel="noreferrer noopener" target="_blank">https://learn.microsoft.com/en-us/uwp/api/windows.ui.xaml.controls.symbol</a></p>



<p>Linux:&nbsp;<a href="https://specifications.freedesktop.org/icon-naming" rel="noreferrer noopener" target="_blank">https://specifications.freedesktop.org/icon-naming</a></p>



<p>macOS:&nbsp;<a href="https://developer.apple.com/design/human-interface-guidelines/sf-symbols" rel="noreferrer noopener" target="_blank">https://developer.apple.com/design/human-interface-guidelines/sf-symbols</a></p>



<h2 class="wp-block-heading">Better Control Over Toolbar Layout</h2>



<p>The toolbar itself now supports a new&nbsp;<code>Style</code>&nbsp;property.  This controls how buttons are visually arranged.</p>



<p><strong>DesktopToolbarStyles options</strong>:</p>



<ul class="wp-block-list">
<li><strong>Default</strong>
<ul class="wp-block-list">
<li>Generally icon/symbol on top, caption below</li>



<li>On Linux and WinUI: icon/symbol on left, caption on right</li>
</ul>
</li>



<li><strong>IconCaptionVertical</strong>
<ul class="wp-block-list">
<li>Forces vertical layout (icon/symbol above text)</li>
</ul>
</li>



<li><strong>IconCaptionHorizontal</strong>
<ul class="wp-block-list">
<li>Forces horizontal layout (icon/symbol beside text)</li>



<li>Only supported on Linux and Windows</li>
</ul>
</li>



<li><strong>IconOnly</strong>
<ul class="wp-block-list">
<li>Displays only the icon/symbol</li>
</ul>
</li>



<li><strong>CaptionOnly</strong>
<ul class="wp-block-list">
<li>Displays only text labels</li>
</ul>
</li>
</ul>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-9d6595d7 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-vertically-aligned-center is-layout-flow wp-block-column-is-layout-flow">
<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="676" height="524" src="https://blog.xojo.com/wp-content/uploads/2026/06/ToolbarMacOS_IconOnly.png" alt="" class="wp-image-16385" srcset="https://blog.xojo.com/wp-content/uploads/2026/06/ToolbarMacOS_IconOnly.png 676w, https://blog.xojo.com/wp-content/uploads/2026/06/ToolbarMacOS_IconOnly-300x233.png 300w" sizes="auto, (max-width: 676px) 100vw, 676px" /></figure>
</div>



<div class="wp-block-column is-vertically-aligned-center is-layout-flow wp-block-column-is-layout-flow">
<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="530" height="378" src="https://blog.xojo.com/wp-content/uploads/2026/06/ToolbarLinux_IconOnly.png" alt="" class="wp-image-16386" srcset="https://blog.xojo.com/wp-content/uploads/2026/06/ToolbarLinux_IconOnly.png 530w, https://blog.xojo.com/wp-content/uploads/2026/06/ToolbarLinux_IconOnly-300x214.png 300w" sizes="auto, (max-width: 530px) 100vw, 530px" /></figure>
</div>



<div class="wp-block-column is-vertically-aligned-center is-layout-flow wp-block-column-is-layout-flow">
<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="445" height="258" src="https://blog.xojo.com/wp-content/uploads/2026/06/ToolbarWindows_IconOnly.png" alt="" class="wp-image-16387" srcset="https://blog.xojo.com/wp-content/uploads/2026/06/ToolbarWindows_IconOnly.png 445w, https://blog.xojo.com/wp-content/uploads/2026/06/ToolbarWindows_IconOnly-300x174.png 300w" sizes="auto, (max-width: 445px) 100vw, 445px" /></figure>
</div>
</div>



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



<p>With support for symbols, additional layout styles, and WinUI support on Windows, we&#8217;re making it easier to create toolbars that look more modern, feel more native on each operating system, and adapt better to different user environments. Whether you prefer icon-only toolbars, text labels, or platform-specific symbols, the new options give you more ways to fine-tune the experience for your users without adding extra complexity to your projects.</p>



<p><em><em><em>William Yu grew up in Canada learning to program BASIC on a Vic-20. He is Xojo’s resident Windows and Linux engineer, among his many other skills. Some may say he has joined the dark side here in the USA, but he will always be a Canadian at heart.</em></em></em></p>



<ul class="wp-block-social-links has-normal-icon-size is-content-justification-center is-layout-flex wp-container-core-social-links-is-layout-16018d1d wp-block-social-links-is-layout-flex"><li class="wp-social-link wp-social-link-facebook  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.facebook.com/goxojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M12 2C6.5 2 2 6.5 2 12c0 5 3.7 9.1 8.4 9.9v-7H7.9V12h2.5V9.8c0-2.5 1.5-3.9 3.8-3.9 1.1 0 2.2.2 2.2.2v2.5h-1.3c-1.2 0-1.6.8-1.6 1.6V12h2.8l-.4 2.9h-2.3v7C18.3 21.1 22 17 22 12c0-5.5-4.5-10-10-10z"></path></svg><span class="wp-block-social-link-label screen-reader-text">Facebook</span></a></li>

<li class="wp-social-link wp-social-link-x  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://x.com/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M13.982 10.622 20.54 3h-1.554l-5.693 6.618L8.745 3H3.5l6.876 10.007L3.5 21h1.554l6.012-6.989L15.868 21h5.245l-7.131-10.378Zm-2.128 2.474-.697-.997-5.543-7.93H8l4.474 6.4.697.996 5.815 8.318h-2.387l-4.745-6.787Z" /></svg><span class="wp-block-social-link-label screen-reader-text">X</span></a></li>

<li class="wp-social-link wp-social-link-linkedin  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.linkedin.com/company/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M19.7,3H4.3C3.582,3,3,3.582,3,4.3v15.4C3,20.418,3.582,21,4.3,21h15.4c0.718,0,1.3-0.582,1.3-1.3V4.3 C21,3.582,20.418,3,19.7,3z M8.339,18.338H5.667v-8.59h2.672V18.338z M7.004,8.574c-0.857,0-1.549-0.694-1.549-1.548 c0-0.855,0.691-1.548,1.549-1.548c0.854,0,1.547,0.694,1.547,1.548C8.551,7.881,7.858,8.574,7.004,8.574z M18.339,18.338h-2.669 v-4.177c0-0.996-0.017-2.278-1.387-2.278c-1.389,0-1.601,1.086-1.601,2.206v4.249h-2.667v-8.59h2.559v1.174h0.037 c0.356-0.675,1.227-1.387,2.526-1.387c2.703,0,3.203,1.779,3.203,4.092V18.338z"></path></svg><span class="wp-block-social-link-label screen-reader-text">LinkedIn</span></a></li>

<li class="wp-social-link wp-social-link-github  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://github.com/topics/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M12,2C6.477,2,2,6.477,2,12c0,4.419,2.865,8.166,6.839,9.489c0.5,0.09,0.682-0.218,0.682-0.484 c0-0.236-0.009-0.866-0.014-1.699c-2.782,0.602-3.369-1.34-3.369-1.34c-0.455-1.157-1.11-1.465-1.11-1.465 c-0.909-0.62,0.069-0.608,0.069-0.608c1.004,0.071,1.532,1.03,1.532,1.03c0.891,1.529,2.341,1.089,2.91,0.833 c0.091-0.647,0.349-1.086,0.635-1.337c-2.22-0.251-4.555-1.111-4.555-4.943c0-1.091,0.39-1.984,1.03-2.682 C6.546,8.54,6.202,7.524,6.746,6.148c0,0,0.84-0.269,2.75,1.025C10.295,6.95,11.15,6.84,12,6.836 c0.85,0.004,1.705,0.114,2.504,0.336c1.909-1.294,2.748-1.025,2.748-1.025c0.546,1.376,0.202,2.394,0.1,2.646 c0.64,0.699,1.026,1.591,1.026,2.682c0,3.841-2.337,4.687-4.565,4.935c0.359,0.307,0.679,0.917,0.679,1.852 c0,1.335-0.012,2.415-0.012,2.741c0,0.269,0.18,0.579,0.688,0.481C19.138,20.161,22,16.416,22,12C22,6.477,17.523,2,12,2z"></path></svg><span class="wp-block-social-link-label screen-reader-text">GitHub</span></a></li>

<li class="wp-social-link wp-social-link-youtube  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.youtube.com/c/XojoInc" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M21.8,8.001c0,0-0.195-1.378-0.795-1.985c-0.76-0.797-1.613-0.801-2.004-0.847c-2.799-0.202-6.997-0.202-6.997-0.202 h-0.009c0,0-4.198,0-6.997,0.202C4.608,5.216,3.756,5.22,2.995,6.016C2.395,6.623,2.2,8.001,2.2,8.001S2,9.62,2,11.238v1.517 c0,1.618,0.2,3.237,0.2,3.237s0.195,1.378,0.795,1.985c0.761,0.797,1.76,0.771,2.205,0.855c1.6,0.153,6.8,0.201,6.8,0.201 s4.203-0.006,7.001-0.209c0.391-0.047,1.243-0.051,2.004-0.847c0.6-0.607,0.795-1.985,0.795-1.985s0.2-1.618,0.2-3.237v-1.517 C22,9.62,21.8,8.001,21.8,8.001z M9.935,14.594l-0.001-5.62l5.404,2.82L9.935,14.594z"></path></svg><span class="wp-block-social-link-label screen-reader-text">YouTube</span></a></li></ul>



<p class="has-text-align-center has-text-color has-link-color wp-elements-a0a2ac26ad214a49dac577734d259176" style="color:#84bd00"><a href="https://xojo.com/download/" target="_blank" rel="noreferrer noopener">Download Xojo</a></p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Build a Threaded Find in Files Solution</title>
		<link>https://blog.xojo.com/2026/06/25/build-a-threaded-find-in-files-solution/</link>
		
		<dc:creator><![CDATA[Gabriel Ludosanu]]></dc:creator>
		<pubDate>Thu, 25 Jun 2026 13:00:00 +0000</pubDate>
				<category><![CDATA[Cross-Platform]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[Files]]></category>
		<category><![CDATA[Preemptive Threads]]></category>
		<category><![CDATA[Search]]></category>
		<category><![CDATA[Threads]]></category>
		<guid isPermaLink="false">https://blog.xojo.com/?p=16269</guid>

					<description><![CDATA[In our previous posts, we built a utility to find text inside files within a single folder, and then added recursion to crawl subfolders. But if you&#8230;]]></description>
										<content:encoded><![CDATA[
<p>In our previous posts, we built a utility to <a href="https://blog.xojo.com/2026/04/02/build-a-simple-find-in-files-function/" target="_blank" rel="noreferrer noopener">find text inside files within a single folder</a>, and then <a href="https://blog.xojo.com/2026/05/04/build-a-recursive-find-in-files-function/" target="_blank" rel="noreferrer noopener">added recursion to crawl subfolders</a>. But if you ran that code on a large directory, like your entire Documents folder, you probably noticed two big problems:</p>



<ol class="wp-block-list">
<li>The UI froze completely until the search finished.</li>



<li>If the folder tree was deep enough, you might have hit a&nbsp;<code>StackOverflowException</code>.</li>



<li>We haven&#8217;t actually built a proper UI for it yet!</li>
</ol>



<p>Today, we&#8217;re fixing all three. We&#8217;ll introduce a custom app UI, create a&nbsp;<code>Thread</code>&nbsp;subclass to perform the search in the background, and swap our recursive folder crawl for a flatter, iterative approach to spare our stack memory. We&#8217;ll also add a file size limit to avoid choking on massive unreadable files.</p>



<h2 class="wp-block-heading" id="step-1-designing-the-ui">Step 1: Designing the UI</h2>



<p>First, let&#8217;s build the interface so you have a real application to run. On your main&nbsp;<code>Window1</code>&nbsp;(or whichever Window you are using), we need to add a few controls:</p>



<ul class="wp-block-list">
<li><strong>Path Selection</strong>: Add a&nbsp;<code>DesktopTextField</code>&nbsp;(named&nbsp;<code>fieldPath</code>, set to ReadOnly) to display the chosen folder path, and a&nbsp;<code>DesktopButton</code>&nbsp;(named&nbsp;<code>buttonSelectPath</code>, caption&nbsp;<code>...</code>) next to it to open a&nbsp;<code>SelectFolderDialog</code>.</li>



<li><strong>Search Input</strong>: Add a&nbsp;<code>DesktopSearchField</code>&nbsp;(named&nbsp;<code>fieldSearchTerm</code>) where the user types the text they want to find.</li>



<li><strong>Action Button</strong>: Add a&nbsp;<code>DesktopButton</code>&nbsp;(named&nbsp;<code>buttonSearchThreaded</code>, caption&nbsp;<code>Search Threaded</code>) to start and cancel the search.</li>



<li><strong>Results List</strong>: Add a&nbsp;<code>DesktopListBox</code>&nbsp;(named&nbsp;<code>listResults</code>) and set its Column Count to 3. (Optional: Set the InitialValue of the Column headers to&nbsp;<code>File | Line No. | Context</code>).</li>



<li><strong>Status labels</strong>: Add a&nbsp;<code>DesktopLabel</code>&nbsp;(named&nbsp;<code>labelStatusValue</code>) at the bottom of the window to display the live search progress.</li>
</ul>


<div class="wp-block-image">
<figure class="aligncenter size-full"><img loading="lazy" decoding="async" width="602" height="452" src="https://blog.xojo.com/wp-content/uploads/2026/05/threaded-find-in-files-xojo-solution.png" alt="" class="wp-image-16272" srcset="https://blog.xojo.com/wp-content/uploads/2026/05/threaded-find-in-files-xojo-solution.png 602w, https://blog.xojo.com/wp-content/uploads/2026/05/threaded-find-in-files-xojo-solution-300x225.png 300w" sizes="auto, (max-width: 602px) 100vw, 602px" /></figure>
</div>


<h2 class="wp-block-heading" id="step-2-creating-the-thread-subclass">Step 2: Creating the Thread Subclass</h2>



<p>Threading lets us run our file search simultaneously with the main application, keeping our UI totally responsive.</p>



<p>Instead of writing standard methods, we need to create a dedicated Class.</p>



<ol class="wp-block-list">
<li>Add a&nbsp;<strong>New Class</strong>, in the <code>SearchUtils</code> module and name it&nbsp;<code>FileSearch</code>.</li>



<li>In the Inspector, change its&nbsp;<strong>Super</strong>&nbsp;to&nbsp;<code>Thread</code>.</li>



<li>Add the following Properties to your new class:
<ul class="wp-block-list">
<li><code>MaximumFileSizeMB As Integer = 1</code></li>



<li><code>SearchTerm As String</code></li>



<li><code>TargetFolder As FolderItem</code></li>



<li><code>startTime As Double</code>&nbsp;(Set Scope to Private)</li>
</ul>
</li>
</ol>



<h3 class="wp-block-heading" id="defining-custom-events">Defining Custom Events</h3>



<p>We need our Thread to broadcast events to the Window that&#8217;s holding it. Add these three Event Definitions to your&nbsp;<code>FileSearch</code>&nbsp;class:</p>



<ul class="wp-block-list">
<li><code>Complete(timeElapsed as Double)</code></li>



<li><code>MatchFound(result as SearchUtils.SearchHit)</code></li>



<li><code>StatusUpdate(currentPath as String)</code></li>
</ul>



<h2 class="wp-block-heading" id="step-3-the-iterative-approach-no-recursion">Step 3: The iterative approach</h2>



<p>Recursion is elegant, but crawling a hierarchy thousands of folders deep throws a&nbsp;<code>StackOverflowException</code>. Instead, we flatten the traversal using an array as a queue. We start by adding our root folder&#8217;s children to an array. As we iterate through that array, any folders we find get their children appended to the&nbsp;<em>end</em>&nbsp;of the same array.</p>



<p>Here is exactly how it looks in the Thread&#8217;s&nbsp;<code>Run</code>&nbsp;event. Add the&nbsp;<code>Run</code>&nbsp;event to your&nbsp;<code>FileSearch</code>&nbsp;class and use this exact code and notice the use of&nbsp;<code>AddUserInterfaceUpdate</code>&nbsp;to safely queue UI updates:</p>



<pre class="wp-block-code"><code>Sub Run() Handles Run
  Var maxFileSize As Double = If( Self.MaximumFileSizeMB &lt; 1, 999999999 * 1024 * 1024, Self.MaximumFileSizeMB * 1024 * 1024 )
  
  Var result As Dictionary
  
  Var lastUpdate As Integer = System.Microseconds
  
  If Not (targetFolder Is Nil) And targetFolder.Exists And Not searchTerm.IsEmpty Then
    
    Var child As FolderItem
    Var toSearch() As FolderItem
    For Each child In targetFolder.Children
      toSearch.Add( child )
    Next
    
    Var ti As TextInputStream
    Var line As String
    Var lineNumber As Integer = -1
    
    For index As Integer = 0 To toSearch.LastIndex
      child = toSearch(index)
      
      If System.Microseconds - lastUpdate &gt; 1000000 Then
        result = New Dictionary
        result.Value( "type" ) = "status"
        result.Value( "current" ) = child.NativePath
        AddUserInterfaceUpdate( result )
        lastUpdate = System.Microseconds
      End If
      
      If child.IsFolder Then
        Try
          
          #Pragma BreakOnExceptions False
          
          For Each innerChild As FolderItem In child.Children
            toSearch.Add( innerChild )
          Next
          
          #Pragma BreakOnExceptions Default
          
        Catch e As IOException
          '// Skip inaccessible folders
        End Try
      Else
        If child.Length &lt; maxFileSize Then
          Try
            ti = TextInputStream.Open( child )
            ti.Encoding = Encodings.UTF8
            
            lineNumber = 0
            
            While Not ti.EndOfFile
              lineNumber = lineNumber + 1
              line = ti.ReadLine
              If line.Contains( searchTerm, ComparisonOptions.CaseInsensitive ) Then
                result = New Dictionary
                result.Value( "type" ) = "match"
                result.Value( "path" ) = child.NativePath
                result.Value( "lineNo" ) = lineNumber
                result.Value( "lineText" ) = line
                AddUserInterfaceUpdate( result )
              End If
            Wend
          Catch ioe As IOException
            '// Skip unreadable files
          End Try
        End If
      End If
    Next
  End If
  
  result = New Dictionary( New Pair( "type", "complete" ) )
  AddUserInterfaceUpdate( result )
End Sub</code></pre>



<h2 class="wp-block-heading" id="step-4-feeding-updates-to-the-ui-safely">Step 4: Sending Updates to the UI safely</h2>



<p>In a thread, you&nbsp;<strong>cannot</strong>&nbsp;update UI controls directly. That&#8217;s why we used&nbsp;<code>AddUserInterfaceUpdate</code>&nbsp;above passing a&nbsp;<code>Dictionary</code>&nbsp;of data. This triggers the Thread&#8217;s&nbsp;<code>UserInterfaceUpdate</code>&nbsp;event on the main UI thread.</p>



<p>Add the&nbsp;<code>UserInterfaceUpdate</code>&nbsp;event to your&nbsp;<code>FileSearch</code>&nbsp;class:</p>



<pre class="wp-block-code"><code>Sub UserInterfaceUpdate(data() As Dictionary) Handles UserInterfaceUpdate
  For Each d As Dictionary In data
    Select Case d.Value( "type" )
    Case "match" 
      Var hit As New SearchHit( d.Value( "path" ), d.Value( "lineNo" ), d.Value( "lineText" ) )
      RaiseEvent MatchFound( hit )
    Case "complete"
      RaiseEvent Complete( (System.Microseconds - startTime) / 1000 )
    Case "status"
      RaiseEvent StatusUpdate( d.Value( "current" ) )
    End Select
  Next
End Sub</code></pre>



<p>And finally, add a public method called&nbsp;<code>Search</code>&nbsp;to the class, making sure it executes Preemptively across CPU cores:</p>



<pre class="wp-block-code"><code>Public Sub Search(path As FolderItem, term As String)
  Self.Type = Thread.Types.Preemptive
  
  startTime = System.Microseconds
  
  Self.TargetFolder = path
  Self.SearchTerm = term
  Self.Start
End Sub</code></pre>



<h2 class="wp-block-heading" id="step-5-wiring-the-ui">Step 5: Wiring the UI</h2>



<p>Now, let&#8217;s bring it all together. Select&nbsp;<code>Window1</code>&nbsp;and&nbsp;<strong>simply drag the&nbsp;<code>FileSearch</code>&nbsp;class from your Navigator onto your Window.</strong>&nbsp;It will appear in a shelf at the bottom as&nbsp;<code>FileSearch1</code>&nbsp;(rename it to&nbsp;<code>seeker</code>).</p>



<p>Implement the Event Handlers to your new&nbsp;<code>seeker</code>&nbsp;control:</p>



<p><strong>seeker.Complete:</strong></p>



<pre class="wp-block-code"><code>Sub Complete(timeElapsed As Double) Handles Complete
  buttonSelectPath.Enabled = True
  buttonSearchThreaded.Caption = "Search Threaded"
  fieldSearchTerm.Enabled = True

  Var count As Integer = listResults.LastRowIndex + 1
  Var timeElapsedSeconds As Double = timeElapsed / 1000
  labelStatusValue.Text = "Complete in " + timeElapsedSeconds.ToString( "#0.00" ) + " seconds! " + count.ToString( "#" ) + " results found."
End Sub</code></pre>



<p><strong>seeker.MatchFound:</strong></p>



<pre class="wp-block-code"><code>Sub MatchFound(result As SearchUtils.SearchHit) Handles MatchFound
  listResults.AddRow( result.FilePath, result.LineNumber.ToString( "#" ), result.LineText )
  listResults.RowTagAt( listResults.LastAddedRowIndex ) = result
End Sub</code></pre>



<p><strong>seeker.StatusUpdate:</strong></p>



<pre class="wp-block-code"><code>Sub StatusUpdate(currentPath As String) Handles StatusUpdate
  labelStatusValue.Text = "Searching '" + currentPath + "'"
End Sub</code></pre>



<p id="step-5-wiring-the-ui">And finally, the code in&nbsp;<code>buttonSearchThreaded</code>&nbsp;to kick off the search (and handle nice cancellation):</p>



<pre class="wp-block-code"><code>Sub Pressed() Handles Pressed
  Select Case Me.Caption
  Case "Search Threaded"
    If fieldSearchTerm.Text.Length &gt;= 3 Then
      If seeker.ThreadState = Thread.ThreadStates.NotRunning Then

        listResults.RemoveAllRows

        fieldSearchTerm.Enabled = False
        buttonSelectPath.Enabled = False
        labelStatusValue.Text = "Searching..."

        Me.Caption = "Cancel"

        seeker.Search( Self.path, fieldSearchTerm.Text )

      End If
    End If
  Case "Cancel"
    seeker.Stop
    labelStatusValue.Text = "Cancelled"
  End Select
End Sub</code></pre>



<h2 class="wp-block-heading" id="step-5-wiring-the-ui">Summary</h2>



<p id="step-5-wiring-the-ui">By switching from recursion to a linear queue, we bulletproofed the code against&nbsp;<code>StackOverflowExceptions</code>. By moving the heavy lifting to a preemptive&nbsp;<code>Thread</code>, we completely unlocked the UI, making the app feel incredibly fast and responsive even while chewing through thousands of files. And using&nbsp;<code>AddUserInterfaceUpdate</code>, we safely pipe results directly back to the user without locking up the UI!</p>



<p id="step-5-wiring-the-ui">You can download the project here: <a href="https://blog.xojo.com/wp-content/uploads/2026/05/SearchUtils.FindInFiles.zip">SearchUtils.FindInFiles.zip</a></p>



<h3 class="wp-block-heading" id="step-5-wiring-the-ui">Special Thanks</h3>



<p id="step-5-wiring-the-ui">A huge shoutout and special thanks to Xojo MVP and forum user&nbsp;<strong>Anthony G. Cyphers</strong>. Anthony generously provided the solution to evolve the&nbsp;<code>SearchUtils</code>&nbsp;module into this threaded version, along with the demo app UI.</p>



<p id="step-5-wiring-the-ui"><em>P.S. Got your own spin on this utility? Have ideas for new features or alternative approaches? Jump into the&nbsp;</em><a href="https://forum.xojo.com/c/code-sharing/62" data-type="link" data-id="https://forum.xojo.com/c/code-sharing/62" target="_blank" rel="noreferrer noopener">Xojo Code Sharing Forum</a><em>&nbsp; and share your improvements with the community!</em></p>



<p id="step-5-wiring-the-ui">Happy coding!</p>



<p><em>Gabriel is a digital marketing enthusiast who loves coding with Xojo to create cool software tools for any platform. He is always eager to learn and share new ideas!</em></p>



<ul class="wp-block-social-links has-normal-icon-size is-content-justification-center is-layout-flex wp-container-core-social-links-is-layout-16018d1d wp-block-social-links-is-layout-flex"><li class="wp-social-link wp-social-link-facebook  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.facebook.com/goxojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M12 2C6.5 2 2 6.5 2 12c0 5 3.7 9.1 8.4 9.9v-7H7.9V12h2.5V9.8c0-2.5 1.5-3.9 3.8-3.9 1.1 0 2.2.2 2.2.2v2.5h-1.3c-1.2 0-1.6.8-1.6 1.6V12h2.8l-.4 2.9h-2.3v7C18.3 21.1 22 17 22 12c0-5.5-4.5-10-10-10z"></path></svg><span class="wp-block-social-link-label screen-reader-text">Facebook</span></a></li>

<li class="wp-social-link wp-social-link-x  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://x.com/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M13.982 10.622 20.54 3h-1.554l-5.693 6.618L8.745 3H3.5l6.876 10.007L3.5 21h1.554l6.012-6.989L15.868 21h5.245l-7.131-10.378Zm-2.128 2.474-.697-.997-5.543-7.93H8l4.474 6.4.697.996 5.815 8.318h-2.387l-4.745-6.787Z" /></svg><span class="wp-block-social-link-label screen-reader-text">X</span></a></li>

<li class="wp-social-link wp-social-link-linkedin  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.linkedin.com/company/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M19.7,3H4.3C3.582,3,3,3.582,3,4.3v15.4C3,20.418,3.582,21,4.3,21h15.4c0.718,0,1.3-0.582,1.3-1.3V4.3 C21,3.582,20.418,3,19.7,3z M8.339,18.338H5.667v-8.59h2.672V18.338z M7.004,8.574c-0.857,0-1.549-0.694-1.549-1.548 c0-0.855,0.691-1.548,1.549-1.548c0.854,0,1.547,0.694,1.547,1.548C8.551,7.881,7.858,8.574,7.004,8.574z M18.339,18.338h-2.669 v-4.177c0-0.996-0.017-2.278-1.387-2.278c-1.389,0-1.601,1.086-1.601,2.206v4.249h-2.667v-8.59h2.559v1.174h0.037 c0.356-0.675,1.227-1.387,2.526-1.387c2.703,0,3.203,1.779,3.203,4.092V18.338z"></path></svg><span class="wp-block-social-link-label screen-reader-text">LinkedIn</span></a></li>

<li class="wp-social-link wp-social-link-github  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://github.com/topics/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M12,2C6.477,2,2,6.477,2,12c0,4.419,2.865,8.166,6.839,9.489c0.5,0.09,0.682-0.218,0.682-0.484 c0-0.236-0.009-0.866-0.014-1.699c-2.782,0.602-3.369-1.34-3.369-1.34c-0.455-1.157-1.11-1.465-1.11-1.465 c-0.909-0.62,0.069-0.608,0.069-0.608c1.004,0.071,1.532,1.03,1.532,1.03c0.891,1.529,2.341,1.089,2.91,0.833 c0.091-0.647,0.349-1.086,0.635-1.337c-2.22-0.251-4.555-1.111-4.555-4.943c0-1.091,0.39-1.984,1.03-2.682 C6.546,8.54,6.202,7.524,6.746,6.148c0,0,0.84-0.269,2.75,1.025C10.295,6.95,11.15,6.84,12,6.836 c0.85,0.004,1.705,0.114,2.504,0.336c1.909-1.294,2.748-1.025,2.748-1.025c0.546,1.376,0.202,2.394,0.1,2.646 c0.64,0.699,1.026,1.591,1.026,2.682c0,3.841-2.337,4.687-4.565,4.935c0.359,0.307,0.679,0.917,0.679,1.852 c0,1.335-0.012,2.415-0.012,2.741c0,0.269,0.18,0.579,0.688,0.481C19.138,20.161,22,16.416,22,12C22,6.477,17.523,2,12,2z"></path></svg><span class="wp-block-social-link-label screen-reader-text">GitHub</span></a></li>

<li class="wp-social-link wp-social-link-youtube  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.youtube.com/c/XojoInc" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M21.8,8.001c0,0-0.195-1.378-0.795-1.985c-0.76-0.797-1.613-0.801-2.004-0.847c-2.799-0.202-6.997-0.202-6.997-0.202 h-0.009c0,0-4.198,0-6.997,0.202C4.608,5.216,3.756,5.22,2.995,6.016C2.395,6.623,2.2,8.001,2.2,8.001S2,9.62,2,11.238v1.517 c0,1.618,0.2,3.237,0.2,3.237s0.195,1.378,0.795,1.985c0.761,0.797,1.76,0.771,2.205,0.855c1.6,0.153,6.8,0.201,6.8,0.201 s4.203-0.006,7.001-0.209c0.391-0.047,1.243-0.051,2.004-0.847c0.6-0.607,0.795-1.985,0.795-1.985s0.2-1.618,0.2-3.237v-1.517 C22,9.62,21.8,8.001,21.8,8.001z M9.935,14.594l-0.001-5.62l5.404,2.82L9.935,14.594z"></path></svg><span class="wp-block-social-link-label screen-reader-text">YouTube</span></a></li></ul>



<p class="has-text-align-center has-text-color has-link-color wp-elements-a0a2ac26ad214a49dac577734d259176" style="color:#84bd00"><a href="https://xojo.com/download/" target="_blank" rel="noreferrer noopener">Download Xojo</a></p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Spotlight On: OfficeTime</title>
		<link>https://blog.xojo.com/2026/06/09/spotlight-on-officetime/</link>
		
		<dc:creator><![CDATA[Alyssa Foley]]></dc:creator>
		<pubDate>Tue, 09 Jun 2026 17:53:26 +0000</pubDate>
				<category><![CDATA[Community]]></category>
		<category><![CDATA[Cross-Platform]]></category>
		<category><![CDATA[Desktop]]></category>
		<category><![CDATA[Spotlight On]]></category>
		<guid isPermaLink="false">https://blog.xojo.com/?p=16191</guid>

					<description><![CDATA[Spotlight On posts focus on Xojo community members. We’ll use this space to tell the stories of people using Xojo, share amazing Xojo-made apps and&#8230;]]></description>
										<content:encoded><![CDATA[
<p><em>Spotlight On posts focus on Xojo community members. We’ll use this space to tell the stories of people using Xojo, share amazing Xojo-made apps and spread awareness of community resources. If you have an app, a project or a person you want to see featured in Spotlight On,&nbsp;<a href="mailto:hello@xojo.com" target="_blank" rel="noreferrer noopener">tell us about it</a>!</em></p>



<p>Stephen Dodd has been a Xojo developer since 2001. Over two decades, he’s seen Xojo evolve, and his work embodies the cross‑platform strength Xojo offers users. During his recent Xojo license renewal, he commented &#8220;See the beautiful cross platform app made with it.&#8221; We absolutely love receiving comments like this; they remind us why we do what we do and how our community uses Xojo to create remarkable projects. Immediately I shared Stephen&#8217;s app, <a href="http://www.officetime.net/" target="_blank" rel="noreferrer noopener">OfficeTime</a>, with the team and it didn&#8217;t take long before someone said &#8220;this deserves a Spotlight On!&#8221;. Fortunately, Stephen was kind enough to say yes and answer our questions.</p>



<h3 class="wp-block-heading"><strong>Mac, Windows or Linux?</strong></h3>



<p>Mac + Windows of course. Evaluating Linux demand.</p>



<h3 class="wp-block-heading"><strong>What do you wish more people would ask you about when it comes to your work? Is there an aspect of your work that people often overlook but you wish they were more curious about?</strong></h3>



<p>I&#8217;m passionate about the user experience. The simpler the app, the more time is needed. OfficeTime came about when the staff at the agency I was head of hated tracking their time. Everyday I&#8217;d walk by graffiti someone plastered that said &#8220;Start writing. What&#8217;s stopping you?&#8221; Coding is writing. OfficeTime is successful because I&#8217;m not &#8216;into&#8217; time tracking. I&#8217;m into something that does its job and stays out of your way. </p>



<p>I’m fond of hiding complication until it’s needed. For example, the user can change the rate of an existing category in OfficeTime. That introduces choices for what previously tracked time is affected. We hide all that interface until the user actually starts typing a new rate. Unfortunately for the developer, the simpler you make it, the longer it takes.&nbsp;</p>



<h3 class="wp-block-heading"><strong>What is something that has surprised you about coding in the last 5 years?</strong></h3>



<p>How fricking long implementing full featured, offline first cloud sync takes to get right. Cloud sync is deceptively hard. The majority of our bugs seem to revolve around timing issues of when data / UI is available or not. </p>



<h3 class="wp-block-heading"><strong>Xojo isn’t the only tool in your kit. What is a piece of software more people should know about?</strong></h3>



<ul class="wp-block-list">
<li>OfficeTime to track my time!</li>



<li>TextExpander to hot key in code snippets and customer support replies.</li>



<li>Claude because it just has a more natural, intuitive output than ChatGPT or Gemini.&nbsp;</li>
</ul>



<h3 class="wp-block-heading">Which three Xojo language features or framework capabilities do you find yourself relying/using on the most?</h3>



<p>We hammer that listbox pretty heavily.  It’s core to all the views and reports.</p>



<h3 class="wp-block-heading"><strong>What did you first build with Xojo? And when was that?</strong></h3>



<p>In the 90’s, using Xojo (then called REALbasic), I built a neural network (before AI was cool) to learn to play tic tac toe.</p>



<p>I originally took up Xojo because the O’REILLY book had a cheetah on it which meant it had to be fast. All the Microsoft books had bugs on them. <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f609.png" alt="😉" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>



<h3 class="wp-block-heading"><strong>What do you build with it now?</strong></h3>



<p>OfficeTime is a cross platform app to better track your time so you can bill more or be more accountable for fixed price projects. &nbsp;The Mac/PC side is Xojo with a few custom written controls. It syncs with an iPhone/iPad app that was written in Xcode long before Xojo offered mobile development.</p>



<figure class="wp-block-image size-large is-resized"><img loading="lazy" decoding="async" width="1024" height="774" src="https://blog.xojo.com/wp-content/uploads/2026/04/OfficeTime-Projects-with-budget-1024x774.png" alt="" class="wp-image-16212" style="aspect-ratio:1.3236291306902943;width:644px;height:auto" srcset="https://blog.xojo.com/wp-content/uploads/2026/04/OfficeTime-Projects-with-budget-1024x774.png 1024w, https://blog.xojo.com/wp-content/uploads/2026/04/OfficeTime-Projects-with-budget-300x227.png 300w, https://blog.xojo.com/wp-content/uploads/2026/04/OfficeTime-Projects-with-budget-768x580.png 768w, https://blog.xojo.com/wp-content/uploads/2026/04/OfficeTime-Projects-with-budget.png 1272w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<h3 class="wp-block-heading"><strong>Do you earn a living with Xojo?</strong></h3>



<p>Yes.</p>



<h3 class="wp-block-heading"><strong>What’s your biggest Xojo success?</strong></h3>



<p>OfficeTime</p>



<h3 class="wp-block-heading">If you were introducing Xojo to a friend, which three words would you use to describe it?</h3>



<p>Easy cross platform</p>



<p><em>Thank you to Stephen Dodd for answering questions and sharing his Xojo experience with the community.&nbsp;If you have an app, a project or a person you want to see featured in Spotlight On,&nbsp;<a href="mailto:hello@xojo.com" target="_blank" rel="noreferrer noopener">tell us about it</a>!</em></p>



<ul class="wp-block-social-links has-normal-icon-size is-content-justification-center is-layout-flex wp-container-core-social-links-is-layout-16018d1d wp-block-social-links-is-layout-flex"><li class="wp-social-link wp-social-link-facebook  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.facebook.com/goxojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M12 2C6.5 2 2 6.5 2 12c0 5 3.7 9.1 8.4 9.9v-7H7.9V12h2.5V9.8c0-2.5 1.5-3.9 3.8-3.9 1.1 0 2.2.2 2.2.2v2.5h-1.3c-1.2 0-1.6.8-1.6 1.6V12h2.8l-.4 2.9h-2.3v7C18.3 21.1 22 17 22 12c0-5.5-4.5-10-10-10z"></path></svg><span class="wp-block-social-link-label screen-reader-text">Facebook</span></a></li>

<li class="wp-social-link wp-social-link-x  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://x.com/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M13.982 10.622 20.54 3h-1.554l-5.693 6.618L8.745 3H3.5l6.876 10.007L3.5 21h1.554l6.012-6.989L15.868 21h5.245l-7.131-10.378Zm-2.128 2.474-.697-.997-5.543-7.93H8l4.474 6.4.697.996 5.815 8.318h-2.387l-4.745-6.787Z" /></svg><span class="wp-block-social-link-label screen-reader-text">X</span></a></li>

<li class="wp-social-link wp-social-link-linkedin  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.linkedin.com/company/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M19.7,3H4.3C3.582,3,3,3.582,3,4.3v15.4C3,20.418,3.582,21,4.3,21h15.4c0.718,0,1.3-0.582,1.3-1.3V4.3 C21,3.582,20.418,3,19.7,3z M8.339,18.338H5.667v-8.59h2.672V18.338z M7.004,8.574c-0.857,0-1.549-0.694-1.549-1.548 c0-0.855,0.691-1.548,1.549-1.548c0.854,0,1.547,0.694,1.547,1.548C8.551,7.881,7.858,8.574,7.004,8.574z M18.339,18.338h-2.669 v-4.177c0-0.996-0.017-2.278-1.387-2.278c-1.389,0-1.601,1.086-1.601,2.206v4.249h-2.667v-8.59h2.559v1.174h0.037 c0.356-0.675,1.227-1.387,2.526-1.387c2.703,0,3.203,1.779,3.203,4.092V18.338z"></path></svg><span class="wp-block-social-link-label screen-reader-text">LinkedIn</span></a></li>

<li class="wp-social-link wp-social-link-github  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://github.com/topics/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M12,2C6.477,2,2,6.477,2,12c0,4.419,2.865,8.166,6.839,9.489c0.5,0.09,0.682-0.218,0.682-0.484 c0-0.236-0.009-0.866-0.014-1.699c-2.782,0.602-3.369-1.34-3.369-1.34c-0.455-1.157-1.11-1.465-1.11-1.465 c-0.909-0.62,0.069-0.608,0.069-0.608c1.004,0.071,1.532,1.03,1.532,1.03c0.891,1.529,2.341,1.089,2.91,0.833 c0.091-0.647,0.349-1.086,0.635-1.337c-2.22-0.251-4.555-1.111-4.555-4.943c0-1.091,0.39-1.984,1.03-2.682 C6.546,8.54,6.202,7.524,6.746,6.148c0,0,0.84-0.269,2.75,1.025C10.295,6.95,11.15,6.84,12,6.836 c0.85,0.004,1.705,0.114,2.504,0.336c1.909-1.294,2.748-1.025,2.748-1.025c0.546,1.376,0.202,2.394,0.1,2.646 c0.64,0.699,1.026,1.591,1.026,2.682c0,3.841-2.337,4.687-4.565,4.935c0.359,0.307,0.679,0.917,0.679,1.852 c0,1.335-0.012,2.415-0.012,2.741c0,0.269,0.18,0.579,0.688,0.481C19.138,20.161,22,16.416,22,12C22,6.477,17.523,2,12,2z"></path></svg><span class="wp-block-social-link-label screen-reader-text">GitHub</span></a></li>

<li class="wp-social-link wp-social-link-youtube  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.youtube.com/c/XojoInc" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M21.8,8.001c0,0-0.195-1.378-0.795-1.985c-0.76-0.797-1.613-0.801-2.004-0.847c-2.799-0.202-6.997-0.202-6.997-0.202 h-0.009c0,0-4.198,0-6.997,0.202C4.608,5.216,3.756,5.22,2.995,6.016C2.395,6.623,2.2,8.001,2.2,8.001S2,9.62,2,11.238v1.517 c0,1.618,0.2,3.237,0.2,3.237s0.195,1.378,0.795,1.985c0.761,0.797,1.76,0.771,2.205,0.855c1.6,0.153,6.8,0.201,6.8,0.201 s4.203-0.006,7.001-0.209c0.391-0.047,1.243-0.051,2.004-0.847c0.6-0.607,0.795-1.985,0.795-1.985s0.2-1.618,0.2-3.237v-1.517 C22,9.62,21.8,8.001,21.8,8.001z M9.935,14.594l-0.001-5.62l5.404,2.82L9.935,14.594z"></path></svg><span class="wp-block-social-link-label screen-reader-text">YouTube</span></a></li></ul>



<p class="has-text-align-center has-text-color has-link-color wp-elements-a0a2ac26ad214a49dac577734d259176" style="color:#84bd00"><a href="https://xojo.com/download/" target="_blank" rel="noreferrer noopener">Download Xojo</a></p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>FAQ: iOS Development with Xojo</title>
		<link>https://blog.xojo.com/2026/05/08/faq-ios-development-with-xojo/</link>
		
		<dc:creator><![CDATA[Javier Menendez]]></dc:creator>
		<pubDate>Fri, 08 May 2026 13:15:00 +0000</pubDate>
				<category><![CDATA[iOS]]></category>
		<category><![CDATA[Learning]]></category>
		<category><![CDATA[Mobile]]></category>
		<category><![CDATA[Tips]]></category>
		<category><![CDATA[App Store]]></category>
		<category><![CDATA[Apple Developer Account]]></category>
		<category><![CDATA[Beginner Tips]]></category>
		<category><![CDATA[Xcode]]></category>
		<guid isPermaLink="false">https://blog.xojo.com/?p=16238</guid>

					<description><![CDATA[In recent weeks I received several questions regarding Xojo iOS, many from users who already use Xojo for desktop or web development and want to&#8230;]]></description>
										<content:encoded><![CDATA[
<p>In recent weeks I received several questions regarding Xojo iOS, many from users who already use Xojo for desktop or web development and want to start using Xojo for mobile, particularly iOS, development. I&#8217;ve compiled some of their questions together with some other tips into this mini-FAQ.</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>I&#8217;ll update this FAQ from time to time, so you may want to bookmark it and revisit! In addition, the <a href="https://forum.xojo.com/c/targets/ios/37" target="_blank" rel="noreferrer noopener">Xojo Forum</a> is a great place to keep the conversation about this and other iOS Xojo-related topics!</p>
</blockquote>



<span id="more-16238"></span>



<h2 class="wp-block-heading">Can I develop iOS apps on Windows?</h2>



<p>No. Running, testing, or debugging an iOS project in Xojo requires the iOS Simulator which is provided only with Apple&#8217;s Xcode and is only available on macOS. We advise using ARM processor based Macs that are updated to the latest version of macOS. You can review the <a href="https://documentation.xojo.com/resources/system_requirements_for_current_release.html#ios-apps" target="_blank" rel="noreferrer noopener">system requirements</a> for building iOS apps with the latest Xojo release.</p>



<h2 class="wp-block-heading">Do I need to install anything besides Xojo?</h2>



<p>In addition to Xojo, you&#8217;ll need to install <a href="https://xcodereleases.com" target="_blank" rel="noreferrer noopener">Xcode</a> and run it at least once in order to accept to the provided agreements and to get logged-in into your developer account from the Xcode preferences (mostly in order to install the Developer Certificates).</p>



<p>Make sure there is, at least, an iOS SDK installed &#8211; it should already be there because it is done automatically during Xcode&#8217;s first installation (and subsequent Xcode updates).</p>


<div class="wp-block-image">
<figure class="aligncenter"><img loading="lazy" decoding="async" width="833" height="1024" src="https://blog.xojo.com/wp-content/uploads/2026/05/Screenshot-2026-05-05-at-13.16.37-833x1024.png" alt="" class="wp-image-16240" srcset="https://blog.xojo.com/wp-content/uploads/2026/05/Screenshot-2026-05-05-at-13.16.37-833x1024.png 833w, https://blog.xojo.com/wp-content/uploads/2026/05/Screenshot-2026-05-05-at-13.16.37-244x300.png 244w, https://blog.xojo.com/wp-content/uploads/2026/05/Screenshot-2026-05-05-at-13.16.37-768x944.png 768w, https://blog.xojo.com/wp-content/uploads/2026/05/Screenshot-2026-05-05-at-13.16.37.png 1224w" sizes="auto, (max-width: 833px) 100vw, 833px" /></figure>
</div>


<p>In addition, if needed, you can download additional iOS SDKs from Xcode &gt; Preferences &gt; Components.</p>


<div class="wp-block-image">
<figure class="aligncenter"><img loading="lazy" decoding="async" width="1024" height="703" src="https://blog.xojo.com/wp-content/uploads/2026/05/Screenshot-2026-05-05-at-13.32.56-1024x703.png" alt="" class="wp-image-16239" srcset="https://blog.xojo.com/wp-content/uploads/2026/05/Screenshot-2026-05-05-at-13.32.56-1024x703.png 1024w, https://blog.xojo.com/wp-content/uploads/2026/05/Screenshot-2026-05-05-at-13.32.56-300x206.png 300w, https://blog.xojo.com/wp-content/uploads/2026/05/Screenshot-2026-05-05-at-13.32.56-768x527.png 768w, https://blog.xojo.com/wp-content/uploads/2026/05/Screenshot-2026-05-05-at-13.32.56-1536x1054.png 1536w, https://blog.xojo.com/wp-content/uploads/2026/05/Screenshot-2026-05-05-at-13.32.56.png 1644w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>
</div>


<p>Also, make sure that the Xcode CLI tools are installed, because Xojo needs these in order to create the package during the build process. You can set these under Xcode &gt; Preferences &gt; Locations.</p>


<div class="wp-block-image">
<figure class="aligncenter"><img loading="lazy" decoding="async" width="1024" height="703" src="https://blog.xojo.com/wp-content/uploads/2026/05/Screenshot-2026-05-05-at-13.19.10-1024x703.png" alt="" class="wp-image-16241" srcset="https://blog.xojo.com/wp-content/uploads/2026/05/Screenshot-2026-05-05-at-13.19.10-1024x703.png 1024w, https://blog.xojo.com/wp-content/uploads/2026/05/Screenshot-2026-05-05-at-13.19.10-300x206.png 300w, https://blog.xojo.com/wp-content/uploads/2026/05/Screenshot-2026-05-05-at-13.19.10-768x527.png 768w, https://blog.xojo.com/wp-content/uploads/2026/05/Screenshot-2026-05-05-at-13.19.10-1536x1054.png 1536w, https://blog.xojo.com/wp-content/uploads/2026/05/Screenshot-2026-05-05-at-13.19.10.png 1644w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>
</div>


<h2 class="wp-block-heading">Why are the Run and Build buttons disabled for my iOS projects in Xojo?</h2>



<p>There could be a few reasons for this. </p>



<ul class="wp-block-list">
<li>Check that the CLI tools are selected in Xcode. See previous point.</li>



<li>Launch Xcode to make sure you have agreed to the license agreement and that there are no Xcode issues that jump out.</li>



<li>Are you signed into the Xojo IDE with the account that holds your Xojo Mobile license? Open the license key window in the Xojo app and verify your license is there. If not, sign in to the IDE to automatically add your license. Check <a href="https://documentation.xojo.com/getting_started/introduction/activating_your_xojo_license_and_building_apps.html#troubleshooting">Troubleshooting</a> tips for licenses.</li>
</ul>



<h2 class="wp-block-heading">I don&#8217;t see a Simulator under Xojo Project &gt; Run On menu… what can I do about that?</h2>



<p>Quit Xojo and re-open it. You should now see the same Simulators installed on Xcode under that Xojo submenu.</p>



<h2 class="wp-block-heading">Do I need to keep Xcode open while using Xojo?</h2>



<p>No. That is not necessary at all!</p>



<h2 class="wp-block-heading">Everything was working fine… but now I can&#8217;t run or build iOS apps. Why?</h2>



<p>It&#8217;s likely there is a new agreement you need to accept from Apple. Go to the <a href="https://appstoreconnect.apple.com/login">Apple Developer Portal log-in</a> using your developer credentials and check if there are new or updated agreements.</p>



<p>Another thing to check for are expired provisioning profiles or missing or expired Developer Certificates. If so, you need to create new ones.</p>



<p>And of course make sure your Xojo license is listed in the license key window. Are you signed into the Xojo IDE with the account that holds your Xojo Mobile license? Open the license key window in the Xojo app and verify your license is there. If not, sign in to the IDE to automatically add your license. Check <a href="https://documentation.xojo.com/getting_started/introduction/activating_your_xojo_license_and_building_apps.html#troubleshooting">Troubleshooting</a> tips for licenses.</p>



<h2 class="wp-block-heading">Can I use Xojo iOS if I have a free Apple Developer Account?</h2>



<p>In short: yes. Free Apple Developer Accounts are those you can create using an Apple Account. That is, the same you use in order to access other Apple services. But, even if it is possible to use a free developer account, these have some limitations compared with the paid Apple Developer account. The following table summarizes these:</p>



<figure class="wp-block-table tg"><table class="has-fixed-layout"><thead><tr><th>&nbsp;</th><th><span style="font-weight: bold; font-style: normal;">Apple Account</span></th><th><span style="font-weight: bold; font-style: normal;">Apple Developer Program</span></th></tr></thead><tbody><tr><td><span style="font-weight: normal; font-style: normal;">Xcode developer tools</span></td><td><span style="font-weight: normal; font-style: normal;">●</span></td><td>●</td></tr><tr><td><span style="font-weight: normal; font-style: normal;">Xcode beta releases</span></td><td>●</td><td>●</td></tr><tr><td><span style="font-weight: normal; font-style: normal;">On-device testing</span></td><td>●</td><td>●</td></tr><tr><td><span style="font-weight: normal; font-style: normal;">Advanced app capabilities and services</span></td><td>&nbsp;</td><td>●</td></tr><tr><td><span style="font-weight: normal; font-style: normal;">App distribution</span></td><td>&nbsp;</td><td>●</td></tr><tr><td><span style="font-weight: normal; font-style: normal;">Ad hoc distribution for testing and internal use</span></td><td>&nbsp;</td><td>●</td></tr></tbody></table></figure>



<p>In addition, you need to also consider the following limitations:</p>



<ul class="wp-block-list">
<li>The number of App IDs that can be registered is limited to 10 and each expires after 7 days.</li>



<li>The number of test devices that can be registered to the account is limited to 3, and each expires after 7 days.</li>



<li>Provisioning profiles will expire 7 days from issuance, which may require you to rebuild and re-install your app to your device after expiration.</li>
</ul>



<p>There are some free tools you can use to skip these limitations, but they are not officially supported, for example <a href="https://sideloadly.io/index.html" target="_blank" rel="noreferrer noopener">Sideloadly</a> (in fact this one can be used even on Windows).</p>



<h2 class="wp-block-heading">I have a free Apple Developer account and I followed all the previous steps and I still can&#8217;t run my app from Xojo.</h2>



<p>In order for an iOS app to run it requires a provisioning profile. These can be created from the Apple Developer website or you can let Xcode handle them. If you don&#8217;t have a lot of experience with iOS development (or Apple platforms development in general), then the easiest way forward is to use the following steps which allow Xcode to create the provisioning profile for your specific app. These steps are for the most basic provisioning profile; one that doesn&#8217;t include the use of any of specific Apple services or technologies that require being included in such provisioning profile:</p>


<div class="wp-block-image">
<figure class="aligncenter"><img loading="lazy" decoding="async" width="1024" height="556" src="https://blog.xojo.com/wp-content/uploads/2026/05/ManagedProvisionProfile-1024x556.png" alt="" class="wp-image-16245" srcset="https://blog.xojo.com/wp-content/uploads/2026/05/ManagedProvisionProfile-1024x556.png 1024w, https://blog.xojo.com/wp-content/uploads/2026/05/ManagedProvisionProfile-300x163.png 300w, https://blog.xojo.com/wp-content/uploads/2026/05/ManagedProvisionProfile-768x417.png 768w, https://blog.xojo.com/wp-content/uploads/2026/05/ManagedProvisionProfile-1536x834.png 1536w, https://blog.xojo.com/wp-content/uploads/2026/05/ManagedProvisionProfile.png 2012w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>
</div>


<ol class="wp-block-list">
<li>Open Xcode and create a new iOS project.</li>



<li>Give the project the same Bundle Identifier as the one you are going to use in your Xojo project.</li>



<li>In the main area of the Xcode window, select the item for the project root (A).</li>



<li>Then, select the target item from the Targets section (B).</li>



<li>Next, select the Signing &amp; Capabilities tab. Make sure your Team is selected and the Bundle Identifier is the same one you are using for your Xojo app (C).</li>



<li>As result of the selections made, you will see the area corresponding to the (Xcode managed) provisioning profile that is going to be created.</li>



<li>Make sure a Simulator is selected and then run the App from Xcode. That action will open the selected Simulator and will run the blank app into it.</li>



<li>Because a provisioning profile has already been created, go back to Xojo and you will be able to run your Xojo app. If that is not the case, quit Xojo and reopen it so the IDE can find the just generated provisioning profile from Xcode.</li>
</ol>



<h2 class="wp-block-heading">Are there other ways to install my iOS apps to my registered devices without going through the App Store?</h2>



<p>Yes. You can install built iOS apps on the devices previously registered in your developer account through what is called <em>sideloading</em> using Xcode.</p>



<p>Once the app has been built using Xojo (it creates a package &#8211; IPA file), go to Xcode &gt; Devices and Simulator, select the device and drop the package onto the area showing the apps installed on that device. That action will initiate the copy (installation) of your iOS app on that specific device.</p>



<p>Take into consideration that this kind of installation allows the app to run for one year; that is, the timespan the provisioning profile lasts for that particular app. Once the provisioning profile expires, you will need to repeat the process: build the app with a new provisioning profile, and copy it again into the device.</p>



<h2 class="wp-block-heading">Is it possible to distribute Xojo-created iOS Apps through the App Store?</h2>



<p>Of course! In fact <a href="https://blog.xojo.com/2025/03/25/how-to-publish-macos-and-ios-apps-to-the-app-store-directly-from-xojo/" target="_blank" rel="noreferrer noopener">the Xojo IDE greatly simplifies the process</a> of building and uploading directly your iOS apps to the App Store Connect portal, both for starting the required Apple review process previous for the app being available through the App Store, or if you simply want to distribute your betas to your beta-testers using Testflight.</p>



<p>In order to distribute iOS apps through the App Store you will need a paid Apple Developer membership.</p>



<h2 class="wp-block-heading">Helpful Resources</h2>



<p>As always, Xojo provides resources for free, no license needed to access our user forum, documentation, videos and other resources. </p>



<ul class="wp-block-list">
<li>Xojo iOS <a href="https://documentation.xojo.com/getting_started/quickstarts/ios_quickstart.html#" target="_blank" rel="noreferrer noopener">Quickstart</a></li>



<li>Xojo iOS <a href="https://documentation.xojo.com/getting_started/tutorials/ios_tutorial.html" target="_blank" rel="noreferrer noopener">Tutorial</a></li>



<li><a href="https://blog.xojo.com/2025/03/25/how-to-publish-macos-and-ios-apps-to-the-app-store-directly-from-xojo/" target="_blank" rel="noreferrer noopener">How to Publish macOS and iOS Apps to the App Store Directly from Xojo</a></li>



<li><a href="https://documentation.xojo.com/topics/android/android_ios_diffs.html" target="_blank" rel="noreferrer noopener">Differences between iOS and Android</a></li>



<li><a href="https://documentation.xojo.com/topics/ios/getting_the_user%27s_location_from_their_mobile_device.html" target="_blank" rel="noreferrer noopener">Getting the user&#8217;s location from their mobile device</a></li>



<li><a href="https://documentation.xojo.com/topics/ios/how_to_apply_a_blur_effect_on_ios.html" target="_blank" rel="noreferrer noopener">How to apply a blur effect on iOS</a></li>



<li><a href="https://documentation.xojo.com/topics/ios/sending_and_receiving_mobile_notifications.html" target="_blank" rel="noreferrer noopener">Sending and receiving mobile notifications</a></li>



<li><a href="https://documentation.xojo.com/topics/ios/loading_third_party_frameworks_in_xojo_ios.html" target="_blank" rel="noreferrer noopener">Loading 3rd Party Frameworks in Xojo iOS</a></li>



<li><a href="https://blog.xojo.com/category/cross-platform/ios/" target="_blank" rel="noreferrer noopener">iOS related posts on the Xojo Blog</a></li>
</ul>



<p><em>Javier Menendez is an engineer at Xojo and has been using Xojo since 1998. He lives in Castellón</em>, <em>Spain and hosts regular Xojo hangouts en español. Ask Javier questions on Twitter at <a href="https://twitter.com/xojoes" target="_blank" rel="noreferrer noopener">@XojoES</a> or on the <a href="https://forum.xojo.com/u/javier_menendez/summary" target="_blank" rel="noreferrer noopener">Xojo Forum</a>.</em></p>



<ul class="wp-block-social-links has-normal-icon-size is-content-justification-center is-layout-flex wp-container-core-social-links-is-layout-16018d1d wp-block-social-links-is-layout-flex"><li class="wp-social-link wp-social-link-facebook  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.facebook.com/goxojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M12 2C6.5 2 2 6.5 2 12c0 5 3.7 9.1 8.4 9.9v-7H7.9V12h2.5V9.8c0-2.5 1.5-3.9 3.8-3.9 1.1 0 2.2.2 2.2.2v2.5h-1.3c-1.2 0-1.6.8-1.6 1.6V12h2.8l-.4 2.9h-2.3v7C18.3 21.1 22 17 22 12c0-5.5-4.5-10-10-10z"></path></svg><span class="wp-block-social-link-label screen-reader-text">Facebook</span></a></li>

<li class="wp-social-link wp-social-link-x  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://x.com/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M13.982 10.622 20.54 3h-1.554l-5.693 6.618L8.745 3H3.5l6.876 10.007L3.5 21h1.554l6.012-6.989L15.868 21h5.245l-7.131-10.378Zm-2.128 2.474-.697-.997-5.543-7.93H8l4.474 6.4.697.996 5.815 8.318h-2.387l-4.745-6.787Z" /></svg><span class="wp-block-social-link-label screen-reader-text">X</span></a></li>

<li class="wp-social-link wp-social-link-linkedin  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.linkedin.com/company/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M19.7,3H4.3C3.582,3,3,3.582,3,4.3v15.4C3,20.418,3.582,21,4.3,21h15.4c0.718,0,1.3-0.582,1.3-1.3V4.3 C21,3.582,20.418,3,19.7,3z M8.339,18.338H5.667v-8.59h2.672V18.338z M7.004,8.574c-0.857,0-1.549-0.694-1.549-1.548 c0-0.855,0.691-1.548,1.549-1.548c0.854,0,1.547,0.694,1.547,1.548C8.551,7.881,7.858,8.574,7.004,8.574z M18.339,18.338h-2.669 v-4.177c0-0.996-0.017-2.278-1.387-2.278c-1.389,0-1.601,1.086-1.601,2.206v4.249h-2.667v-8.59h2.559v1.174h0.037 c0.356-0.675,1.227-1.387,2.526-1.387c2.703,0,3.203,1.779,3.203,4.092V18.338z"></path></svg><span class="wp-block-social-link-label screen-reader-text">LinkedIn</span></a></li>

<li class="wp-social-link wp-social-link-github  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://github.com/topics/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M12,2C6.477,2,2,6.477,2,12c0,4.419,2.865,8.166,6.839,9.489c0.5,0.09,0.682-0.218,0.682-0.484 c0-0.236-0.009-0.866-0.014-1.699c-2.782,0.602-3.369-1.34-3.369-1.34c-0.455-1.157-1.11-1.465-1.11-1.465 c-0.909-0.62,0.069-0.608,0.069-0.608c1.004,0.071,1.532,1.03,1.532,1.03c0.891,1.529,2.341,1.089,2.91,0.833 c0.091-0.647,0.349-1.086,0.635-1.337c-2.22-0.251-4.555-1.111-4.555-4.943c0-1.091,0.39-1.984,1.03-2.682 C6.546,8.54,6.202,7.524,6.746,6.148c0,0,0.84-0.269,2.75,1.025C10.295,6.95,11.15,6.84,12,6.836 c0.85,0.004,1.705,0.114,2.504,0.336c1.909-1.294,2.748-1.025,2.748-1.025c0.546,1.376,0.202,2.394,0.1,2.646 c0.64,0.699,1.026,1.591,1.026,2.682c0,3.841-2.337,4.687-4.565,4.935c0.359,0.307,0.679,0.917,0.679,1.852 c0,1.335-0.012,2.415-0.012,2.741c0,0.269,0.18,0.579,0.688,0.481C19.138,20.161,22,16.416,22,12C22,6.477,17.523,2,12,2z"></path></svg><span class="wp-block-social-link-label screen-reader-text">GitHub</span></a></li>

<li class="wp-social-link wp-social-link-youtube  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.youtube.com/c/XojoInc" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M21.8,8.001c0,0-0.195-1.378-0.795-1.985c-0.76-0.797-1.613-0.801-2.004-0.847c-2.799-0.202-6.997-0.202-6.997-0.202 h-0.009c0,0-4.198,0-6.997,0.202C4.608,5.216,3.756,5.22,2.995,6.016C2.395,6.623,2.2,8.001,2.2,8.001S2,9.62,2,11.238v1.517 c0,1.618,0.2,3.237,0.2,3.237s0.195,1.378,0.795,1.985c0.761,0.797,1.76,0.771,2.205,0.855c1.6,0.153,6.8,0.201,6.8,0.201 s4.203-0.006,7.001-0.209c0.391-0.047,1.243-0.051,2.004-0.847c0.6-0.607,0.795-1.985,0.795-1.985s0.2-1.618,0.2-3.237v-1.517 C22,9.62,21.8,8.001,21.8,8.001z M9.935,14.594l-0.001-5.62l5.404,2.82L9.935,14.594z"></path></svg><span class="wp-block-social-link-label screen-reader-text">YouTube</span></a></li></ul>



<p class="has-text-align-center has-text-color has-link-color wp-elements-a0a2ac26ad214a49dac577734d259176" style="color:#84bd00"><a href="https://xojo.com/download/" target="_blank" rel="noreferrer noopener">Download Xojo</a></p>



<p></p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Guide to Constructing and Reading JSON</title>
		<link>https://blog.xojo.com/2026/05/06/guide-to-constructing-and-reading-json/</link>
		
		<dc:creator><![CDATA[Gabriel Ludosanu]]></dc:creator>
		<pubDate>Wed, 06 May 2026 15:55:00 +0000</pubDate>
				<category><![CDATA[Cross-Platform]]></category>
		<category><![CDATA[Data Structures]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[Arrays]]></category>
		<category><![CDATA[JSON]]></category>
		<category><![CDATA[JSONItem]]></category>
		<category><![CDATA[Lookup]]></category>
		<guid isPermaLink="false">https://blog.xojo.com/?p=16235</guid>

					<description><![CDATA[JSONItem is the native class for dealing with JSON. Depending on how you use it, it treats your data as either a standard dictionary (key-value pairs)&#8230;]]></description>
										<content:encoded><![CDATA[
<p><code>JSONItem</code> is the native class for dealing with JSON. Depending on how you use it, it treats your data as either a standard dictionary (key-value pairs) or a zero-indexed array.</p>



<h2 class="wp-block-heading" id="part-1-building-json">Part 1: Building JSON</h2>



<p>Building JSON from scratch means firing up a new&nbsp;<code>JSONItem</code>&nbsp;and throwing data at it. Don’t build JSON by stitching strings together. It breaks easily, you&#8217;ll mess up the escaping, and&nbsp;<code>JSONItem</code>&nbsp;makes it completely unnecessary.</p>



<h3 class="wp-block-heading" id="the-basic-payload">The Basic Payload</h3>



<p>When you just need to fire a flat object at a web service:</p>



<pre class="wp-block-code"><code>Var apiPayload As New JSONItem
apiPayload.Value("endpoint") = "/users/create"
apiPayload.Value("timestamp") = 1715423000
apiPayload.Value("forceSync") = True

// Get the string back
Var jsonString As String = apiPayload.ToString
// {"endpoint":"/users/create","timestamp":1715423000,"forceSync":true}</code></pre>



<h3 class="wp-block-heading" id="making-arrays">Making Arrays</h3>



<p>If you&#8217;re making a list of tags or IDs, use the <code>.Add</code> method. The moment you call <code>.Add</code>, Xojo treats that <code>JSONItem</code> as a JSON array under the hood.</p>



<pre class="wp-block-code"><code>Var tags As New JSONItem
tags.Add("xojo")
tags.Add("desktop")
tags.Add("api")

Var jsonString As String = tags.ToString
// &#91;"xojo","desktop","api"]</code></pre>



<h3 class="wp-block-heading" id="nesting-things">Nesting Things</h3>



<p>Most APIs want nested payloads. You map this out by making separate&nbsp;<code>JSONItem</code>&nbsp;objects and attaching them to each other.</p>



<pre class="wp-block-code"><code>Var payload As New JSONItem
payload.Value("status") = "active"

Var user As New JSONItem
user.Value("id") = 982
user.Value("username") = "johndoe"

Var roles As New JSONItem
roles.Add("admin")
roles.Add("editor")

user.Value("roles") = roles // Attach the array to the user object
payload.Value("data") = user // Attach the user object to the main payload

Var jsonString As String = payload.ToString
// {"status":"active","data":{"id":982,"username":"johndoe","roles":&#91;"admin","editor"]}}</code></pre>



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



<h2 class="wp-block-heading" id="part-2-parsing-json">Part 2: Parsing JSON</h2>



<p>To go the other direction, pass a raw JSON string straight into the constructor.</p>



<h3 class="wp-block-heading" id="reading-a-flat-response">Reading a Flat Response</h3>



<p>When a server hands you back a flat config or auth token, just pull the values right out.</p>



<pre class="wp-block-code"><code>Var rawJSON As String = "{""token"":""abc123xyz"",""expiresIn"":3600,""active"":true}"
Var response As New JSONItem(rawJSON)

Var token As String = response.Value("token")
Var expiresIn As Integer = response.Value("expiresIn")
Var isActive As Boolean = response.Value("active")</code></pre>



<h3 class="wp-block-heading" id="handling-optional-keys-with-lookup">Handling Optional Keys with Lookup</h3>



<p>If you use&nbsp;<code>.Value("key")</code>&nbsp;and the key isn&#8217;t in the JSON, Xojo throws a&nbsp;<code>KeyNotFoundException</code>. Instead of writing boilerplate&nbsp;<code>If response.HasKey("key") Then</code>&nbsp;checks everywhere, use&nbsp;<code>.Lookup()</code>. It lets you define a fallback value in line.</p>



<pre class="wp-block-code"><code>Var rawJSON As String = "{""username"":""johndoe""}"
Var response As New JSONItem(rawJSON)

// Returns "johndoe" because the key is present
Var user As String = response.Lookup("username", "anonymous") 

// Returns False because "forceSync" is missing from the JSON
Var isSyncForced As Boolean = response.Lookup("forceSync", False) </code></pre>



<h3 class="wp-block-heading" id="looping-over-an-array">Looping Over an Array</h3>



<p>If an API hands you a list of database records:</p>



<pre class="wp-block-code"><code>Var rawJSON As String = "&#91;{""id"":1, ""name"":""Alice""}, {""id"":2, ""name"":""Bob""}]"
Var userList As New JSONItem(rawJSON)

For i As Integer = 0 To userList.Count - 1
  Var currentUser As JSONItem = userList.ValueAt(i)

  Var id As Integer = currentUser.Value("id")
  Var name As String = currentUser.Value("name")

  System.DebugLog(id.ToString + ": " + name)
Next</code></pre>



<h3 class="wp-block-heading" id="digging-out-nested-nodes">Digging out Nested Nodes</h3>



<p>This is where&nbsp;<code>.Child()</code>&nbsp;comes in handy. While&nbsp;<code>.Value()</code>&nbsp;returns a generic&nbsp;<code>Variant</code>&nbsp;(which you can&#8217;t chain directly),&nbsp;<code>.Child("key")</code>&nbsp;explicitly returns the nested object as a&nbsp;<code>JSONItem</code>. This allows for perfectly clean chaining.</p>



<pre class="wp-block-code"><code>Var rawJSON As String = "{""weather"":{""current"":{""temp"":22, ""condition"":""Sunny""}}}"
Var forecast As New JSONItem(rawJSON)

// Use .Child() to tunnel down into objects, then .Value() to pull the final primitive data 
Var temperature As Double = forecast.Child("weather").Child("current").Value("temp")
Var condition As String = forecast.Child("weather").Child("current").Value("condition")</code></pre>



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



<h2 class="wp-block-heading" id="part-3-identifying-the-structure">Part 3: Identifying the Structure</h2>



<p>APIs are notoriously inconsistent. Check the&nbsp;<code>.IsArray</code>&nbsp;property to figure out what structure you&#8217;re dealing with before parsing it, so your loops don&#8217;t crash when passing something unexpected.</p>



<pre class="wp-block-code"><code>Var rawJSON As String = "&#91;""apple"", ""banana"", ""orange""]"
Var parsedData As New JSONItem(rawJSON)

If parsedData.IsArray Then
  System.DebugLog("Looks like an array with " + parsedData.Count.ToString + " items.")

  For i As Integer = 0 To parsedData.Count - 1
    System.DebugLog(parsedData.ValueAt(i).StringValue)
  Next
Else
  System.DebugLog("It's a standard dictionary.")
  If parsedData.HasKey("data") Then
    System.DebugLog(parsedData.Value("data").StringValue)
  End If
End If</code></pre>



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



<p>That&#8217;s it. For more info on JSONItem, don&#8217;t forget to check the online documentation at: <a href="https://documentation.xojo.com/api/text/json/jsonitem.html" target="_blank" rel="noreferrer noopener">https://documentation.xojo.com/api/text/json/jsonitem.html</a></p>



<p><em>Gabriel is a digital marketing enthusiast who loves coding with Xojo to create cool software tools for any platform. He is always eager to learn and share new ideas!</em></p>



<ul class="wp-block-social-links has-normal-icon-size is-content-justification-center is-layout-flex wp-container-core-social-links-is-layout-16018d1d wp-block-social-links-is-layout-flex"><li class="wp-social-link wp-social-link-facebook  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.facebook.com/goxojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M12 2C6.5 2 2 6.5 2 12c0 5 3.7 9.1 8.4 9.9v-7H7.9V12h2.5V9.8c0-2.5 1.5-3.9 3.8-3.9 1.1 0 2.2.2 2.2.2v2.5h-1.3c-1.2 0-1.6.8-1.6 1.6V12h2.8l-.4 2.9h-2.3v7C18.3 21.1 22 17 22 12c0-5.5-4.5-10-10-10z"></path></svg><span class="wp-block-social-link-label screen-reader-text">Facebook</span></a></li>

<li class="wp-social-link wp-social-link-x  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://x.com/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M13.982 10.622 20.54 3h-1.554l-5.693 6.618L8.745 3H3.5l6.876 10.007L3.5 21h1.554l6.012-6.989L15.868 21h5.245l-7.131-10.378Zm-2.128 2.474-.697-.997-5.543-7.93H8l4.474 6.4.697.996 5.815 8.318h-2.387l-4.745-6.787Z" /></svg><span class="wp-block-social-link-label screen-reader-text">X</span></a></li>

<li class="wp-social-link wp-social-link-linkedin  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.linkedin.com/company/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M19.7,3H4.3C3.582,3,3,3.582,3,4.3v15.4C3,20.418,3.582,21,4.3,21h15.4c0.718,0,1.3-0.582,1.3-1.3V4.3 C21,3.582,20.418,3,19.7,3z M8.339,18.338H5.667v-8.59h2.672V18.338z M7.004,8.574c-0.857,0-1.549-0.694-1.549-1.548 c0-0.855,0.691-1.548,1.549-1.548c0.854,0,1.547,0.694,1.547,1.548C8.551,7.881,7.858,8.574,7.004,8.574z M18.339,18.338h-2.669 v-4.177c0-0.996-0.017-2.278-1.387-2.278c-1.389,0-1.601,1.086-1.601,2.206v4.249h-2.667v-8.59h2.559v1.174h0.037 c0.356-0.675,1.227-1.387,2.526-1.387c2.703,0,3.203,1.779,3.203,4.092V18.338z"></path></svg><span class="wp-block-social-link-label screen-reader-text">LinkedIn</span></a></li>

<li class="wp-social-link wp-social-link-github  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://github.com/topics/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M12,2C6.477,2,2,6.477,2,12c0,4.419,2.865,8.166,6.839,9.489c0.5,0.09,0.682-0.218,0.682-0.484 c0-0.236-0.009-0.866-0.014-1.699c-2.782,0.602-3.369-1.34-3.369-1.34c-0.455-1.157-1.11-1.465-1.11-1.465 c-0.909-0.62,0.069-0.608,0.069-0.608c1.004,0.071,1.532,1.03,1.532,1.03c0.891,1.529,2.341,1.089,2.91,0.833 c0.091-0.647,0.349-1.086,0.635-1.337c-2.22-0.251-4.555-1.111-4.555-4.943c0-1.091,0.39-1.984,1.03-2.682 C6.546,8.54,6.202,7.524,6.746,6.148c0,0,0.84-0.269,2.75,1.025C10.295,6.95,11.15,6.84,12,6.836 c0.85,0.004,1.705,0.114,2.504,0.336c1.909-1.294,2.748-1.025,2.748-1.025c0.546,1.376,0.202,2.394,0.1,2.646 c0.64,0.699,1.026,1.591,1.026,2.682c0,3.841-2.337,4.687-4.565,4.935c0.359,0.307,0.679,0.917,0.679,1.852 c0,1.335-0.012,2.415-0.012,2.741c0,0.269,0.18,0.579,0.688,0.481C19.138,20.161,22,16.416,22,12C22,6.477,17.523,2,12,2z"></path></svg><span class="wp-block-social-link-label screen-reader-text">GitHub</span></a></li>

<li class="wp-social-link wp-social-link-youtube  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.youtube.com/c/XojoInc" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M21.8,8.001c0,0-0.195-1.378-0.795-1.985c-0.76-0.797-1.613-0.801-2.004-0.847c-2.799-0.202-6.997-0.202-6.997-0.202 h-0.009c0,0-4.198,0-6.997,0.202C4.608,5.216,3.756,5.22,2.995,6.016C2.395,6.623,2.2,8.001,2.2,8.001S2,9.62,2,11.238v1.517 c0,1.618,0.2,3.237,0.2,3.237s0.195,1.378,0.795,1.985c0.761,0.797,1.76,0.771,2.205,0.855c1.6,0.153,6.8,0.201,6.8,0.201 s4.203-0.006,7.001-0.209c0.391-0.047,1.243-0.051,2.004-0.847c0.6-0.607,0.795-1.985,0.795-1.985s0.2-1.618,0.2-3.237v-1.517 C22,9.62,21.8,8.001,21.8,8.001z M9.935,14.594l-0.001-5.62l5.404,2.82L9.935,14.594z"></path></svg><span class="wp-block-social-link-label screen-reader-text">YouTube</span></a></li></ul>



<p class="has-text-align-center has-text-color has-link-color wp-elements-a0a2ac26ad214a49dac577734d259176" style="color:#84bd00"><a href="https://xojo.com/download/" target="_blank" rel="noreferrer noopener">Download Xojo</a></p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Build a Recursive Find in Files Function</title>
		<link>https://blog.xojo.com/2026/05/04/build-a-recursive-find-in-files-function/</link>
		
		<dc:creator><![CDATA[Gabriel Ludosanu]]></dc:creator>
		<pubDate>Mon, 04 May 2026 15:32:02 +0000</pubDate>
				<category><![CDATA[Cross-Platform]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[Files]]></category>
		<category><![CDATA[Method Overload]]></category>
		<category><![CDATA[Recursiveness]]></category>
		<category><![CDATA[Search]]></category>
		<guid isPermaLink="false">https://blog.xojo.com/?p=16179</guid>

					<description><![CDATA[In the&#160;previous post, we built a utility to find text inside files within a single folder. Today we&#8217;re upgrading that utility to support recursive searching&#8230;]]></description>
										<content:encoded><![CDATA[
<p>In the&nbsp;<a href="https://blog.xojo.com/2026/04/02/build-a-simple-find-in-files-function/">previous post</a>, we built a utility to find text inside files within a single folder. Today we&#8217;re upgrading that utility to support recursive searching with depth control. We&#8217;ll also refactor the code to keep it maintainable as it gets more complex.</p>



<h2 class="wp-block-heading" id="the-goal">The Goal</h2>



<p>We want to:</p>



<ol class="wp-block-list">
<li>Search through subfolders automatically.</li>



<li>Add a&nbsp;<code>maxDepth</code>&nbsp;parameter so we don&#8217;t accidentally crawl the entire hard drive.</li>



<li>Keep the simple version working using method overloading.</li>
</ol>



<h2 class="wp-block-heading" id="step-1-move-file-reading-to-its-own-method">Step 1: Move File Reading to its own Method</h2>



<p>The original&nbsp;<code>FindInFiles</code>&nbsp;function did everything: validated the folder, looped through children, read file content, and matched text. Adding recursion to that would make the code look ugly, so let&#8217;s refactor our code.</p>



<p>We&#8217;ll start by moving the file-reading logic into its own private method:&nbsp;<code>SearchFile</code>. This keeps the &#8220;search&#8221; logic separate from the &#8220;looping&#8221; logic.</p>



<pre class="wp-block-code"><code>Private Sub SearchFile(file As FolderItem, searchTerm As String, hits() As SearchHit)
  Try
    Var input As TextInputStream = TextInputStream.Open(file)
    input.Encoding = Encodings.UTF8
    Var lineNumber As Integer = 0
    While Not input.EndOfFile
      Var line As String = input.ReadLine
      lineNumber = lineNumber + 1
      If line.Contains(searchTerm, ComparisonOptions.CaseInsensitive) Then
        hits.Add(New SearchHit(file.NativePath, lineNumber, line))
      End If
    Wend
    input.Close
  Catch error As IOException
    // Skip unreadable files
  End Try
End Sub</code></pre>



<h2 class="wp-block-heading" id="step-2-recursive-folder-traversal">Step 2: Recursive Folder Traversal</h2>



<p>Now we create&nbsp;<code>SearchFolder</code>. This method loops through a folder. If it finds a file, it calls&nbsp;<code>SearchFile</code>. If it finds a folder, it calls itself.</p>



<p>To keep this safe, we Use&nbsp;<code>maxDepth</code>:</p>



<ul class="wp-block-list">
<li><code>maxDepth = 0</code>: Search only this folder.</li>



<li><code>maxDepth &gt; 0</code>: Search this folder and N levels of subfolders.</li>



<li><code>maxDepth = -1</code>: Search everything (unlimited).</li>
</ul>



<pre class="wp-block-code"><code>Private Sub SearchFolder(folder As FolderItem, searchTerm As String, hits() As SearchHit, maxDepth As Integer)
   Try
    For Each item As FolderItem In folder.Children
      If item Is Nil Or Not item.Exists Or Not item.IsReadable Then Continue
      If item.IsFolder Then
        If maxDepth &lt;&gt; 0 Then
          Var nextDepth As Integer = If(maxDepth &gt; 0, maxDepth - 1, maxDepth)
          SearchFolder(item, searchTerm, hits, nextDepth)
        End If
      Else
        SearchFile(item, searchTerm, hits)
      End If
    Next
  Catch error As IOException
    // Skip inaccessible folders
  End Try
End Sub</code></pre>



<p>The logic in&nbsp;<code>nextDepth</code>&nbsp;lets us count down if there&#8217;s a limit, or stay at -1 if there isn&#8217;t.</p>



<h2 class="wp-block-heading" id="step-3-support-both-versions-with-method-overloading">Step 3: Support Both Versions with Method Overloading</h2>



<p>Overloading is a feature that lets you have multiple methods with the same name, as long as they have different parameters. In our case, it allows us to provide a simple version for one folder, and a recursive version with a depth limit. Xojo will automatically pick the right one based on the arguments you pass. You can read more about it in the&nbsp;<a href="https://documentation.xojo.com/getting_started/object-oriented_programming/oop_design_concepts.html#getting-started-object-oriented-programming-oop-design-concepts-overloading" target="_blank" rel="noreferrer noopener">Xojo Documentation</a>.</p>



<p>The default version (depth 0):</p>



<pre class="wp-block-code"><code>Public Function FindInFiles(targetFolder As FolderItem, searchTerm As String) As SearchHit()
  Return FindInFiles(targetFolder, searchTerm, 0)
End Function</code></pre>



<p>The recursive version:</p>



<pre class="wp-block-code"><code>Public Function FindInFiles(targetFolder As FolderItem, searchTerm As String, maxDepth As Integer) As SearchHit()
  Var hits() As SearchHit
  If targetFolder Is Nil Or Not targetFolder.Exists Or Not targetFolder.IsFolder Or searchTerm.IsEmpty Then
    Return hits
  End If
  Try
    SearchFolder(targetFolder, searchTerm, hits, maxDepth)
  Catch error As IOException
    // Skip inaccessible folders
  End Try
  Return hits
End Function</code></pre>



<p id="why-this-structure">By separating the validation, traversal, and processing, the code is much easier to modify. If you want to add Regex support, you only change&nbsp;<code>SearchFile</code>. If you want to filter by file extension, you only change&nbsp;<code>SearchFolder</code>.</p>



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



<p>Now, you can search a single folder just like before, or crawl a directory tree with one extra parameter:</p>



<pre class="wp-block-code"><code>// Search up to 3 levels deep
Var results() As SearchUtils.SearchHit = SearchUtils.FindInFiles(myFolder, "TODO", 3)</code></pre>



<h2 class="wp-block-heading" id="the-complete-recursive-code">The Complete Recursive Code</h2>



<h3 class="wp-block-heading" id="the-searchutils-module">The SearchUtils Module</h3>



<pre class="wp-block-code"><code>Module SearchUtils

  Class SearchHit
    Public Property FilePath As String
    Public Property LineNumber As Integer
    Public Property LineText As String

    Public Sub Constructor(filePath As String, lineNumber As Integer, lineText As String)
      Self.FilePath = filePath
      Self.LineNumber = lineNumber
      Self.LineText = lineText
    End Sub
  End Class

  Public Function FindInFiles(targetFolder As FolderItem, searchTerm As String) As SearchHit()
    // Simple usage: depth = 0
    Return FindInFiles(targetFolder, searchTerm, 0)
  End Function

  Public Function FindInFiles(targetFolder As FolderItem, searchTerm As String, maxDepth As Integer) As SearchHit()
    // Recursive usage: maxDepth ( -1 is unlimited )

    Var hits() As SearchHit

    If targetFolder Is Nil Or Not targetFolder.Exists Or Not targetFolder.IsFolder Or searchTerm.IsEmpty Then
      Return hits
    End If

    Try
      SearchFolder(targetFolder, searchTerm, hits, maxDepth)
    Catch error As IOException
      // Skip inaccessible folders
    End Try

    Return hits
  End Function

  Private Sub SearchFolder(folder As FolderItem, searchTerm As String, hits() As SearchHit, maxDepth As Integer)
    Try
      For Each item As FolderItem In folder.Children
        If item Is Nil Or Not item.Exists Or Not item.IsReadable Then Continue

        If item.IsFolder Then
          If maxDepth &lt;&gt; 0 Then
            Var nextDepth As Integer = If(maxDepth &gt; 0, maxDepth - 1, maxDepth)
            SearchFolder(item, searchTerm, hits, nextDepth)
          End If
        Else
          SearchFile(item, searchTerm, hits)
        End If
      Next
    Catch error As IOException
      // Skip inaccessible folders
    End Try
  End Sub

  Private Sub SearchFile(file As FolderItem, searchTerm As String, hits() As SearchHit)
    Try
      Var input As TextInputStream = TextInputStream.Open(file)
      input.Encoding = Encodings.UTF8
      Var lineNumber As Integer = 0

      While Not input.EndOfFile
        Var line As String = input.ReadLine
        lineNumber = lineNumber + 1

        If line.Contains(searchTerm, ComparisonOptions.CaseInsensitive) Then
          hits.Add(New SearchHit(file.NativePath, lineNumber, line))
        End If
      Wend

      input.Close
    Catch error As IOException
      // Skip unreadable files
    End Try
  End Sub
End Module</code></pre>



<p>Happy coding!</p>



<p><em>Gabriel is a digital marketing enthusiast who loves coding with Xojo to create cool software tools for any platform. He is always eager to learn and share new ideas!</em></p>



<ul class="wp-block-social-links has-normal-icon-size is-content-justification-center is-layout-flex wp-container-core-social-links-is-layout-16018d1d wp-block-social-links-is-layout-flex"><li class="wp-social-link wp-social-link-facebook  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.facebook.com/goxojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M12 2C6.5 2 2 6.5 2 12c0 5 3.7 9.1 8.4 9.9v-7H7.9V12h2.5V9.8c0-2.5 1.5-3.9 3.8-3.9 1.1 0 2.2.2 2.2.2v2.5h-1.3c-1.2 0-1.6.8-1.6 1.6V12h2.8l-.4 2.9h-2.3v7C18.3 21.1 22 17 22 12c0-5.5-4.5-10-10-10z"></path></svg><span class="wp-block-social-link-label screen-reader-text">Facebook</span></a></li>

<li class="wp-social-link wp-social-link-x  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://x.com/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M13.982 10.622 20.54 3h-1.554l-5.693 6.618L8.745 3H3.5l6.876 10.007L3.5 21h1.554l6.012-6.989L15.868 21h5.245l-7.131-10.378Zm-2.128 2.474-.697-.997-5.543-7.93H8l4.474 6.4.697.996 5.815 8.318h-2.387l-4.745-6.787Z" /></svg><span class="wp-block-social-link-label screen-reader-text">X</span></a></li>

<li class="wp-social-link wp-social-link-linkedin  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.linkedin.com/company/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M19.7,3H4.3C3.582,3,3,3.582,3,4.3v15.4C3,20.418,3.582,21,4.3,21h15.4c0.718,0,1.3-0.582,1.3-1.3V4.3 C21,3.582,20.418,3,19.7,3z M8.339,18.338H5.667v-8.59h2.672V18.338z M7.004,8.574c-0.857,0-1.549-0.694-1.549-1.548 c0-0.855,0.691-1.548,1.549-1.548c0.854,0,1.547,0.694,1.547,1.548C8.551,7.881,7.858,8.574,7.004,8.574z M18.339,18.338h-2.669 v-4.177c0-0.996-0.017-2.278-1.387-2.278c-1.389,0-1.601,1.086-1.601,2.206v4.249h-2.667v-8.59h2.559v1.174h0.037 c0.356-0.675,1.227-1.387,2.526-1.387c2.703,0,3.203,1.779,3.203,4.092V18.338z"></path></svg><span class="wp-block-social-link-label screen-reader-text">LinkedIn</span></a></li>

<li class="wp-social-link wp-social-link-github  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://github.com/topics/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M12,2C6.477,2,2,6.477,2,12c0,4.419,2.865,8.166,6.839,9.489c0.5,0.09,0.682-0.218,0.682-0.484 c0-0.236-0.009-0.866-0.014-1.699c-2.782,0.602-3.369-1.34-3.369-1.34c-0.455-1.157-1.11-1.465-1.11-1.465 c-0.909-0.62,0.069-0.608,0.069-0.608c1.004,0.071,1.532,1.03,1.532,1.03c0.891,1.529,2.341,1.089,2.91,0.833 c0.091-0.647,0.349-1.086,0.635-1.337c-2.22-0.251-4.555-1.111-4.555-4.943c0-1.091,0.39-1.984,1.03-2.682 C6.546,8.54,6.202,7.524,6.746,6.148c0,0,0.84-0.269,2.75,1.025C10.295,6.95,11.15,6.84,12,6.836 c0.85,0.004,1.705,0.114,2.504,0.336c1.909-1.294,2.748-1.025,2.748-1.025c0.546,1.376,0.202,2.394,0.1,2.646 c0.64,0.699,1.026,1.591,1.026,2.682c0,3.841-2.337,4.687-4.565,4.935c0.359,0.307,0.679,0.917,0.679,1.852 c0,1.335-0.012,2.415-0.012,2.741c0,0.269,0.18,0.579,0.688,0.481C19.138,20.161,22,16.416,22,12C22,6.477,17.523,2,12,2z"></path></svg><span class="wp-block-social-link-label screen-reader-text">GitHub</span></a></li>

<li class="wp-social-link wp-social-link-youtube  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.youtube.com/c/XojoInc" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M21.8,8.001c0,0-0.195-1.378-0.795-1.985c-0.76-0.797-1.613-0.801-2.004-0.847c-2.799-0.202-6.997-0.202-6.997-0.202 h-0.009c0,0-4.198,0-6.997,0.202C4.608,5.216,3.756,5.22,2.995,6.016C2.395,6.623,2.2,8.001,2.2,8.001S2,9.62,2,11.238v1.517 c0,1.618,0.2,3.237,0.2,3.237s0.195,1.378,0.795,1.985c0.761,0.797,1.76,0.771,2.205,0.855c1.6,0.153,6.8,0.201,6.8,0.201 s4.203-0.006,7.001-0.209c0.391-0.047,1.243-0.051,2.004-0.847c0.6-0.607,0.795-1.985,0.795-1.985s0.2-1.618,0.2-3.237v-1.517 C22,9.62,21.8,8.001,21.8,8.001z M9.935,14.594l-0.001-5.62l5.404,2.82L9.935,14.594z"></path></svg><span class="wp-block-social-link-label screen-reader-text">YouTube</span></a></li></ul>



<p class="has-text-align-center has-text-color has-link-color wp-elements-a0a2ac26ad214a49dac577734d259176" style="color:#84bd00"><a href="https://xojo.com/download/" target="_blank" rel="noreferrer noopener">Download Xojo</a></p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Web Apps Denial of Service</title>
		<link>https://blog.xojo.com/2026/04/29/web-apps-denial-of-service/</link>
		
		<dc:creator><![CDATA[Ricardo Cruz]]></dc:creator>
		<pubDate>Wed, 29 Apr 2026 22:39:52 +0000</pubDate>
				<category><![CDATA[Networking]]></category>
		<category><![CDATA[Security]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[Xojo Cloud]]></category>
		<category><![CDATA[Web 2.0]]></category>
		<category><![CDATA[Web Development]]></category>
		<category><![CDATA[webdev]]></category>
		<category><![CDATA[Xojo Web]]></category>
		<guid isPermaLink="false">https://blog.xojo.com/?p=16222</guid>

					<description><![CDATA[Last week we got a report of a critical bug affecting Xojo Web apps. Here's what happened, what we did about it, and what you should do depending on how your apps are deployed.]]></description>
										<content:encoded><![CDATA[
<p>Last week we got a report of a critical bug affecting Xojo Web apps. A malformed percent-encoded URL was enough to crash the web app server. Something as small as <code>?x=%</code> in a query string was all it took. We shipped a fix in <a href="https://xojo.com/download/">2026r1.2</a>, and Xojo Cloud has been patched at the platform level to cover users who can&#8217;t upgrade right away. Here&#8217;s what happened, what we did about it, and what you should do depending on how your apps are deployed.</p>



<h2 class="wp-block-heading">Am I affected? What do I do?</h2>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p><strong>If you only read one section, read this one.</strong></p>
</blockquote>



<ul class="wp-block-list">
<li><strong>On Xojo Cloud (Web 1 or Web 2)?</strong>&nbsp;You&#8217;re covered. Nothing to do.</li>



<li><strong>Using Lifeboat?</strong>&nbsp;Update Lifeboat and redeploy.</li>



<li><strong>Self-hosted behind Apache or Nginx?</strong> Drop in the filtering rule below. If you&#8217;re on Web 2, also upgrade to 2026r1.2 if possible.</li>



<li><strong>Self-hosted with the Xojo app exposed directly?</strong> On Web 2, upgrade to 2026r1.2 if possible, otherwise put a reverse proxy in front. On Web 1, put a reverse proxy in front (which is what we&#8217;d recommend either way).</li>
</ul>



<p>The full details follow.</p>



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



<ul class="wp-block-list">
<li><strong>Thursday, the 23rd.</strong>&nbsp;A public issue and a private message landed on the same day, both pointing at the same bug.</li>



<li><strong>Thursday through Monday.</strong>&nbsp;We tracked down the root cause, wrote the fix, and tested it.</li>



<li><strong>Tuesday, the 28th.</strong> 2026r1.2 shipped with the patch.</li>



<li><strong>Wednesday, the 29th.</strong>&nbsp;Xojo Cloud patched at the platform level.</li>
</ul>



<p>Under a week from the report to a patched release, with the platform-level mitigation following the next day.</p>



<h2 class="wp-block-heading">What Happened</h2>



<p>A request with a malformed percent-encoded sequence in a query parameter could crash a running Xojo Web app. The smallest reproducer is something like&nbsp;<code>?x=%</code>. That&#8217;s a&nbsp;<code>%</code>&nbsp;not followed by two hex digits, which is invalid percent-encoding and isn&#8217;t decodable.</p>



<p>The bug lives in&nbsp;<code>DecodeURLComponent</code>. When the method ran into invalid input, it raised an exception instead of handling the input gracefully. Because the framework calls this method while parsing incoming requests, anyone could crash a web app by sending a single malformed URL. No authentication, no special headers, no payload. Just a bad query string.</p>



<p>A few things worth being upfront about:</p>



<ul class="wp-block-list">
<li><strong>The bug has probably been there since&nbsp;<code>DecodeURLComponent</code>&nbsp;was introduced.</strong>&nbsp;Every Xojo release that ships the method might be affected.</li>



<li><strong>Both Web 1 and Web 2 are known to be affected.</strong>&nbsp;The Web framework has been calling this method on incoming requests across both generations.</li>



<li><strong>It&#8217;s not just a Web problem.</strong>&nbsp;<code>DecodeURLComponent</code>&nbsp;is a general-purpose method, and the same crash can happen in Desktop and other project types if you call it on attacker-controlled input. Web is the obvious target because requests arrive from the network, but the underlying issue isn&#8217;t Web-specific.</li>
</ul>



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



<p>In 2026r1.2, <code>DecodeURLComponent</code> no longer crashes on invalid input. Instead, it returns an empty String when the input contains a malformed percent-encoded sequence.</p>



<p>We thought about a few approaches and went with this one on purpose, for being consistent with the other sanity checks we do on this method. An empty return value lets existing code keep running rather than letting an exception bubble up through request handling, which is what you want from a method that&#8217;s frequently called on untrusted input. If your code already wraps&nbsp;<code>DecodeURLComponent</code>&nbsp;with its own validation, the new behavior gives you a clean signal to act on (an empty result) instead of an exception to catch.</p>



<p>Xojo 2026r1.2 is the only release with the fix. <strong>Web 1 won&#8217;t be getting a backported patch.</strong> What that means in practice is covered below.</p>



<h2 class="wp-block-heading">What Xojo has already done for you</h2>



<p><strong>Xojo Cloud has been patched at the platform level.</strong>&nbsp;As of Wednesday 29th, Xojo Cloud rejects requests with malformed percent-encoding before they ever reach your app, returning a&nbsp;<code>400 Bad Request</code>&nbsp;from the front-end web server. This protection doesn&#8217;t care which Xojo version your app was built with, and it covers Web 1 and Web 2 the same way.</p>



<p>If your app runs on Xojo Cloud, you don&#8217;t need to redeploy, upgrade, or change anything. We rolled this out specifically so that users who can&#8217;t upgrade right away are covered, including Web 1 users who can&#8217;t upgrade to a fixed version at all.</p>



<h2 class="wp-block-heading">What you should do</h2>



<p>The right move depends on which Web version you&#8217;re on and where your app runs.</p>



<h3 class="wp-block-heading">If you&#8217;re on Web 2</h3>



<p>Upgrade to 2026r1.2 and redeploy if you can. That&#8217;s the cleanest fix and it addresses the issue at the source.</p>



<p>We know &#8220;just upgrade&#8221; isn&#8217;t always realistic. You might be on an older version because your license has expired, because a third-party plugin you rely on hasn&#8217;t caught up yet, because a newer Xojo release introduced a regression you can&#8217;t ship around, or for any number of other reasons. If that&#8217;s you, the hosting-based mitigations below will protect your app in the meantime, and they work regardless of which Xojo version you built with.</p>



<h3 class="wp-block-heading">If you&#8217;re on Web 1</h3>



<p>There&#8217;s no Xojo release that patches&nbsp;<code>DecodeURLComponent</code>&nbsp;for Web 1, so the fix has to live outside your app. The good news is that if you follow Xojo&#8217;s standard hosting recommendations, you&#8217;re fully covered against this specific issue:</p>



<ul class="wp-block-list">
<li><strong>Stay on Xojo Cloud.</strong>&nbsp;You&#8217;re already protected.</li>



<li><strong>Use Lifeboat.</strong>&nbsp;Tim Parnell shipped a Lifeboat update that catches malformed percent-encoding before it reaches your app. Update Lifeboat and redeploy.</li>



<li><strong>Run behind Apache or Nginx</strong>&nbsp;with the rules in the next section.</li>
</ul>



<p>Separately, and on a longer horizon: Web 1 isn&#8217;t receiving framework patches anymore in general, so if you&#8217;re still on it, this is a reasonable moment to start thinking about a migration to Web 2. That&#8217;s a much bigger conversation than this post, but worth flagging.</p>



<h3 class="wp-block-heading">Hosting-level mitigations</h3>



<p>These rules reject malformed percent-encoded URLs at the web server, before the request reaches your Xojo app at all. They work for Web 1 and Web 2, and they don&#8217;t depend on the Xojo version you built with.</p>



<p><strong>Apache:</strong></p>



<pre class="wp-block-code"><code># Reject malformed percent-encoding in the URI.
RewriteCond %{THE_REQUEST} %(?!&#91;0-9A-Fa-f]{2})
RewriteRule .* - &#91;R=400,L]</code></pre>



<p><strong>Nginx:</strong></p>



<pre class="wp-block-code"><code># Reject malformed percent-encoding in the URI.
if ($request_uri ~ "%(?!&#91;0-9A-Fa-f]{2})") {
  return 400;
}</code></pre>



<p>Reload your web server after updating the config (<code>apachectl graceful</code>&nbsp;or&nbsp;<code>nginx -s reload</code>) and check that a request like&nbsp;<code>https://yourapp.example.com/?x=%</code>&nbsp;comes back as&nbsp;<code>400 Bad Request</code>.</p>



<p>These two snippets aren&#8217;t the only way to handle this. The goal is just to block malformed URLs before they reach your app, however you do it. If you&#8217;re running <code>mod_security</code>, for example, a rule that rejects URIs containing invalid percent-encoding will get you the same result. Same idea for any WAF, edge filter, CDN, or load balancer in front of your stack: catch the bad request, return a&nbsp;<code>400</code>, move on.</p>



<h3 class="wp-block-heading">If your Xojo app is exposed directly to the internet</h3>



<p>If your Web app is talking to the internet without a reverse proxy in front of it, your options are narrower. On Web 2, upgrade to 2026r1.2 if you can. On Web 1, or on Web 2 if upgrading isn&#8217;t an option, you&#8217;ll need to put Apache, Nginx, or Lifeboat in front of your app, or move to Xojo Cloud, our managed hosting solution.</p>



<p>This is also a good moment to revisit the setup more broadly.&nbsp;<strong>Xojo recommends always serving Web apps behind a web server</strong>, both for performance and as a defense-in-depth measure against bugs like this one. A reverse proxy would have neutralized this specific issue before it reached the framework, and it&#8217;ll do the same for the next class of issue too.</p>



<h3 class="wp-block-heading">If you use&nbsp;<code>DecodeURLComponent</code>&nbsp;in a non-Web project</h3>



<p>The crash isn&#8217;t unique to Web. If you&#8217;re calling&nbsp;<code>DecodeURLComponent</code>&nbsp;on input you don&#8217;t control (anything coming from a user, a file, a network response, a clipboard), the same bug can hit a Desktop, Console, or other project type.</p>



<p>Upgrade to 2026r1.2 if you can; that&#8217;s the proper fix.</p>



<p>If you can&#8217;t upgrade, you&#8217;ll need to sanitize the input yourself before calling&nbsp;<code>DecodeURLComponent</code>. The check is simple in principle: every&nbsp;<code>%</code>&nbsp;in the string must be followed by exactly two hexadecimal characters (<code>0-9</code>,&nbsp;<code>A-F</code>,&nbsp;<code>a-f</code>). If any&nbsp;<code>%</code>&nbsp;doesn&#8217;t meet that condition, treat the input as invalid and don&#8217;t pass it to&nbsp;<code>DecodeURLComponent</code>. A small helper that validates the string up front and either returns early or substitutes an empty value will keep your app from crashing on the same kind of malformed input that triggers the Web bug.</p>



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



<p>Thanks to the user who reported this through both public and private channels. That&#8217;s exactly the kind of disclosure that lets us turn a fix around in under a week. Thanks also to Tim Parnell for the fast <a href="https://strawberrysw.com/lifeboat/">Lifeboat</a> update, which gave self-hosted users a drop-in mitigation almost immediately.</p>



<p>If you find a security issue in Xojo, please report it privately. You can email&nbsp;<a href="mailto:support@xojo.com">support@xojo.com</a>&nbsp;or file a confidential issue on the issue tracker. Both reach us, and either one lets us get a fix out before the details become public, protecting the rest of the users.</p>



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



<ul class="wp-block-list">
<li><a href="https://documentation.xojo.com/resources/release_notes/2026r1.2.html">Release notes for 2026r1.2</a></li>
</ul>



<p><em>Ricardo has always been curious about how things work. Growing up surrounded by computers</em> he became interested in <em>web technologies in the dial-up connections era. Xojo has been his secret weapon and language of preference since 2018. When he’s not online, chances are he will be scuba diving … or crocheting amigurumis. Find Ricardo on Twitter <a href="https://x.com/piradoiv" target="_blank" rel="noreferrer noopener">@piradoiv</a>.</em></p>



<ul class="wp-block-social-links has-normal-icon-size is-content-justification-center is-layout-flex wp-container-core-social-links-is-layout-16018d1d wp-block-social-links-is-layout-flex"><li class="wp-social-link wp-social-link-facebook  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.facebook.com/goxojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M12 2C6.5 2 2 6.5 2 12c0 5 3.7 9.1 8.4 9.9v-7H7.9V12h2.5V9.8c0-2.5 1.5-3.9 3.8-3.9 1.1 0 2.2.2 2.2.2v2.5h-1.3c-1.2 0-1.6.8-1.6 1.6V12h2.8l-.4 2.9h-2.3v7C18.3 21.1 22 17 22 12c0-5.5-4.5-10-10-10z"></path></svg><span class="wp-block-social-link-label screen-reader-text">Facebook</span></a></li>

<li class="wp-social-link wp-social-link-x  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://x.com/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M13.982 10.622 20.54 3h-1.554l-5.693 6.618L8.745 3H3.5l6.876 10.007L3.5 21h1.554l6.012-6.989L15.868 21h5.245l-7.131-10.378Zm-2.128 2.474-.697-.997-5.543-7.93H8l4.474 6.4.697.996 5.815 8.318h-2.387l-4.745-6.787Z" /></svg><span class="wp-block-social-link-label screen-reader-text">X</span></a></li>

<li class="wp-social-link wp-social-link-linkedin  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.linkedin.com/company/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M19.7,3H4.3C3.582,3,3,3.582,3,4.3v15.4C3,20.418,3.582,21,4.3,21h15.4c0.718,0,1.3-0.582,1.3-1.3V4.3 C21,3.582,20.418,3,19.7,3z M8.339,18.338H5.667v-8.59h2.672V18.338z M7.004,8.574c-0.857,0-1.549-0.694-1.549-1.548 c0-0.855,0.691-1.548,1.549-1.548c0.854,0,1.547,0.694,1.547,1.548C8.551,7.881,7.858,8.574,7.004,8.574z M18.339,18.338h-2.669 v-4.177c0-0.996-0.017-2.278-1.387-2.278c-1.389,0-1.601,1.086-1.601,2.206v4.249h-2.667v-8.59h2.559v1.174h0.037 c0.356-0.675,1.227-1.387,2.526-1.387c2.703,0,3.203,1.779,3.203,4.092V18.338z"></path></svg><span class="wp-block-social-link-label screen-reader-text">LinkedIn</span></a></li>

<li class="wp-social-link wp-social-link-github  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://github.com/topics/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M12,2C6.477,2,2,6.477,2,12c0,4.419,2.865,8.166,6.839,9.489c0.5,0.09,0.682-0.218,0.682-0.484 c0-0.236-0.009-0.866-0.014-1.699c-2.782,0.602-3.369-1.34-3.369-1.34c-0.455-1.157-1.11-1.465-1.11-1.465 c-0.909-0.62,0.069-0.608,0.069-0.608c1.004,0.071,1.532,1.03,1.532,1.03c0.891,1.529,2.341,1.089,2.91,0.833 c0.091-0.647,0.349-1.086,0.635-1.337c-2.22-0.251-4.555-1.111-4.555-4.943c0-1.091,0.39-1.984,1.03-2.682 C6.546,8.54,6.202,7.524,6.746,6.148c0,0,0.84-0.269,2.75,1.025C10.295,6.95,11.15,6.84,12,6.836 c0.85,0.004,1.705,0.114,2.504,0.336c1.909-1.294,2.748-1.025,2.748-1.025c0.546,1.376,0.202,2.394,0.1,2.646 c0.64,0.699,1.026,1.591,1.026,2.682c0,3.841-2.337,4.687-4.565,4.935c0.359,0.307,0.679,0.917,0.679,1.852 c0,1.335-0.012,2.415-0.012,2.741c0,0.269,0.18,0.579,0.688,0.481C19.138,20.161,22,16.416,22,12C22,6.477,17.523,2,12,2z"></path></svg><span class="wp-block-social-link-label screen-reader-text">GitHub</span></a></li>

<li class="wp-social-link wp-social-link-youtube  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.youtube.com/c/XojoInc" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M21.8,8.001c0,0-0.195-1.378-0.795-1.985c-0.76-0.797-1.613-0.801-2.004-0.847c-2.799-0.202-6.997-0.202-6.997-0.202 h-0.009c0,0-4.198,0-6.997,0.202C4.608,5.216,3.756,5.22,2.995,6.016C2.395,6.623,2.2,8.001,2.2,8.001S2,9.62,2,11.238v1.517 c0,1.618,0.2,3.237,0.2,3.237s0.195,1.378,0.795,1.985c0.761,0.797,1.76,0.771,2.205,0.855c1.6,0.153,6.8,0.201,6.8,0.201 s4.203-0.006,7.001-0.209c0.391-0.047,1.243-0.051,2.004-0.847c0.6-0.607,0.795-1.985,0.795-1.985s0.2-1.618,0.2-3.237v-1.517 C22,9.62,21.8,8.001,21.8,8.001z M9.935,14.594l-0.001-5.62l5.404,2.82L9.935,14.594z"></path></svg><span class="wp-block-social-link-label screen-reader-text">YouTube</span></a></li></ul>



<p class="has-text-align-center has-text-color has-link-color wp-elements-a0a2ac26ad214a49dac577734d259176" style="color:#84bd00"><a href="https://xojo.com/download/" target="_blank" rel="noreferrer noopener">Download Xojo</a></p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Quick Tip: Font Properties in DrawControlInLayoutEditor for Mobile Projects</title>
		<link>https://blog.xojo.com/2026/04/22/quick-tip-font-properties-in-drawcontrolinlayouteditor-for-mobile-projects/</link>
		
		<dc:creator><![CDATA[Martin T.]]></dc:creator>
		<pubDate>Wed, 22 Apr 2026 20:30:00 +0000</pubDate>
				<category><![CDATA[Android]]></category>
		<category><![CDATA[Community]]></category>
		<category><![CDATA[Guest Post]]></category>
		<category><![CDATA[iOS]]></category>
		<category><![CDATA[Mobile]]></category>
		<category><![CDATA[Tips]]></category>
		<guid isPermaLink="false">https://blog.xojo.com/?p=16193</guid>

					<description><![CDATA[In the new DrawControlInLayoutEditor event of Xojo, which is available for MobileCanvas, AndroidMobileUserControl, and iOSMobileUserControl, there are properties available that otherwise do not exist in&#8230;]]></description>
										<content:encoded><![CDATA[
<p>In the new DrawControlInLayoutEditor event of Xojo, which is available for <a href="https://documentation.xojo.com/api/user_interface/mobile/mobilecanvas.html#mobilecanvas">MobileCanvas</a>, AndroidMobileUserControl, and iOSMobileUserControl, there are properties available that otherwise do not exist in the Graphics class for mobile projects.</p>



<p>Specifically, the following properties can be used there:</p>



<ul class="wp-block-list">
<li>Graphics.FontName</li>



<li>Graphics.FontSize</li>



<li>Graphics.FontAscent</li>
</ul>



<p>These properties are known from other Xojo targets (e.g. Desktop), but are not part of the official mobile API and are not shown in Autocomplete. They cannot be used outside of this event. </p>



<p>In contrast, the mobile API property Graphics.Font cannot be used within the DrawControlInLayoutEditor event. The usage is strictly limited to the DrawControlInLayoutEditor event. Using these properties in runtime code will result in errors.</p>



<p>These properties allow for more accurate text rendering in the layout editor, for example in custom controls where font metrics need to be considered. </p>



<p>Although these properties are not part of the mobile API, they can be used selectively within the layout editor context.</p>



<p>This code will work fine in your mobile control’s DrawControlInLayoutEditor event:</p>



<pre class="wp-block-code"><code>Var s As String = "Happy coding!"
Var x As Double = g.Width / 2 - g.TextWidth(s) / 2
Var y As Double = g.Height / 2 - g.TextHeight / 2 + g.FontAscent

g.DrawingColor = Color.Red
g.DrawOval(0, 0, g.Width, g.Height)

g.DrawingColor = TextColor
g.Bold = True
g.FontName = "Times New Roman"
g.FontSize = 16
g.DrawText(s, x, y)</code></pre>



<figure class="wp-block-image size-large is-resized"><img loading="lazy" decoding="async" width="571" height="1024" src="https://blog.xojo.com/wp-content/uploads/2026/04/Bildschirmfoto-2026-04-15-um-02.17.17-571x1024.png" alt="" class="wp-image-16194" style="aspect-ratio:0.557587099017292;width:325px;height:auto" srcset="https://blog.xojo.com/wp-content/uploads/2026/04/Bildschirmfoto-2026-04-15-um-02.17.17-571x1024.png 571w, https://blog.xojo.com/wp-content/uploads/2026/04/Bildschirmfoto-2026-04-15-um-02.17.17-167x300.png 167w, https://blog.xojo.com/wp-content/uploads/2026/04/Bildschirmfoto-2026-04-15-um-02.17.17-768x1377.png 768w, https://blog.xojo.com/wp-content/uploads/2026/04/Bildschirmfoto-2026-04-15-um-02.17.17.png 852w" sizes="auto, (max-width: 571px) 100vw, 571px" /></figure>



<p>Happy coding!</p>



<p><em>Martin T. is a Xojo MVP and has been very involved in testing Android support.</em></p>



<ul class="wp-block-social-links has-normal-icon-size is-content-justification-center is-layout-flex wp-container-core-social-links-is-layout-16018d1d wp-block-social-links-is-layout-flex"><li class="wp-social-link wp-social-link-facebook  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.facebook.com/goxojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M12 2C6.5 2 2 6.5 2 12c0 5 3.7 9.1 8.4 9.9v-7H7.9V12h2.5V9.8c0-2.5 1.5-3.9 3.8-3.9 1.1 0 2.2.2 2.2.2v2.5h-1.3c-1.2 0-1.6.8-1.6 1.6V12h2.8l-.4 2.9h-2.3v7C18.3 21.1 22 17 22 12c0-5.5-4.5-10-10-10z"></path></svg><span class="wp-block-social-link-label screen-reader-text">Facebook</span></a></li>

<li class="wp-social-link wp-social-link-x  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://x.com/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M13.982 10.622 20.54 3h-1.554l-5.693 6.618L8.745 3H3.5l6.876 10.007L3.5 21h1.554l6.012-6.989L15.868 21h5.245l-7.131-10.378Zm-2.128 2.474-.697-.997-5.543-7.93H8l4.474 6.4.697.996 5.815 8.318h-2.387l-4.745-6.787Z" /></svg><span class="wp-block-social-link-label screen-reader-text">X</span></a></li>

<li class="wp-social-link wp-social-link-linkedin  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.linkedin.com/company/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M19.7,3H4.3C3.582,3,3,3.582,3,4.3v15.4C3,20.418,3.582,21,4.3,21h15.4c0.718,0,1.3-0.582,1.3-1.3V4.3 C21,3.582,20.418,3,19.7,3z M8.339,18.338H5.667v-8.59h2.672V18.338z M7.004,8.574c-0.857,0-1.549-0.694-1.549-1.548 c0-0.855,0.691-1.548,1.549-1.548c0.854,0,1.547,0.694,1.547,1.548C8.551,7.881,7.858,8.574,7.004,8.574z M18.339,18.338h-2.669 v-4.177c0-0.996-0.017-2.278-1.387-2.278c-1.389,0-1.601,1.086-1.601,2.206v4.249h-2.667v-8.59h2.559v1.174h0.037 c0.356-0.675,1.227-1.387,2.526-1.387c2.703,0,3.203,1.779,3.203,4.092V18.338z"></path></svg><span class="wp-block-social-link-label screen-reader-text">LinkedIn</span></a></li>

<li class="wp-social-link wp-social-link-github  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://github.com/topics/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M12,2C6.477,2,2,6.477,2,12c0,4.419,2.865,8.166,6.839,9.489c0.5,0.09,0.682-0.218,0.682-0.484 c0-0.236-0.009-0.866-0.014-1.699c-2.782,0.602-3.369-1.34-3.369-1.34c-0.455-1.157-1.11-1.465-1.11-1.465 c-0.909-0.62,0.069-0.608,0.069-0.608c1.004,0.071,1.532,1.03,1.532,1.03c0.891,1.529,2.341,1.089,2.91,0.833 c0.091-0.647,0.349-1.086,0.635-1.337c-2.22-0.251-4.555-1.111-4.555-4.943c0-1.091,0.39-1.984,1.03-2.682 C6.546,8.54,6.202,7.524,6.746,6.148c0,0,0.84-0.269,2.75,1.025C10.295,6.95,11.15,6.84,12,6.836 c0.85,0.004,1.705,0.114,2.504,0.336c1.909-1.294,2.748-1.025,2.748-1.025c0.546,1.376,0.202,2.394,0.1,2.646 c0.64,0.699,1.026,1.591,1.026,2.682c0,3.841-2.337,4.687-4.565,4.935c0.359,0.307,0.679,0.917,0.679,1.852 c0,1.335-0.012,2.415-0.012,2.741c0,0.269,0.18,0.579,0.688,0.481C19.138,20.161,22,16.416,22,12C22,6.477,17.523,2,12,2z"></path></svg><span class="wp-block-social-link-label screen-reader-text">GitHub</span></a></li>

<li class="wp-social-link wp-social-link-youtube  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.youtube.com/c/XojoInc" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M21.8,8.001c0,0-0.195-1.378-0.795-1.985c-0.76-0.797-1.613-0.801-2.004-0.847c-2.799-0.202-6.997-0.202-6.997-0.202 h-0.009c0,0-4.198,0-6.997,0.202C4.608,5.216,3.756,5.22,2.995,6.016C2.395,6.623,2.2,8.001,2.2,8.001S2,9.62,2,11.238v1.517 c0,1.618,0.2,3.237,0.2,3.237s0.195,1.378,0.795,1.985c0.761,0.797,1.76,0.771,2.205,0.855c1.6,0.153,6.8,0.201,6.8,0.201 s4.203-0.006,7.001-0.209c0.391-0.047,1.243-0.051,2.004-0.847c0.6-0.607,0.795-1.985,0.795-1.985s0.2-1.618,0.2-3.237v-1.517 C22,9.62,21.8,8.001,21.8,8.001z M9.935,14.594l-0.001-5.62l5.404,2.82L9.935,14.594z"></path></svg><span class="wp-block-social-link-label screen-reader-text">YouTube</span></a></li></ul>



<p class="has-text-align-center has-text-color has-link-color wp-elements-a0a2ac26ad214a49dac577734d259176" style="color:#84bd00"><a href="https://xojo.com/download/" target="_blank" rel="noreferrer noopener">Download Xojo</a></p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Spotlight on: Paul Garfield</title>
		<link>https://blog.xojo.com/2026/04/22/spotlight-on-paul-garfield/</link>
		
		<dc:creator><![CDATA[Alyssa Foley]]></dc:creator>
		<pubDate>Wed, 22 Apr 2026 15:24:29 +0000</pubDate>
				<category><![CDATA[Community]]></category>
		<category><![CDATA[Mac]]></category>
		<category><![CDATA[Citizen Developer]]></category>
		<category><![CDATA[Spotlight On]]></category>
		<guid isPermaLink="false">https://blog.xojo.com/?p=16174</guid>

					<description><![CDATA[Spotlight On posts focus on Xojo community members. We’ll use this space to tell the stories of people using Xojo, share amazing Xojo-made apps and&#8230;]]></description>
										<content:encoded><![CDATA[
<p><em>Spotlight On posts focus on Xojo community members. We’ll use this space to tell the stories of people using Xojo, share amazing Xojo-made apps and spread awareness of community resources. If you have an app, a project or a person you want to see featured in Spotlight On,&nbsp;<a href="mailto:hello@xojo.com" target="_blank" rel="noreferrer noopener">tell us about it</a>!</em></p>



<p>Though he started his development journey on Windows machines, after a seven-year spell at SAIC Ltd. (Science Applications International Corp), Paul decided he wanted to move to Apple computers and started looking for a VB/Access replacement. That’s how he discovered Xojo and built a suite of applications that managed multiple aspects of his hire-boat business, overseeing 17 boats on the British Canal System. Even in retirement, he remains actively coding in 2026.</p>



<h3 class="wp-block-heading"><strong>Mac, Windows or Linux?</strong></h3>



<p>Mac.</p>



<h3 class="wp-block-heading"><strong>How did you find Xojo? And when did you start using Xojo?</strong></h3>



<p>I started in 2000 with RealBASIC. I needed a database/programming combination to run my boat yard and hire boat business on the British Canal system. I went for RealBASIC and FrontBase database, it was fast reliable and very stable. It enabled me to create a suite of about 10 programs for renting the boats, doing the maintenance, tracking sales and running the cafe. The applications managed the bookings for 17 boats which operated on a varied pattern of 3, 4, 7 and 14 night holidays. The progams stored the bookings, printed the legal documents required at the start of each trip and logged the fuel usage and engineering routines.</p>



<h3 class="wp-block-heading"><strong>Do you earn a living with Xojo?</strong></h3>



<p>No, but my business would not have run without it.</p>



<h3 class="wp-block-heading"><strong>Xojo isn’t the only tool in your kit. What is a piece of software more people should know about?</strong></h3>



<p>A good knowledge of a database which interfaces well with Xojo is useful. I interfaced my early applications with FrontBase but the plugin does not exist now. I moved to PostgresSQL, it was a bit different at first, but the new AddROW instruction in Xojo has really streamlined my apps.</p>



<h3 class="wp-block-heading">Which three Xojo language features or framework capabilities do you find yourself relying/using on the most?</h3>



<p>My three main items are Listbox, Graphics &#8211; items loading pictures and drawing on top of the picture, and the database plugins. Shame we lost FrontBase but PostgreSQL seems to suite me almost as well.</p>



<figure class="wp-block-gallery has-nested-images columns-default is-cropped wp-block-gallery-4 is-layout-flex wp-block-gallery-is-layout-flex">
<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="791" data-id="16183" src="https://blog.xojo.com/wp-content/uploads/2026/04/Screenshot-2026-04-12-at-15.36.07-1024x791.png" alt="" class="wp-image-16183" srcset="https://blog.xojo.com/wp-content/uploads/2026/04/Screenshot-2026-04-12-at-15.36.07-1024x791.png 1024w, https://blog.xojo.com/wp-content/uploads/2026/04/Screenshot-2026-04-12-at-15.36.07-300x232.png 300w, https://blog.xojo.com/wp-content/uploads/2026/04/Screenshot-2026-04-12-at-15.36.07-768x593.png 768w, https://blog.xojo.com/wp-content/uploads/2026/04/Screenshot-2026-04-12-at-15.36.07-1536x1186.png 1536w, https://blog.xojo.com/wp-content/uploads/2026/04/Screenshot-2026-04-12-at-15.36.07-2048x1582.png 2048w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="797" data-id="16182" src="https://blog.xojo.com/wp-content/uploads/2026/04/Screenshot-2026-04-12-at-15.37.01-1024x797.png" alt="" class="wp-image-16182" srcset="https://blog.xojo.com/wp-content/uploads/2026/04/Screenshot-2026-04-12-at-15.37.01-1024x797.png 1024w, https://blog.xojo.com/wp-content/uploads/2026/04/Screenshot-2026-04-12-at-15.37.01-300x233.png 300w, https://blog.xojo.com/wp-content/uploads/2026/04/Screenshot-2026-04-12-at-15.37.01-768x598.png 768w, https://blog.xojo.com/wp-content/uploads/2026/04/Screenshot-2026-04-12-at-15.37.01-1536x1195.png 1536w, https://blog.xojo.com/wp-content/uploads/2026/04/Screenshot-2026-04-12-at-15.37.01.png 1696w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>
</figure>



<h3 class="wp-block-heading"><strong>What do you build with it now?</strong></h3>



<p>I currently help a very good friend who owns a canal boat marina in the heart of the UK, sadly he uses Windows machines and some rather clunky Access database applications, I would love to get my hands on them! </p>



<h3 class="wp-block-heading"><strong>How would you explain your most recent project to a new developer?</strong></h3>



<p>I wanted to maintain a visual display of the boats in a marina and track the ownership and movements of the boats. Initially, I created a Listbox to display the database table which allowed me to count and record vessel details. But I wanted to visualise the position and load it as a picture. Using the DesktopBevelButton, I recorded the position on the plan. They are the red and green squares along the edge of the piers and clicking on an individual location fetches the boat data. I am now looking to locate all the technical resources electric and water points and pontoon detail for our service and engineering crew.</p>



<h3 class="wp-block-heading"><strong>Do you use it for any hobbies?</strong></h3>



<p>At nearly 80 I just enjoy the mental exercise, but I still build games for my granddaughter and things to help at the office where I do some administration. I retired and sold the business, but I do some part-time work at a canal marina where we live. Using Xojo and PostgreSQL I am developing a visual boat management system. We moor nearly 200 boats of varying lengths on pontoons of varying lengths! A real juggling job!</p>



<h3 class="wp-block-heading"><strong>What’s your biggest Xojo success?</strong></h3>



<p>Sticking with it for such a long time, all through changing RECORDSET to ROWSET, and how simple INSTR grew. I mastered the new graphics methods after much effort &#8211; but I did it!</p>



<h3 class="wp-block-heading">If you were introducing Xojo to a friend, which three words would you use to describe it?</h3>



<p>Flexible, fast with great technical backup when you need it.</p>



<p><em>Thank you to Paul Garfield for answering questions and sharing his Xojo experience with the community.&nbsp;If you have an app, a project or a person you want to see featured in Spotlight On,&nbsp;<a href="mailto:hello@xojo.com" target="_blank" rel="noreferrer noopener">tell us about it</a>!</em></p>



<ul class="wp-block-social-links has-normal-icon-size is-content-justification-center is-layout-flex wp-container-core-social-links-is-layout-16018d1d wp-block-social-links-is-layout-flex"><li class="wp-social-link wp-social-link-facebook  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.facebook.com/goxojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M12 2C6.5 2 2 6.5 2 12c0 5 3.7 9.1 8.4 9.9v-7H7.9V12h2.5V9.8c0-2.5 1.5-3.9 3.8-3.9 1.1 0 2.2.2 2.2.2v2.5h-1.3c-1.2 0-1.6.8-1.6 1.6V12h2.8l-.4 2.9h-2.3v7C18.3 21.1 22 17 22 12c0-5.5-4.5-10-10-10z"></path></svg><span class="wp-block-social-link-label screen-reader-text">Facebook</span></a></li>

<li class="wp-social-link wp-social-link-x  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://x.com/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M13.982 10.622 20.54 3h-1.554l-5.693 6.618L8.745 3H3.5l6.876 10.007L3.5 21h1.554l6.012-6.989L15.868 21h5.245l-7.131-10.378Zm-2.128 2.474-.697-.997-5.543-7.93H8l4.474 6.4.697.996 5.815 8.318h-2.387l-4.745-6.787Z" /></svg><span class="wp-block-social-link-label screen-reader-text">X</span></a></li>

<li class="wp-social-link wp-social-link-linkedin  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.linkedin.com/company/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M19.7,3H4.3C3.582,3,3,3.582,3,4.3v15.4C3,20.418,3.582,21,4.3,21h15.4c0.718,0,1.3-0.582,1.3-1.3V4.3 C21,3.582,20.418,3,19.7,3z M8.339,18.338H5.667v-8.59h2.672V18.338z M7.004,8.574c-0.857,0-1.549-0.694-1.549-1.548 c0-0.855,0.691-1.548,1.549-1.548c0.854,0,1.547,0.694,1.547,1.548C8.551,7.881,7.858,8.574,7.004,8.574z M18.339,18.338h-2.669 v-4.177c0-0.996-0.017-2.278-1.387-2.278c-1.389,0-1.601,1.086-1.601,2.206v4.249h-2.667v-8.59h2.559v1.174h0.037 c0.356-0.675,1.227-1.387,2.526-1.387c2.703,0,3.203,1.779,3.203,4.092V18.338z"></path></svg><span class="wp-block-social-link-label screen-reader-text">LinkedIn</span></a></li>

<li class="wp-social-link wp-social-link-github  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://github.com/topics/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M12,2C6.477,2,2,6.477,2,12c0,4.419,2.865,8.166,6.839,9.489c0.5,0.09,0.682-0.218,0.682-0.484 c0-0.236-0.009-0.866-0.014-1.699c-2.782,0.602-3.369-1.34-3.369-1.34c-0.455-1.157-1.11-1.465-1.11-1.465 c-0.909-0.62,0.069-0.608,0.069-0.608c1.004,0.071,1.532,1.03,1.532,1.03c0.891,1.529,2.341,1.089,2.91,0.833 c0.091-0.647,0.349-1.086,0.635-1.337c-2.22-0.251-4.555-1.111-4.555-4.943c0-1.091,0.39-1.984,1.03-2.682 C6.546,8.54,6.202,7.524,6.746,6.148c0,0,0.84-0.269,2.75,1.025C10.295,6.95,11.15,6.84,12,6.836 c0.85,0.004,1.705,0.114,2.504,0.336c1.909-1.294,2.748-1.025,2.748-1.025c0.546,1.376,0.202,2.394,0.1,2.646 c0.64,0.699,1.026,1.591,1.026,2.682c0,3.841-2.337,4.687-4.565,4.935c0.359,0.307,0.679,0.917,0.679,1.852 c0,1.335-0.012,2.415-0.012,2.741c0,0.269,0.18,0.579,0.688,0.481C19.138,20.161,22,16.416,22,12C22,6.477,17.523,2,12,2z"></path></svg><span class="wp-block-social-link-label screen-reader-text">GitHub</span></a></li>

<li class="wp-social-link wp-social-link-youtube  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.youtube.com/c/XojoInc" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M21.8,8.001c0,0-0.195-1.378-0.795-1.985c-0.76-0.797-1.613-0.801-2.004-0.847c-2.799-0.202-6.997-0.202-6.997-0.202 h-0.009c0,0-4.198,0-6.997,0.202C4.608,5.216,3.756,5.22,2.995,6.016C2.395,6.623,2.2,8.001,2.2,8.001S2,9.62,2,11.238v1.517 c0,1.618,0.2,3.237,0.2,3.237s0.195,1.378,0.795,1.985c0.761,0.797,1.76,0.771,2.205,0.855c1.6,0.153,6.8,0.201,6.8,0.201 s4.203-0.006,7.001-0.209c0.391-0.047,1.243-0.051,2.004-0.847c0.6-0.607,0.795-1.985,0.795-1.985s0.2-1.618,0.2-3.237v-1.517 C22,9.62,21.8,8.001,21.8,8.001z M9.935,14.594l-0.001-5.62l5.404,2.82L9.935,14.594z"></path></svg><span class="wp-block-social-link-label screen-reader-text">YouTube</span></a></li></ul>



<p class="has-text-align-center has-text-color has-link-color wp-elements-a0a2ac26ad214a49dac577734d259176" style="color:#84bd00"><a href="https://xojo.com/download/" target="_blank" rel="noreferrer noopener">Download Xojo</a></p>



<p><a href="https://www.youtube.com/c/XojoInc" target="_blank" rel="noreferrer noopener"></a></p>
]]></content:encoded>
					
		
		
			</item>
	</channel>
</rss>
