pingping
Topic Author
Posts: 5
Joined: 25 Jul 2020, 00:59

Loading xamls (UserControls) without adding corresponding C++ classes

17 Nov 2021, 17:35

As I observed in the sample projects, we need to create C++ view classes to corresponding UserControls. The C++ class is only loading the xaml, and I found it cumbersome. I understand that it is necessary for Noesis when parsing the XAML markups. But can we have a solution where we do not need to do add these c++ classes?

I come-up with a solution where we need such XAML markup,
<view:UserAvatar />

I could create a custom control to load the xaml directly. (view:XamlLoaderControl is a Custom Control)
<view:XamlLoaderControl Source="/BlendProj;component/views/user_avatar.xaml" />

This way I wouldn't need to create UserAvatar.h/cpp classes or Noesis registration of these components.
I use Noesis::GUI::LoadXaml in Noesis and Application.LoadComponent in the C# code.
Although such solution works perfectly in Noesis, Blend-runtime, it is sometimes problematic in Blend designtime preview. I think using Application.LoadComponent requires building the project first and it is not reliable. Since we do not have much things to change how Blend is working, I start to consider doing some changes in Noesis.

I can imagine such solution that when Noesis is parsing xaml and when it finds a custom XML Markup (eg. <view:UserAvatar/>) and if it can't find the symbol definition, it can call some callback where we could load the xaml for that control manually (similar to XamlProvider or TextureProvider). This way we wouldn't need to write the c++ class that only loads the xaml. To be able to make this work, we would need to have a mapping between the name of xaml markup to the xaml file. But developer can solve that part the way they want.

Would it be possible to add such feature to the Noesis?

Tags:
 
User avatar
jsantos
Site Admin
Posts: 3338
Joined: 20 Jan 2012, 17:18
Contact:

Re: Loading xamls (UserControls) without adding corresponding C++ classes

17 Nov 2021, 18:40

There are two related features already implemented that could help here:

1. LoadContentAction for loading Xaml from Xaml itself.
2. Reflection::SetFallbackHandler for setting a callback invoked whenever there is a request from a type not already registered. From this callback you must register the new type using Factory::RegisterComponent, this is not exactly what you want, because in your case I think you want to create the new instance from the callback itself (calling LoadXaml)?
 
pingping
Topic Author
Posts: 5
Joined: 25 Jul 2020, 00:59

Re: Loading xamls (UserControls) without adding corresponding C++ classes

17 Nov 2021, 19:16

Thank you for the quick response.

The problem with the LoadContentAction:
1. It is not easy to use it for elements in the hierarchy
Does it mean I can use it like this?
<StackPanel>

<ContentControl>
    <b:Interaction.Triggers>
      <b:EventTrigger EventName="Loaded">
        <noesis:LoadContentAction Source="Content1.xaml" />
      </b:EventTrigger>
    </b:Interaction.Triggers>
  </ContentControl>
  
<ContentControl>
    <b:Interaction.Triggers>
      <b:EventTrigger EventName="Loaded">
        <noesis:LoadContentAction Source="Content2.xaml" />
      </b:EventTrigger>
    </b:Interaction.Triggers>
  </ContentControl>
  
</StackPanel>
instead of what I have
<StackPanel>
<view:XamlLoaderControl Source="Content1.xaml"/>
<view:XamlLoaderControl Source="Content2.xaml"/>
</StackPanel>
I think they would work the same under the hood. But the latter is simplier in xaml.

2. noesis:LoadContentAction is also using Application.LoadComponent in C# implementation. So, I would have exactly the same problem I am having with Blend design time.

Problem with Reflection::SetFallbackHandler:
This would still require writing C++ class for that User Control xaml. Because Reclection::GetType is going to check if the type is exist again after calling the callback. As you said we need to register the type in the callback via Factory::RegisterComponent.
But the idea of this fallback handler is similar to what I am looking for.
Instead of returning type, I would like to return the instance of the control. Because I could load the control manually with Noesis::GUI::LoadXaml and cast it to UserControl. Then it can be added to the hierarchy. In this case, I wouldn't need to write C++ class to just be able to load the xaml.
I am not sure how difficult it would be to implement such thing or if it is doable with current way of parsing xamls.
 
User avatar
jsantos
Site Admin
Posts: 3338
Joined: 20 Jan 2012, 17:18
Contact:

Re: Loading xamls (UserControls) without adding corresponding C++ classes

18 Nov 2021, 00:46

In this case, I wouldn't need to write C++ class to just be able to load the xaml.
I am not sure how difficult it would be to implement such thing or if it is doable with current way of parsing xamls.
Before exploring this alternative there is something I need to understand. It is true that you don't need to create a new class but you need a way to map the requested type to a given XAML, so at the end you are going to need recompiling for adding this to your internal map or whatever you have. If I am wrong could you please elaborate a bit more?
 
pingping
Topic Author
Posts: 5
Joined: 25 Jul 2020, 00:59

Re: Loading xamls (UserControls) without adding corresponding C++ classes

18 Nov 2021, 11:34

Yes, you are right.
My point is to not create C++ classes when we want to add new UserControl xamls. In the solution I propose we would need a mapping that maps <view:UserAvatar /> to its xaml path eg. "/BlendProj;component/assets/views/user_avatar.xaml".

This mapping could be constructed manually (or automatically) in the Blend project as a resource dictionary (view_mapping.xaml),
<ResourceDictionary>
<sys:String x:Key="view:UserAvatar">/BlendProj;component/assets/views/user_avatar.xaml</sys:String>
</ResourceDictionary>
Then we could read this xaml from C++ code where we handle that callback. This way we wouldn't need to touch or add C++ classes every time when we add new UserControl. And we wouldn't need to compile C++ project (the game).

Potentially the mapping file could be generated automatically when we run the Blend project. I can imagine a solution when we run the Blend project, it goes trough all xamls and if they contain UserControl as root node, then it means it is a UserControl, and it can be added to view_mapping.xaml automatically. (There can be other solutions too). Such solution could be part of NoesisGUIExtensions.dll

Other solution would be writing a Blend extension that watches file changes. And if a file added it could check if it is a UserControl and add it to the view_mapping.xaml automatically. But I am not sure if we are able to create custom extensions for Blend.
 
User avatar
jsantos
Site Admin
Posts: 3338
Joined: 20 Jan 2012, 17:18
Contact:

Re: Loading xamls (UserControls) without adding corresponding C++ classes

18 Nov 2021, 13:32

I see, you could even guess the XAML from the name of the class ("UserAvatar" -> "user_avatar.xaml") or something similar.

Could you please open a ticket about this (private if you need)? Let me think more about it and propose a solution.

Who is online

Users browsing this forum: No registered users and 2 guests