{"id":108141,"date":"2023-05-04T07:00:00","date_gmt":"2023-05-04T14:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=108141"},"modified":"2023-05-04T09:21:20","modified_gmt":"2023-05-04T16:21:20","slug":"20230504-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20230504-00\/?p=108141","title":{"rendered":"Why does XAML complain that none of the overloads of <CODE>winrt::to_hstring<\/CODE> could be used?"},"content":{"rendered":"<p>A customer was having trouble compiling their C++\/WinRT project that used XAML binding.<\/p>\n<p>They had a data template that binds the <code>Content<\/code> property of the <code>AwesomeThing<\/code> to a <code>TextBlock<\/code>&#8216;s text:<\/p>\n<pre>&lt;!-- XAML --&gt;\r\n&lt;DataTemplate x:DataType=\"local:AwesomeThing\"&gt;\r\n    &lt;TextBlock Text=\"{x:Bind Content}\" \/&gt;\r\n&lt;\/DataTemplate&gt;\r\n<\/pre>\n<p>But when they tried to compile this, they got a C++\/WinRT error:<\/p>\n<pre style=\"white-space: pre-wrap;\">MainPage.xaml.g.hpp(200): error C2665: 'winrt::to_hstring': none of the 13 overloads could convert all the argument types\r\n    while trying to match the argument list '(winrt::<wbr \/>Windows::<wbr \/>Foundation::<wbr \/>IInspectable)'\r\n    while compiling class template member function 'void winrt::<wbr \/>Contoso::<wbr \/>implementation::MainPageT&lt;<wbr \/>winrt::<wbr \/>Contoso::<wbr \/>implementation::<wbr \/>MainPage&gt;::MainPage_<wbr \/>obj1_<wbr \/>Bindings::<wbr \/>Update_<wbr \/>Content(<wbr \/>winrt::<wbr \/>Windows::<wbr \/>Foundation::<wbr \/>IInspectable,<wbr \/>int32_t)'\r\n    see reference to class template instantiation 'winrt::<wbr \/>Contoso::<wbr \/>implementation::<wbr \/>MainPageT&lt;<wbr \/>winrt::<wbr \/>Contoso::<wbr \/>implementation::<wbr \/>MainPage&gt;::<wbr \/>MainPage_<wbr \/>obj1_<wbr \/>Bindings' being compiled\r\nMainPage.xaml.g.hpp(200): error C2660: 'winrt::<wbr \/>Contoso::<wbr \/>implementation::<wbr \/>MainPageT&lt;<wbr \/>winrt::<wbr \/>Contoso::<wbr \/>implementation::MainPage&gt;::<wbr \/>MainPage_<wbr \/>obj1_<wbr \/>Bindings::<wbr \/>Set_<wbr \/>Windows_<wbr \/>UI_<wbr \/>Xaml_<wbr \/>Controls_<wbr \/>TextBlock_<wbr \/>Text': function does not take 1 arguments\r\n    see declaration of 'winrt::<wbr \/>Contoso::<wbr \/>implementation::<wbr \/>MainPageT&lt;<wbr \/>winrt::<wbr \/>Contoso::<wbr \/>implementation::<wbr \/>MainPage&gt;::<wbr \/>MainPage_<wbr \/>obj1_<wbr \/>Bindings::<wbr \/>Set_<wbr \/>Windows_<wbr \/>UI_<wbr \/>Xaml_<wbr \/>Controls_<wbr \/>TextBlock_<wbr \/>Text'\r\n<\/pre>\n<p>What&#8217;s going on here?<\/p>\n<p>Let&#8217;s see if we can decode the error message.<\/p>\n<p>The first error says that somebody is trying to call <code>winrt::<wbr \/>to_hstring<\/code> with something that can&#8217;t be converted to a string. How curious.<\/p>\n<p>The Visual Studio Error List window shows only the first line of each error message. <a title=\"How can I find the invalid class when C++\/WinRT tells me that the class may not be final?\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20230417-00\/?p=108057\"> To see the important supplemental information, you have to switch to the Output window<\/a>. That&#8217;s what tells us that the argument that couldn&#8217;t be converted to a string is an <code>IInspectable<\/code>.<\/p>\n<p>The second error says that somebody passed only one parameter to the <code>Set_<wbr \/>Windows_<wbr \/>UI_<wbr \/>Xaml_<wbr \/>Controls_<wbr \/>TextBlock_<wbr \/>Text<\/code> function. This is probably a cascade failure: The function takes two parameters, but one of them ended up being an error, so there was only one valid parameter left.<\/p>\n<p>Looking at the source code confirms this diagnosis:<\/p>\n<pre>void Update_Content(::winrt::Windows::Foundation::IInspectable obj, int32_t phase)\r\n{\r\n    if((phase &amp; ((1 &lt;&lt; 0) | NOT_PHASED )) != 0)\r\n    {\r\n        Set_Windows_UI_Xaml_Controls_TextBlock_Text(obj7, ::winrt::to_hstring(obj));\r\n    }\r\n}\r\n<\/pre>\n<p>What we&#8217;ve learned so far is that the XAML compiler generated some code that takes an <code>IInspectable<\/code> and tries to convert to a string (via <code>to_hstring<\/code>), so it can set the <code>Text<\/code> property of a <code>TextBlock<\/code>.<\/p>\n<p>Gosh, where in our XAML markup could we be trying to assign an <code>IInspectable<\/code> to a <code>Text<\/code> property?<\/p>\n<p>Well, I made it easy because it is in fact the only binding in the entire XAML fragment: It&#8217;s the <code>Text=\"{x:Bind Content}\"<\/code>. (The other clue is that the method is named <code>Update_<wbr \/>Content<\/code>.)<\/p>\n<p>The <code>Content<\/code> property was declared like this:<\/p>\n<pre>\/\/ Contoso.idl\r\n\r\nnamespace Contoso\r\n{\r\n    runtimeclass AwesomeThing\r\n    {\r\n        Object Name{ get; };\r\n        Object Content{ get; };\r\n        \/* and other properties *\/\r\n    }\r\n}\r\n<\/pre>\n<p>Notice that the <code>Content<\/code> property is declared as an <code>Object<\/code>, which is the MIDL compiler&#8217;s name for what in the ABI is called <code>IInspectable<\/code>.<\/p>\n<p>And that&#8217;s why we have the error. The XAML markup is trying to bind the <code>TextBlock.<wbr \/>Text<\/code> property (which is a string) to the <code>Awesome\u00adThing.<wbr \/>Content<\/code> property (which is an <code>IInspectable<\/code>). The XAML compiler sees that this is a type mismatch and tries to coerce the conversion by calling <code>to_hstring<\/code> and hoping for the best.<\/p>\n<p>Unfortunately, it didn&#8217;t work.<\/p>\n<p>You can fix this in a few ways.<\/p>\n<p>The simplest way is to change the type of the <code>Content<\/code> property to <code>String<\/code>. Then you&#8217;re binding a string to a string, and everything lines up.<\/p>\n<p>On the other hand, maybe your <code>Content<\/code> property is an <code>Object<\/code> on purpose, say, because it can hold multiple things. Maybe it&#8217;s a string. Maybe it&#8217;s an integer. Maybe it&#8217;s a XAML element tree.<\/p>\n<p>In that case, you&#8217;ll have to teach XAML how to convert that mysterious object to a string. You can do this with a converter, or since you&#8217;re already invested in <code>x:Bind<\/code>, you can use a function binding. Write a function to convert that mysterious object into a string, using an algorithm that describes how you want the conversion to occur. For example, maybe you&#8217;ll write it like this:<\/p>\n<pre>\/\/ Contoso.idl\r\n\r\nnamespace Contoso\r\n{\r\n    runtimeclass AwesomeThing\r\n    {\r\n        Object Name{ get; };\r\n        Object Content{ get; };\r\n        \/* and other properties *\/\r\n\r\n        <span style=\"color: #08f;\">static String ContentToString(Object o);<\/span>\r\n    }\r\n}\r\n\r\n\/\/ C++\/WinRT implementation\r\n\r\nwinrt::hstring AwesomeThing::ContentToString(IInspectable const&amp; o)\r\n{\r\n    if (auto s = o.try_as&lt;winrt::hstring&gt;()) {\r\n        return s.value();\r\n    }\r\n    if (auto i = o.try_as&lt;int&gt;()) {\r\n        \/\/ assume that \"%d\" is acceptable\r\n        return winrt::to_hstring(i.value());\r\n    }\r\n    if (auto e = o.try_as&lt;winrt::FrameworkElement&gt;()) {\r\n        \/\/ ?? figure out what to return here\r\n        return L\"\";\r\n    }\r\n    return L\"\";\r\n}\r\n\r\n&lt;!-- XAML --&gt;\r\n&lt;DataTemplate x:DataType=\"local:AwesomeThing\"&gt;\r\n    &lt;TextBlock Text=\"{x:Bind local:AwesomeThing.ContentToString(Content)}\" \/&gt;\r\n&lt;\/DataTemplate&gt;\r\n<\/pre>\n<p>You might have thought of adding a new property that does the conversion:<\/p>\n<pre>\/\/ Contoso.idl\r\n\r\nnamespace Contoso\r\n{\r\n    runtimeclass AwesomeThing\r\n    {\r\n        Object Name{ get; };\r\n        Object Content{ get; };\r\n        \/* and other properties *\/\r\n\r\n        <span style=\"color: #08f;\">String ContentAsString{ get; };<\/span>\r\n    }\r\n}\r\n\r\n\/\/ C++\/WinRT implementation\r\n\r\nwinrt::hstring AwesomeThing::<span style=\"color: #08f;\">ContentAsString()<\/span>\r\n{\r\n    <span style=\"color: #08f;\">auto o = Content();<\/span>\r\n\r\n    if (auto s = o.try_as&lt;winrt::hstring&gt;()) {\r\n        return s.value();\r\n    }\r\n    if (auto i = o.try_as&lt;int&gt;()) {\r\n        \/\/ assume that \"%d\" is acceptable\r\n        return winrt::to_hstring(i.value());\r\n    }\r\n    if (auto e = o.try_as&lt;winrt::FrameworkElement&gt;()) {\r\n        \/\/ ?? figure out what to return here\r\n        return L\"\";\r\n    }\r\n    return L\"\";\r\n}\r\n\r\n&lt;!-- XAML --&gt;\r\n&lt;DataTemplate x:DataType=\"local:AwesomeThing\"&gt;\r\n    &lt;TextBlock Text=\"{x:Bind <span style=\"color: #08f;\">ContentAsString<\/span>}\" \/&gt;\r\n&lt;\/DataTemplate&gt;\r\n<\/pre>\n<p>This works, but only because <code>x:Bind<\/code> defaults to one-time binding. If you switch to one-way binding:<\/p>\n<pre>&lt;!-- XAML --&gt;\r\n&lt;DataTemplate x:DataType=\"local:AwesomeThing\"&gt;\r\n    &lt;TextBlock Text=\"{x:Bind ContentAsString, <span style=\"color: #08f;\">Mode=OneWay<\/span>}\" \/&gt;\r\n&lt;\/DataTemplate&gt;\r\n<\/pre>\n<p>then changes to the <code>Content<\/code> property will not trigger a recalculation of <code>ContentAsString<\/code>. You have to remember to raise a <code>PropertyChanged<\/code> event for <code>ContentAsString<\/code> whenever the <code>Content<\/code> property changes.<\/p>\n<p>The function binding avoids this need to remember to raise extra property change notifications: Passing <code>Content<\/code> as a parameter to the function binding not only provides a parameter to the <code>ContentAsString<\/code> function, the XAML compiler will see that the parameter is a property and recalculate the binding whenever <code>Content<\/code> changes.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Look at what you are converting from and converting to.<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[25],"class_list":["post-108141","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Look at what you are converting from and converting to.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/108141","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=108141"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/108141\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=108141"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=108141"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=108141"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}