View Issue Details

IDProjectCategoryView StatusLast Update
0002196NoesisGUIC++ SDKpublic2022-03-04 12:05
Reporterlowprofile Assigned Tojsantos  
PrioritynormalSeverityfeature 
Status assignedResolutionopen 
Product Version3.1 
Summary0002196: Create a callback allows loading UserControl xamls when the Control type is not found while parsing xamls hierarchy
Description

Currently we need to create C++ class for all UserControls that we use in the hierarchy. And usually that C++ class only do loading the corresponding UserControl xaml.
Could we have a solution that there is a callback that developer can handle, that is called when there is a control type found undefined during parsing xamls?

Details are described in this forum thread.
https://www.noesisengine.com/forums/viewtopic.php?f=3&t=2477&p=13589#p13589

Attached Files
PlatformAny

Activities

jsantos

jsantos

2021-11-19 11:04

manager   ~0007591

Thanks for the report, you have access to the source code right? I mean, I can send you a patch for testing things.

lowprofile

lowprofile

2021-11-19 12:27

reporter   ~0007592

Yes, we have the source code. We could test if you send a patch.

jsantos

jsantos

2021-12-06 17:30

manager   ~0007656

Last edited: 2022-01-05 15:52

Something as simple as the attached patch should work.

Right now, there is a bit of inefficiency because for the implementation of Factory::IsComponentRegistered we need to also invoke the custom callback just for checking the returned object and then just discard. I think we could get rid of IsComponentRegistered. But let's experiment with this first.

Factory.patch (2,230 bytes)   
Index: Include/NsCore/Factory.h
===================================================================
--- Include/NsCore/Factory.h	(revision 10984)
+++ Include/NsCore/Factory.h	(working copy)
@@ -35,6 +35,9 @@
 /// Creates an instance of the specified component 
 NS_CORE_KERNEL_API Ptr<BaseComponent> CreateComponent(Symbol name);
 
+typedef Ptr<BaseComponent> (*FallbackHandler)(Symbol name);
+NS_CORE_KERNEL_API void SetFallbackHandler(FallbackHandler handler);
+
 /// Registers a component
 typedef BaseComponent* (*CreatorFn)(Symbol name);
 NS_CORE_KERNEL_API void RegisterComponent(Symbol name, Symbol category, CreatorFn func);
Index: Src/Factory.cpp
===================================================================
--- Src/Factory.cpp	(revision 10984)
+++ Src/Factory.cpp	(working copy)
@@ -27,7 +27,9 @@
 typedef HashMap<Symbol, Vector<Symbol>> CategoryMap;
 static CategoryMap gCategories;
 
+static Factory::FallbackHandler gFallbackHandler;
 
+
 ////////////////////////////////////////////////////////////////////////////////////////////////////
 static ComponentMap::ConstIterator FallbackFind(Symbol name)
 {
@@ -44,7 +46,7 @@
 ////////////////////////////////////////////////////////////////////////////////////////////////////
 bool Factory::IsComponentRegistered(Symbol name)
 {
-    return FallbackFind(name) != gComponents.End();
+    return FallbackFind(name) != gComponents.End() || (gFallbackHandler && gFallbackHandler(name));
 }
 
 ////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -64,10 +66,21 @@
         return *(it->value(name));
     }
 
+    if (gFallbackHandler != nullptr)
+    {
+        return gFallbackHandler(name);
+    }
+
     return nullptr;
 }
 
 ////////////////////////////////////////////////////////////////////////////////////////////////////
+void Factory::SetFallbackHandler(FallbackHandler handler)
+{
+    gFallbackHandler = handler;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
 void Factory::RegisterComponent(Symbol name, Symbol category, Factory::CreatorFn func)
 {
     NS_ASSERT(!name.IsNull());
Factory.patch (2,230 bytes)   
lowprofile

lowprofile

2022-01-11 14:27

reporter   ~0007724

Last edited: 2022-01-11 14:28

After applying the patch, I noticed that the callback is not called. I investigated the source code and saw that there is an early return if Reflection::GetType(typeId) returns nullptr in XmlContext.cpp line 823. I fixed this part by adding if IsComponentRegistered. Then the callback was called properly. I was using Noesis::GUI::LoadXaml in the callback. But it wasn't showing the loaded xaml in the hierarchy. Would be great if you could test it.

I think we should have 2 callbacks. One is for to be used in the IsComponentRegistered that checks if view xaml could be loaded (without loading it). And the second callback from Factory::CreateComponent to load the xaml.

lowprofile

lowprofile

2022-01-13 13:45

reporter   ~0007731

I have changed the source code in XamlContext.cpp and It works now. I will send the solution to you. You might want to check it if it has any side effects.

jsantos

jsantos

2022-01-13 17:23

manager   ~0007732

Last edited: 2022-01-13 17:24

We want to remove all kind of "IsComponentRegistered" or "IsTypeRegistered" API to simplify everything a bit but I still didn't have time to think about it.

Yes, please, if you could attach a patch with the changes in all your files, that will definitely help toward having this feature officially supported.

Thank you!

lowprofile

lowprofile

2022-01-17 18:16

reporter   ~0007741

Last edited: 2022-01-21 14:22

I made very minimal changes and it works.
I shouldn't put Assert for typeId. Because type will be always come from the loaded xaml root element. Which is mostly UserControl.

noesis.diff.txt (1,908 bytes)   
==== //Noesis/NoesisSDK/Native/Src/Packages/Core/Kernel/Include/NsCore/Factory.h#2 (text) - //Noesis/NoesisSDK/Native/Src/Packages/Core/Kernel/Include/NsCore/Factory.h#1 (text) ==== content
13c13
< #include <functional>
---
> 
38,43d37
< // Set create component callback
< using FallbackHandler = std::function<Ptr<BaseComponent>(Symbol const name)>;
< NS_CORE_KERNEL_API void SetFallbackHandler(FallbackHandler handler);
< 
==== //Noesis/NoesisSDK/Native/Src/Packages/Core/Kernel/Src/Factory.cpp#2 (text) - //Noesis/NoesisSDK/Native/Src/Packages/Core/Kernel/Src/Factory.cpp#1 (text) ==== content
30,32d29
< static Factory::FallbackHandler gFallbackHandler;
70,77d66
< // Call callback to create component
< 	if (gFallbackHandler != nullptr)
< 	{
< 		return gFallbackHandler(name);
< 	}
< 
82,88d70
< void Factory::SetFallbackHandler(FallbackHandler handler)
< {
< 	gFallbackHandler = handler;
< }
< ////////////////////////////////////////////////////////////////////////////////////////////////////
==== //Noesis/NoesisSDK/Native/Src/Packages/Gui/Core/Src/XamlContext.cpp#2 (text) - //Noesis/NoesisSDK/Native/Src/Packages/Gui/Core/Src/XamlContext.cpp#1 (text) ==== content
822,841c822
< 	const Type* type = Reflection::GetType(typeId);
< 	Ptr<BaseComponent> instance;
< 
< // Call the factory create component that contains a fallback. This way we can load xamls 
< // without having corresponding c++ classes (without registered symbols)
< 	if (type == 0)
< 	{
< 		instance = Factory::CreateComponent(typeId);
< 
< 		if (instance != nullptr)
< 		{
< 			type = Reflection::GetType(instance->GetClassType()->GetTypeId());
< 			NS_ASSERT(instance->GetClassType()->GetTypeId() == typeId);
< 
< 			CheckTemplateOpen(instance, mAmbient);
< 		}
< 	}
< 
---
>     const Type* type = Reflection::GetType(typeId);
856a838,839
>     Ptr<BaseComponent> instance;
> 
noesis.diff.txt (1,908 bytes)   
jsantos

jsantos

2022-01-31 16:07

manager   ~0007759

Thanks for the patch, I will review it as soon as possible.

Issue History

Date Modified Username Field Change
2021-11-18 14:42 lowprofile New Issue
2021-11-18 14:42 lowprofile Tag Attached: C#
2021-11-18 14:42 lowprofile Tag Attached: C++
2021-11-18 14:42 lowprofile Tag Attached: xaml
2021-11-19 11:00 jsantos Assigned To => jsantos
2021-11-19 11:00 jsantos Status new => assigned
2021-11-19 11:00 jsantos Target Version => 3.1.2
2021-11-19 11:04 jsantos Note Added: 0007591
2021-11-19 11:04 jsantos Status assigned => feedback
2021-11-19 12:27 lowprofile Note Added: 0007592
2021-11-19 12:27 lowprofile Status feedback => assigned
2021-12-06 17:24 jsantos Target Version 3.1.2 =>
2021-12-06 17:24 jsantos View Status public => private
2021-12-06 17:26 jsantos File Added: Factory.patch
2021-12-06 17:27 jsantos Status assigned => feedback
2021-12-06 17:29 jsantos File Deleted: Factory.patch
2021-12-06 17:30 jsantos File Added: Factory.patch
2021-12-06 17:30 jsantos Note Added: 0007656
2022-01-05 15:52 jsantos View Status private => public
2022-01-05 15:52 jsantos Note View State: 0007592: public
2022-01-05 15:52 jsantos Note Edited: 0007656
2022-01-11 14:27 lowprofile Note Added: 0007724
2022-01-11 14:27 lowprofile Status feedback => assigned
2022-01-11 14:28 lowprofile Note Edited: 0007724
2022-01-13 13:45 lowprofile Note Added: 0007731
2022-01-13 17:23 jsantos Note Added: 0007732
2022-01-13 17:23 jsantos Status assigned => feedback
2022-01-13 17:24 jsantos Note Edited: 0007732
2022-01-13 17:24 jsantos Note Edited: 0007732
2022-01-17 18:16 lowprofile File Added: noesis.diff.txt
2022-01-17 18:16 lowprofile Note Added: 0007741
2022-01-17 18:16 lowprofile Status feedback => assigned
2022-01-21 14:22 lowprofile Note Edited: 0007741
2022-01-31 16:07 jsantos Note Added: 0007759