Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WASM] Custom attached property not working when used in XAML #15813

Closed
IneedHelp opened this issue Mar 8, 2024 · 14 comments
Closed

[WASM] Custom attached property not working when used in XAML #15813

IneedHelp opened this issue Mar 8, 2024 · 14 comments
Assignees
Labels
area/code-generation Categorizes an issue or PR as relevant to code generation difficulty/tbd Categorizes an issue for which the difficulty level needs to be defined. kind/bug Something isn't working triage/untriaged Indicates an issue requires triaging or verification

Comments

@IneedHelp
Copy link

Current behavior

The problem is that I can't get attached properties to work when I use them in XAML with a WASM targeted project (I haven't tried other project types).

I have created this attached property:

namespace UnoApp12.SRC.NS_AP_HTML
{
    public static partial class AP_HTML
    {
        private static void _SRCPropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs args)
        {
            Console.WriteLine(value: "CALLBACK DOES NOT HIT");
        }

        public static readonly DependencyProperty _SRCProperty = DependencyProperty.RegisterAttached(
            name: "_SRC", propertyType: typeof(string), ownerType: typeof(AP_HTML), defaultMetadata: new PropertyMetadata(defaultValue: default(string), propertyChangedCallback: _SRCPropertyChangedCallback));

        public static void Set_SRC(DependencyObject element, string value)
        {
            Console.WriteLine(value: "SETTER DOES NOT HIT");

            element.SetValue(dp: _SRCProperty, value: value);
        }

        public static string Get_SRC(DependencyObject element)
        {
            return (string)element.GetValue(dp: _SRCProperty);
        }
    }
}

And used it as such in a clean/fresh WASM only project

<Page x:Class="UnoApp12.MainPage"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      xmlns:local="using:UnoApp12"
      xmlns:nsApHtml="clr-namespace:UnoApp12.SRC.NS_AP_HTML"
      Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
  <StackPanel
        HorizontalAlignment="Center"
        VerticalAlignment="Center">
    <TextBlock AutomationProperties.AutomationId="HelloTextBlock X"
               nsApHtml:AP_HTML._SRC="TEST STRING"
          Text="Hello Uno Platform"
          HorizontalAlignment="Center" />
  </StackPanel>
</Page>

and in the source generator there is no trace of the property being used

image

// <autogenerated />
#pragma warning disable 618 // Ignore obsolete members warnings
#pragma warning disable 105 // Ignore duplicate namespaces
#pragma warning disable 1591 // Ignore missing XML comment warnings
#pragma warning disable CS8669 // Ignore annotation for nullable reference types
#pragma warning disable CS0114
#pragma warning disable CS0108
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using Uno.UI;
using Uno.UI.Xaml;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Controls.Primitives;
using Microsoft.UI.Xaml.Data;
using Microsoft.UI.Xaml.Documents;
using Microsoft.UI.Xaml.Media;
using Microsoft.UI.Xaml.Media.Animation;
using Microsoft.UI.Xaml.Shapes;
using Windows.UI.Text;
using Uno.Extensions;
using Uno;
using Uno.UI.Helpers;
using Uno.UI.Helpers.Xaml;
using UnoApp12;

#if __ANDROID__
using _View = Android.Views.View;
#elif __IOS__
using _View = UIKit.UIView;
#elif __MACOS__
using _View = AppKit.NSView;
#else
using _View = Microsoft.UI.Xaml.UIElement;
#endif

namespace UnoApp12
{
	[global::System.Diagnostics.CodeAnalysis.SuppressMessage("nventive.Usage", "NV0056", Justification="Generated code")]
	[global::System.Diagnostics.CodeAnalysis.SuppressMessage("nventive.Usage", "NV0058", Justification="Generated code")]
	[global::System.Diagnostics.CodeAnalysis.SuppressMessage("nventive.Usage", "NV1003", Justification="Generated code")]
	[global::System.Diagnostics.CodeAnalysis.SuppressMessage("nventive.Usage", "NV0085", Justification="Generated code")]
	[global::System.Diagnostics.CodeAnalysis.SuppressMessage("nventive.Usage", "NV2001", Justification="Generated code")]
	[global::System.Diagnostics.CodeAnalysis.SuppressMessage("nventive.Usage", "NV2003", Justification="Generated code")]
	[global::System.Diagnostics.CodeAnalysis.SuppressMessage("nventive.Usage", "NV2004", Justification="Generated code")]
	[global::System.Diagnostics.CodeAnalysis.SuppressMessage("nventive.Usage", "NV2005", Justification="Generated code")]
	[global::System.Diagnostics.CodeAnalysis.SuppressMessage("dotnet", "CA1001", Justification="Generated code")]
	[global::System.Runtime.CompilerServices.CreateNewOnMetadataUpdate]
	partial class MainPage : global::Microsoft.UI.Xaml.Controls.Page
	{
		[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
		internal string __checksum() => "59d68aad90dc6096add00db659440efa0dedcb493b769bfb1a87b6078c94c56d";
		[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
		private const string __baseUri_prefix_MainPage_5ec5ebea63532915b4441ee7d8b45403 = "ms-appx:///UnoApp12/";
		[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
		private const string __baseUri_MainPage_5ec5ebea63532915b4441ee7d8b45403 = "ms-appx:///UnoApp12/MainPage.xaml";
		private global::Microsoft.UI.Xaml.NameScope __nameScope = new global::Microsoft.UI.Xaml.NameScope();
		private void InitializeComponent()
		{
			var __resourceLocator = new global::System.Uri("file:///C:/Users/Snek/source/repos/UnoApp12/UnoApp12/MainPage.xaml");
			if(global::Uno.UI.ApplicationHelper.IsLoadableComponent(__resourceLocator))
			{
				global::Microsoft.UI.Xaml.Application.LoadComponent(this, __resourceLocator);
				return;
			}
			NameScope.SetNameScope(this, __nameScope);
			var __that = this;
			base.IsParsing = true;
			// Source ..\..\..\MainPage.xaml (Line 1:2)
			base.Content = 
			new global::Microsoft.UI.Xaml.Controls.StackPanel
			{
				IsParsing = true,
				HorizontalAlignment = global::Microsoft.UI.Xaml.HorizontalAlignment.Center,
				VerticalAlignment = global::Microsoft.UI.Xaml.VerticalAlignment.Center,
				// Source ..\..\..\MainPage.xaml (Line 7:4)
				Children = 
				{
					new global::Microsoft.UI.Xaml.Controls.TextBlock
					{
						IsParsing = true,
						Text = "Hello Uno Platform",
						HorizontalAlignment = global::Microsoft.UI.Xaml.HorizontalAlignment.Center,
						// Source ..\..\..\MainPage.xaml (Line 10:6)
					}
					.GenericApply(__that, __nameScope, ((c0, __that, __nameScope) => 
					{
						global::Microsoft.UI.Xaml.Automation.AutomationProperties.SetAutomationId(c0, "HelloTextBlock X");
						global::Uno.UI.FrameworkElementHelper.SetBaseUri(c0, __baseUri_MainPage_5ec5ebea63532915b4441ee7d8b45403, "file:///C:/Users/Snek/source/repos/UnoApp12/UnoApp12/MainPage.xaml", 10, 6);
						c0.CreationComplete();
					}
					))
					,
				}
			}
			.GenericApply(__that, __nameScope, ((c1, __that, __nameScope) => 
			{
				global::Uno.UI.FrameworkElementHelper.SetBaseUri(c1, __baseUri_MainPage_5ec5ebea63532915b4441ee7d8b45403, "file:///C:/Users/Snek/source/repos/UnoApp12/UnoApp12/MainPage.xaml", 7, 4);
				c1.CreationComplete();
			}
			))
			;
			
			this
			.GenericApply(__that, __nameScope, ((c2, __that, __nameScope) => 
			{
				// Source ..\..\..\MainPage.xaml (Line 1:2)
				
				// WARNING Property c2.base does not exist on {http://schemas.microsoft.com/winfx/2006/xaml/presentation}Page, the namespace is http://www.w3.org/XML/1998/namespace. This error was considered irrelevant by the XamlFileGenerator
			}
			))
			.GenericApply(__that, __nameScope, ((c3, __that, __nameScope) => 
			{
				/* _isTopLevelDictionary:False */
				__that._component_0 = c3;
				// Class UnoApp12.MainPage
				global::Uno.UI.ResourceResolverSingleton.Instance.ApplyResource(c3, global::Microsoft.UI.Xaml.Controls.Page.BackgroundProperty, "ApplicationPageBackgroundThemeBrush", isThemeResourceExtension: true, isHotReloadSupported: true, context: global::UnoApp12.GlobalStaticResources.__ParseContext_);
				global::Uno.UI.FrameworkElementHelper.SetBaseUri(c3, __baseUri_MainPage_5ec5ebea63532915b4441ee7d8b45403, "file:///C:/Users/Snek/source/repos/UnoApp12/UnoApp12/MainPage.xaml", 1, 2);
				c3.CreationComplete();
			}
			))
			;
			OnInitializeCompleted();

			Bindings = ((IMainPage_Bindings)global::Uno.UI.Helpers.TypeMappings.CreateInstance<MainPage_Bindings>(this));
			global::Uno.UI.Helpers.MarkupHelper.SetElementProperty(__that, "owner", __that);
			Loading += (s, e) => 
			{
				var __that = global::Uno.UI.Helpers.MarkupHelper.GetElementProperty<global::UnoApp12.MainPage>(s, "owner");
				__that.Bindings.UpdateResources();
			}
			;
		}
		partial void OnInitializeCompleted();
		private global::Microsoft.UI.Xaml.Markup.ComponentHolder _component_0_Holder { get; } = new global::Microsoft.UI.Xaml.Markup.ComponentHolder(isWeak: true);
		private global::Microsoft.UI.Xaml.Controls.Page _component_0
		{
			get
			{
				return (global::Microsoft.UI.Xaml.Controls.Page)_component_0_Holder.Instance;
			}
			set
			{
				_component_0_Holder.Instance = value;
			}
		}
		private interface IMainPage_Bindings
		{
			void Initialize();
			void Update();
			void UpdateResources();
			void StopTracking();
		}
		#pragma warning disable 0169 //  Suppress unused field warning in case Bindings is not used.
		private IMainPage_Bindings Bindings;
		#pragma warning restore 0169
		[global::System.Runtime.CompilerServices.CreateNewOnMetadataUpdate]
		[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
		private class MainPage_Bindings : IMainPage_Bindings
		{
			#if UNO_HAS_UIELEMENT_IMPLICIT_PINNING
			private global::System.WeakReference _ownerReference;
			private global::UnoApp12.MainPage Owner { get => (global::UnoApp12.MainPage)_ownerReference?.Target; set => _ownerReference = new global::System.WeakReference(value); }
			#else
			private global::UnoApp12.MainPage Owner { get; set; }
			#endif
			public MainPage_Bindings(global::UnoApp12.MainPage owner)
			{
				Owner = owner;
			}
			void IMainPage_Bindings.Initialize()
			{
			}
			void IMainPage_Bindings.Update()
			{
				var owner = Owner;
			}
			void IMainPage_Bindings.UpdateResources()
			{
				var owner = Owner;
				owner._component_0.UpdateResourceBindings();
			}
			void IMainPage_Bindings.StopTracking()
			{
			}
		}
	}
}

Expected behavior

I expect the attached property to work, but in the sample I have provided, the setter isn't hit, the callback function isn't hit.

How to reproduce it (as minimally and precisely as possible)

No response

Workaround

No response

Works on UWP/WinUI

None

Environment

No response

NuGet package version(s)

No response

Affected platforms

WebAssembly

IDE

Visual Studio 2022

IDE version

No response

Relevant plugins

No response

Anything else we need to know?

No response

@IneedHelp IneedHelp added difficulty/tbd Categorizes an issue for which the difficulty level needs to be defined. kind/bug Something isn't working triage/untriaged Indicates an issue requires triaging or verification labels Mar 8, 2024
@Youssef1313 Youssef1313 self-assigned this Mar 8, 2024
@Youssef1313 Youssef1313 added the area/code-generation Categorizes an issue or PR as relevant to code generation label Mar 8, 2024
@IneedHelp
Copy link
Author

IneedHelp commented Mar 10, 2024

I realized attached properties in WASM projects only work when I have the Windows SDK NET framework referenced
image
So I can't have working attached properties unless that framework is referenced too.

Basically the project targeted frameworks has too look like this:

<TargetFrameworks Condition="$([MSBuild]::IsOSPlatform('windows')) or '$(EnableWindowsTargeting)' == 'true'">$(TargetFrameworks);$(DotNetVersion)-windows10.0.19041</TargetFrameworks>
<TargetFrameworks>$(TargetFrameworks);$(DotNetVersion);</TargetFrameworks>
<TargetFrameworks Condition="'$(OverrideTargetFramework)'!=''">$(OverrideTargetFramework)</TargetFrameworks>

Is there any reason it works this way ?

@Youssef1313
Copy link
Member

@IneedHelp Thanks for reporting this. I think the issue here is that you're using xmlns:nsApHtml="clr-namespace:UnoApp12.SRC.NS_AP_HTML".

Can you try xmlns:nsApHtml="using:UnoApp12.SRC.NS_AP_HTML" instead?

Currently, the action I think we should do is failing the build with a clear error message or producing a warning.

@jeromelaban thoughts?

@IneedHelp
Copy link
Author

@Youssef1313 YES! that was it, thank you very much!! I think I've created well over 50 projects by now trying to understand where the issue might be and why does it work when I have the Windows SDK NET framework referenced, but which in turn was creating problems when I was using Uno.WinUI.Runtime.WebAssembly.

Thank you! clr-namespace was being auto-generated by ReSharper and it just didn't go through my mind that it was the cause of the issue, especially after seeing it works in different circumstances. Failing the build with a clear error message or producing a warning is definitely a good idea, might save some time down the road for others that might face similar circumstances.

@IneedHelp
Copy link
Author

IneedHelp commented Mar 11, 2024

@Youssef1313 unfortunately now I've encountered a different problem related to this; if the attached properties are defined in an external library, when I try to reference them as such

xmlns:nsHtmlIframe="using:UnoHTML5Elements.SRC.L40.NS_HTML_iframe;assembly=UnoHTML5Elements"
xmlns:nsApHtml="using:UnoHTML5Elements.SRC.L20.NS_AP_HTML;assembly=UnoHTML5Elements"

it does not work, the compiler doesn't recognize the classes.
The only way I can get the code to compile is if I use it like this

xmlns:nsHtmlIframe1="clr-namespace:UnoHTML5Elements.SRC.L40.NS_HTML_iframe;assembly=UnoHTML5Elements"
xmlns:nsApHtml1="clr-namespace:UnoHTML5Elements.SRC.L20.NS_AP_HTML;assembly=UnoHTML5Elements"

but then we're back to the problem where attached properties don't work.

Is there something I'm doing wrong here ?
Thank you in advance!

//`─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────

Edit:
I even tried to work around it using XMLNS prefixes as such

using System.Windows.Markup;

[assembly: XmlnsPrefix(xmlNamespace: "http://UnoHTML5Elements.com/", prefix: "h5")]
[assembly: XmlnsDefinition(xmlNamespace: "http://UnoHTML5Elements.com/", clrNamespace: "UnoHTML5Elements.SRC.L20.NS_AP_HTML")]

and then using it

xmlns:h5="http://UnoHTML5Elements.com/"

but with no luck :( attached properties referenced this way still don't work..

//`─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────

EDIT2:
nevermind, it seems I have to skip using ;assembly=UnoHTML5Elements
so this works even if the code is from an external library

xmlns:nsHtmlIframe="using:UnoHTML5Elements.SRC.L40.NS_HTML_iframe"
xmlns:nsApHtml="using:UnoHTML5Elements.SRC.L20.NS_AP_HTML"

I guess all this ReSharper generated code really isn't in favor of using Uno.

Note: I could just remove this comment, but I think it's better to leave it here just in case others find themselves in similar situations.

@jeromelaban
Copy link
Member

Thanks for the update. XmlnsDefinition is not supported by WinUI, and Uno does not support it either at this time. You need to use the using:MyNamespace syntax. Additionally, the assembly qualifier that you added is not supported by either WinUI or Uno, but specifying using: is enough.

Still, it's an interesting issue. Could you provide a repro sample that demonstrates that issue? Attached properties work in general, we're using that extensively in many libraries, so it must be a scenario we're not covering.

Currently, the action I think we should do is failing the build with a clear error message or producing a warning.

@Youssef1313 we could, but WinUI does not, as far as I know.

@Youssef1313
Copy link
Member

@jeromelaban This fails to compile on WinUI

@jeromelaban
Copy link
Member

@Youssef1313 what's the error? Is it just the type not being found or something else?

@IneedHelp
Copy link
Author

@jeromelaban Using using:MyNamespace is what is should've done from the beginning, I just wasn't aware of the syntax and mostly going with what ReSharper was automatically generating, so really the only problem is me not knowing the specific syntax.

What is interesting tho is that clr-namespace works if the project also targets the Windows SDK, so that added to my confusion, making me believe it must be something else I'm doing wrong.

@jeromelaban
Copy link
Member

Thanks for the update. @Youssef1313 mentioned recently that this syntax was not supported for WinUI, and I wonder if there's something contextual to the use of this particular syntax. Youssef, would you remember?

@Youssef1313
Copy link
Member

Youssef1313 commented Mar 17, 2024

@IneedHelp Having a Windows project in the solution shouldn't have an effect. Can you attach a repro where it works with Windows project in the solution.

@jeromelaban The WinUI failure with clr-namespace is:

1>C:\Users\PC\source\repos\App19\MainWindow.xaml(12,16): XamlCompiler error WMC0010: Unknown attachable member 'AP_HTML._SRC' on element 'TextBlock'

Once clr-namespace is replaced with using it builds successfully.

@IneedHelp
Copy link
Author

IneedHelp commented Mar 17, 2024

@Youssef1313 you're right, the Windows project in the solution doesn't have an effect, it's about having referenced the Windows SDK in the common project (the one where we do the XAML work and where I initially observed the clr-namespace/using behavior)
image

@jeromelaban
Copy link
Member

@IneedHelp could you provide a repro of what you're experiencing?

@IneedHelp
Copy link
Author

IneedHelp commented Mar 19, 2024

@jeromelaban interestingly I can't reproduce this anymore, something must've changed since I last experienced this behavior, when using clr-namespace it doesn't compile anymore like it used to, which I guess is a good thing.

@Youssef1313
Copy link
Member

As clr-namespace is something that doesn't work in WinAppSDK and shouldn't work in Uno anyways (even if it probably does work in some cases today), I'm going to close this issue.

We'll probably take a breaking change in the next major to remove clr-namespace support completely from Uno targets, which will be tracked by #8339.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area/code-generation Categorizes an issue or PR as relevant to code generation difficulty/tbd Categorizes an issue for which the difficulty level needs to be defined. kind/bug Something isn't working triage/untriaged Indicates an issue requires triaging or verification
Projects
None yet
Development

No branches or pull requests

3 participants