The perils of binding to value types in XAML

The Old New Thing (Raymond Chen) Tools

Summary

This blog post discusses a technical pitfall in XAML where binding to value types leads to navigation failures with assistive tools due to copy-by-value semantics, and suggests using runtime classes with helper libraries like wil to avoid the issue.

<p>A colleague ran into trouble with their XAML program. They were using a <code>FlipView</code> control to bind to a collection, but when the user tried to navigate the <code>FlipView</code> using an assistive technology tool, there were cases where the navigation failed.</p> <p>Some time later, they came back with the solution to the mystery.</p> <p>The team noticed that their data model consisted only of strings and other value types, so they decided to declare their data model as a <code>struct</code> rather than a full <code>runtimeclass</code>, thereby avoiding a lot of boilerplate typing.</p> <p>If defined as a <code>runtimeclass</code>:</p> <pre>// MyComponent.idl runtimeclass MyPageContent { String Title { get; }; String Description { get; }; String LinkUri { get; }; Boolean IsNew{ get; }; } // MyPageContent.h namespace winrt::MyComponent { struct MyPageContent : implements&lt;MyPageContent&gt; { MyPageContent(hstring const&amp; title, hstring const&amp; description, hstring const&amp; link, bool isNew) : m_title(title), m_description(description), m_link(link), m_isNew(isNew) {} hstring Title() const { return m_title; } hstring Description() const { return m_description; } hstring Link() const { return m_link; } bool IsNew() const { return m_isNew; } private: hstring m_title; hstring m_description; Windows::Foundation::Uri m_link; bool m_isNew; }; } // Consumer.cpp m_pages.Append(winrt::make&lt;MyPageContent&gt;( title, description, link, isNew)); </pre> <p>But if you define it as a <code>struct</code>, then most of this code isn&#8217;t necessary:</p> <pre>// MyComponent.idl <span style="border: solid 1px currentcolor;">struct</span> MyPageContent { String Title; String Description; String Link; Boolean IsNew; } // <span style="text-decoration: line-through;">MyPageContent.h</span> not needed // Consumer.cpp m_pages.Append(MyPageContent(title, description, link, isNew)); </pre> <p><a href="https://en.wikipedia.org/wiki/Miller_Lite#Advertising">Tastes great, less filling</a>.</p> <p>Now, the thing that makes value types value types is that they are copy-by-value, not copy-by-reference. This means that when XAML calls <code>GetAt(n)</code> on the <code>m_pages</code> to get the <var>n</var>th item, it gets a <i>copy</i> of the <code>MyPageContent</code> and binds to the copy.</p> <p>And that&#8217;s the source of the problem.</p> <p>When the code wants to navigate to a specific item at the request of the assistive technology tool, it passes the <code>MyPageContent</code> to navigate to, but that&#8217;s just another copy because value types are always passed by copy. XAML says, &#8220;I don&#8217;t have that guy&#8221; and fails the navigation. (XAML doesn&#8217;t realize that it has a guy who <i>looks just like</i> that guy. Not that it matters, because it&#8217;s not the same guy.)</p> <p>The clever shortcut turned out to be the problem.</p> <p>Now, while it&#8217;s true that there&#8217;s a bunch of typing needed to implement a C++/WinRT runtime class, there are helpers to reduce the amount of typing required. In the Windows Implementation Library (wil), the <code>cppwinrt_authoring.h</code> header contains classes to simplify the implementation of events and properties. It exploits CRTP <a title="Exploiting C++/WinRT CRTP: Property and event declarations" href="https://devblogs.microsoft.com/oldnewthing/20230317-00/?p=107946"> in the same way I discussed some time ago</a>.</p> <pre>// MyPageContent.h namespace winrt::MyComponent { struct MyPageContent : implements&lt;MyPageContent&gt; { MyPageContent(hstring const&amp; title, hstring const&amp; description, hstring const&amp; link, bool isNew) : m_title(title), m_description(description), m_link(link), m_isNew(isNew) {} <span style="border: solid 1px currentcolor; border-bottom: none;">wil::single_threaded_property&lt;hstring&gt; Title; </span> <span style="border: 1px currentcolor; border-style: none solid;">wil::single_threaded_property&lt;hstring&gt; Description;</span> <span style="border: 1px currentcolor; border-style: none solid;">wil::single_threaded_property&lt;hstring&gt; Link; </span> <span style="border: solid 1px currentcolor; border-top: none;">wil::single_threaded_property&lt;bool&gt; IsNew; </span> }; } </pre> <p>We can get away with using a <code>single_<wbr />threaded_<wbr />property</code> because the properties are written only at construction, so concurrent reads are not going to cause problems.</p> <p>The post <a href="https://devblogs.microsoft.com/oldnewthing/20260902-00/?p=112668">The perils of binding to value types in XAML</a> appeared first on <a href="https://devblogs.microsoft.com/oldnewthing">The Old New Thing</a>.</p>
Original Article
View Cached Full Text

Cached at: 09/03/26, 11:43 AM

# The perils of binding to value types in XAML - The Old New Thing Source: [https://devblogs.microsoft.com/oldnewthing/20260902-00?p=112668](https://devblogs.microsoft.com/oldnewthing/20260902-00?p=112668) A colleague ran into trouble with their XAML program\. They were using a`FlipView`control to bind to a collection, but when the user tried to navigate the`FlipView`using an assistive technology tool, there were cases where the navigation failed\. Some time later, they came back with the solution to the mystery\. The team noticed that their data model consisted only of strings and other value types, so they decided to declare their data model as a`struct`rather than a full`runtimeclass`, thereby avoiding a lot of boilerplate typing\. If defined as a`runtimeclass`: ``` // MyComponent.idl runtimeclass MyPageContent { String Title { get; }; String Description { get; }; String LinkUri { get; }; Boolean IsNew{ get; }; } // MyPageContent.h namespace winrt::MyComponent { struct MyPageContent : implements<MyPageContent> { MyPageContent(hstring const& title, hstring const& description, hstring const& link, bool isNew) : m_title(title), m_description(description), m_link(link), m_isNew(isNew) {} hstring Title() const { return m_title; } hstring Description() const { return m_description; } hstring Link() const { return m_link; } bool IsNew() const { return m_isNew; } private: hstring m_title; hstring m_description; Windows::Foundation::Uri m_link; bool m_isNew; }; } // Consumer.cpp m_pages.Append(winrt::make<MyPageContent>( title, description, link, isNew)); ``` But if you define it as a`struct`, then most of this code isn’t necessary: ``` // MyComponent.idl struct MyPageContent { String Title; String Description; String Link; Boolean IsNew; } // MyPageContent.h not needed // Consumer.cpp m_pages.Append(MyPageContent(title, description, link, isNew)); ``` [Tastes great, less filling](https://en.wikipedia.org/wiki/Miller_Lite#Advertising)\. Now, the thing that makes value types value types is that they are copy\-by\-value, not copy\-by\-reference\. This means that when XAML calls`GetAt\(n\)`on the`m\_pages`to get thenth item, it gets a*copy*of the`MyPageContent`and binds to the copy\. And that’s the source of the problem\. When the code wants to navigate to a specific item at the request of the assistive technology tool, it passes the`MyPageContent`to navigate to, but that’s just another copy because value types are always passed by copy\. XAML says, “I don’t have that guy” and fails the navigation\. \(XAML doesn’t realize that it has a guy who*looks just like*that guy\. Not that it matters, because it’s not the same guy\.\) The clever shortcut turned out to be the problem\. Now, while it’s true that there’s a bunch of typing needed to implement a C\+\+/WinRT runtime class, there are helpers to reduce the amount of typing required\. In the Windows Implementation Library \(wil\), the`cppwinrt\_authoring\.h`header contains classes to simplify the implementation of events and properties\. It exploits CRTP[in the same way I discussed some time ago](https://devblogs.microsoft.com/oldnewthing/20230317-00/?p=107946)\. ``` // MyPageContent.h namespace winrt::MyComponent { struct MyPageContent : implements<MyPageContent> { MyPageContent(hstring const& title, hstring const& description, hstring const& link, bool isNew) : m_title(title), m_description(description), m_link(link), m_isNew(isNew) {} wil::single_threaded_property<hstring> Title; wil::single_threaded_property<hstring> Description; wil::single_threaded_property<hstring> Link; wil::single_threaded_property<bool> IsNew; }; } ``` We can get away with using a`single\_threaded\_property`because the properties are written only at construction, so concurrent reads are not going to cause problems\. ### Category ### Topics ## Author ![Raymond Chen](https://devblogs.microsoft.com/oldnewthing/wp-content/uploads/sites/38/2019/02/RaymondChen_5in-150x150.jpg) Raymond has been involved in the evolution of Windows for more than 30 years\. In 2003, he began a Web site known as The Old New Thing which has grown in popularity far beyond his wildest imagination, a development which still gives him the heebie\-jeebies\. The Web site spawned a book, coincidentally also titled The Old New Thing \(Addison Wesley 2007\)\. He occasionally appears on the Windows Dev Docs Twitter account to tell stories which convey no useful information\.

Similar Articles

Vision-Language Models are Fragile Multilingual Associators

arXiv cs.CL

This paper introduces M2BIND, a benchmark to evaluate whether vision-language models maintain stable visual-linguistic associations across languages. It finds that binding is not language-invariant, with cross-family and cross-script settings causing significant performance collapse and weaker internal causal binding.