Rocko Bonaparte
Topic Author
Posts: 39
Joined: 13 Oct 2020, 08:32

Proper way to load compiled XAML at run time in Unity

27 Mar 2021, 08:11

I feel stupid asking this because it must be pretty simple. I've implemented InitializeComponent with the LoadComponent calls that I think I need to properly pair to XAML in Noesis with Unity. This works fine while in the editor. However, the built game can't find the XAML files, and I'm not surprised. I figure I have to use the compiled asset instead, but I'm not sure how to point to that since everything implies being given a XAML. I figured I'd ask while poking around because the turnaround on trying stuff is kind of long thanks to the builds. Do I just use the .asset files in my Resources path instead?

What am I supposed to do in the final build instead of this?
private void InitializeComponent()
{
	Noesis.GUI.LoadComponent(this, "Assets/Project/UI/wpf/mainmenu/Save/SaveUserControl.xaml");
}
 
Rocko Bonaparte
Topic Author
Posts: 39
Joined: 13 Oct 2020, 08:32

Re: Proper way to load compiled XAML at run time in Unity

27 Mar 2021, 17:18

I guess the samples directly associate the XAML with the scene so Unity would know to include them. It implies I need to put the xaml in Resources if I want to find them.

I kind of figured the .xaml was getting compiled when made into an asset but I guess it's not true.
 
Rocko Bonaparte
Topic Author
Posts: 39
Joined: 13 Oct 2020, 08:32

Re: Proper way to load compiled XAML at run time in Unity

28 Mar 2021, 07:24

The saga continues.

Of course trying to reference paths in the Resources path wouldn't work because Unity turns that into single-file blob. I tried using StreamingResources instead. However, Noesis.GUI.LoadComponent never seems to find the path if I use what I thought was the typical thing:
Noesis.GUI.LoadComponent(this, System.IO.Path.Combine(Application.streamingAssetsPath, "UI/wpf/mainmenu/Top/MainMenuUserControl.xaml"));
The error I see reported matches up to the xaml in both the editor and the game, but the runtime errors that it can't locate it when I do this. Just to lay this out, the exact logged error text:
[noesis] Xaml not found 'C:/coding/learning_unity/game/unity/Assets/StreamingAssets\UI\wpf\mainmenu\Top\MainMenuUserControl.xaml'
UnityEngine.Debug:LogError(Object)
NoesisUnity:UnityLog(Int32, String) (at Assets/NoesisGUI/Plugins/NoesisUnity.cs:141)
Noesis.GUI:Noesis_LoadComponent(HandleRef, String)
Noesis.GUI:LoadComponent(Object, String) (at Assets/NoesisGUI/Plugins/API/Core/NoesisGUI.cs:292)
GameWpf.MainMenuUserControl:InitializeComponent() (at Assets/Project/UI/wpf/mainmenu/Top/MainMenuUserControl.xaml.cs:184)
GameWpf.MainMenuUserControl:.ctor() (at Assets/Project/UI/wpf/mainmenu/Top/MainMenuUserControl.xaml.cs:175)
System.Object:lambda_method(Closure)
Noesis.Extend:CreateInstance(IntPtr, IntPtr) (at Assets/NoesisGUI/Plugins/API/Core/Extend.cs:4659)
System.Object:wrapper_native_00007FFDF370E400(HandleRef, Size&, Size&)
Noesis.FrameworkElement:MeasureOverride(Size) (at Assets/NoesisGUI/Plugins/API/Proxies/FrameworkElementExtend.cs:45)
Noesis.FrameworkElement:CallMeasureOverride(Size, MeasureBaseCallback) (at Assets/NoesisGUI/Plugins/API/Proxies/FrameworkElementExtend.cs:89)
Noesis.Extend:FrameworkElementMeasure(IntPtr, Size&, Size&, MeasureBaseCallback) (at Assets/NoesisGUI/Plugins/API/Core/Extend.cs:1949)
Noesis.View:Noesis_View_SetSize(HandleRef, Int32, Int32)
Noesis.View:SetSize(Int32, Int32) (at Assets/NoesisGUI/Plugins/API/Core/View.cs:57)
NoesisXamlEditor:RenderPreview(View, Int32, Int32) (at Assets/NoesisGUI/Plugins/Editor/NoesisXamlEditor.cs:267)
NoesisXamlEditor:RenderStaticPreview(String, Object[], Int32, Int32) (at Assets/NoesisGUI/Plugins/Editor/NoesisXamlEditor.cs:241)
UnityEditor.AssetDatabase:SaveAssets()
NoesisPostprocessor:ImportXaml(String, Boolean, Boolean, Boolean&) (at Assets/NoesisGUI/Plugins/Editor/NoesisPostprocessor.cs:342)
NoesisPostprocessor:ImportXaml(String, Boolean, Boolean) (at Assets/NoesisGUI/Plugins/Editor/NoesisPostprocessor.cs:299)
NoesisPostprocessor:ImportAssets(String[], Boolean, UpdateProgress) (at Assets/NoesisGUI/Plugins/Editor/NoesisPostprocessor.cs:78)
NoesisPostprocessor:ImportAllAssets(UpdateProgress) (at Assets/NoesisGUI/Plugins/Editor/NoesisPostprocessor.cs:28)
NoesisPostprocessor:ImportAllAssets() (at Assets/NoesisGUI/Plugins/Editor/NoesisPostprocessor.cs:15)
NoesisSettingsEditor:OnInspectorGUI(SerializedObject) (at Assets/NoesisGUI/Plugins/Editor/NoesisSettingsEditor.cs:96)
NoesisSettingsEditor:OnInspectorGUI() (at Assets/NoesisGUI/Plugins/Editor/NoesisSettingsEditor.cs:11)
UnityEngine.GUIUtility:ProcessEvent(Int32, IntPtr)
Side note: It seems to turn my slashes into forward slashes no matter what I do. I got the same exact error when I changed them around, had the code built, and reimported all the XAMLs for giggles:
Noesis.GUI.LoadComponent(this, System.IO.Path.Combine(Application.streamingAssetsPath, @"UI\wpf\mainmenu\Top\MainMenuUserControl.xaml"));
I could get it to work in the editor is I didn't use Application.streamingAssetsPath but just referenced it relative to my project root: Assets/StreamingAssets/UI/wpf/mainmenu/Top/MainMenuUserControl.xaml. This doesn't work in the game build and I'm not sure what would when I can't reference the installation streaming asset path.

So I'm getting a lot of vibes here that even streaming paths are a no-go. I have to stub up some object that drags in the assets to get them into the build.
 
User avatar
sfernandez
Site Admin
Posts: 2984
Joined: 22 Dec 2011, 19:20

Re: Proper way to load compiled XAML at run time in Unity

29 Mar 2021, 10:35

Hi Rocko,

Yes, xaml assets must be referenced by the scene so Unity would know to include them.

As explained in our Unity tutorial the import process will automatically inject dependencies to used resources like ResourceDictionaries, UserControls, Textures, AudioClips and Fonts. For UserControls the .xaml file should be named as the control type to be automatically found (class NumericUpDown -> NumericUpDown.xaml).

In case you need to add extra dependencies to your XAML, for example resources used by code we provided an extension property, Xaml.Dependencies, for that purpose.
<UserControl
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:noesis="clr-namespace:NoesisGUIExtensions"
  x:Class="Localization.MainWindow"
  FontFamily="./#Oxygen, ./#FontopoNIHONGO"
  Foreground="#FF488EB5">

  <noesis:Xaml.Dependencies>
    <noesis:Dependency Source="Language-en.xaml"/>
    <noesis:Dependency Source="Language-fr.xaml"/>
    <noesis:Dependency Source="Language-jp.xaml"/>
  </noesis:Xaml.Dependencies>

</UserControl>
Another option is to have in your scene a gameobject that exposes a list of xamls assets that will be used in your application, this way they are also referenced and available to be loaded later in code using the path inside assets:
Noesis.GUI.LoadXaml("Assets/Path/To/Some.xaml");
Noesis.GUI.LoadComponent(this, "Assets/Path/To/SomeControl.xaml");
 
Rocko Bonaparte
Topic Author
Posts: 39
Joined: 13 Oct 2020, 08:32

Re: Proper way to load compiled XAML at run time in Unity

29 Mar 2021, 19:58

I figured out this method from skimming around a lot of posts. Instead of using the static LoadComponent, I can load the NoesisXaml as a result and then call LoadComponent on it instead:
        private void InitializeComponent()
        {
            // Previously: Noesis.GUI.LoadComponent(this, "Assets/Project/UI/wpf/mainmenu/Top/MainMenuUserControl.xaml");
            var xaml = UnityEngine.Resources.Load<NoesisXaml>("UI/wpf/mainmenu/Top/MainMenuUserControl");
            xaml.LoadComponent(this);
        }
I tried reference the NoesisXAML objects in my project but the Noesis.GUI.LoadComponent call still didn't find them for some reason. The tutorials seem fine using the asset path but they're also directly shoving them right into the Noesis View. I tried to get cute and make a stub in an included scene to just get the references in place. That just didn't seem to be enough for the path to be recognized from my title screen scene. I didn't poke it any further once I found that other method of loading them.

Taking it from resources does have its own down side. I have to make sure the output in the Resources folder is up-to-date. Before I had my project in the Unity directory tree, I had a batch file doing that. I'm not sure how I want to do it now with the Blend project in the same tree.
 
User avatar
jsantos
Site Admin
Posts: 3906
Joined: 20 Jan 2012, 17:18
Contact:

Re: Proper way to load compiled XAML at run time in Unity

29 Mar 2021, 20:47

We don't recommend using Resources folder. Just have your user controls located wherever you want, make sure .xaml and .cs have the same name and reference the .xaml from code like this.
private void InitializeComponent()
{
    Noesis.GUI.LoadComponent(this, "Assets/NoesisGUI/Samples/TicTacToe/MainWindow.xaml");
}
Whenever this user control is used in another XAML, our post processor will inject a dependency to the xaml and everything should work, all our examples are built like that.

If something is not working, please report a ticket with a minimal repro (for example, just the usercontrol and the xaml using it).

Who is online

Users browsing this forum: Ahrefs [Bot], Google [Bot] and 53 guests