unvestigate
Topic Author
Posts: 32
Joined: 17 Jan 2018, 09:55

Sub-menus on separate xaml files?

24 Mar 2019, 12:23

Lets say I have a menu in a game, eg. your typical main menu where you have Start New Game, Load Game, Optons and Exit. If you click the options button the main menu is hidden and an options window is shown instead. If you click Back on the options menu you go back to the main menu.

How would you structure this? Do you have both the main menu buttons and the options menu window in the same xaml file and toggle visibility on/off at runtime, or do you put the main menu in one xaml file and the options menu in another? If you go the route of two xaml files, you also have to have two views loaded (assuming a native C++ engine here) and you have to make sure you switch between the views, routing input and rendering the active one etc, right? Also, does having two separate xamls (and by extension, I guess, two separate views) affect the possibility of animating the transition between the main menu and the options menu? Ie. do they have to be in the same xaml to be able to animate the transition easily?

Lastly, can I have the two menus in separate files, eg. to be able to edit them in Blend individually, but still have them both loaded into the same view at runtime?

Thanks!
 
User avatar
sfernandez
Site Admin
Posts: 2984
Joined: 22 Dec 2011, 19:20

Re: Sub-menus on separate xaml files?

25 Mar 2019, 12:29

There can be different approaches to this, for example you can take a look at our Menu3D sample where each screen is defined in a different xaml (UserControl), but all 3 screens (main menu, settings and start) are included in a parent xaml (main window), and then using data triggers to fire the transition animations between screens.

I recommend having a root xaml with a single View, and as many xamls (UserControls) as screens you need. Then you can load them dynamically using LoadXaml() to add them to the root xaml:
void ShowSettingsScreen()
{
  this.container.Content = (UserControl)Noesis.GUI.LoadXaml("SettingsScreen.xaml");
}
Or you can use data templates so based on the selected screen data type, a content control can show the appropriate screen:
<Grid
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  x:Name="Root">
  <Grid.Resources>
    <DataTemplate DataType="{x:Type local:MainMenuViewModel}">
      <local:MainMenuScreen/>
    </DataTemplate>
    <DataTemplate DataType="{x:Type local:SettingsViewModel}">
      <local:SettingsScreen/>
    </DataTemplate>
    ...
  <Grid.Resources>
  ...
  <ContentControl Content="{Binding SelectedScreen}"/>
  ...
</Grid>
I hope this helps.
 
unvestigate
Topic Author
Posts: 32
Joined: 17 Jan 2018, 09:55

Re: Sub-menus on separate xaml files?

26 Mar 2019, 19:40

Thank you, yes that is indeed very helpful. I started working on a menu system using the Menu3D sample as a base, and I have some follow-up questions. The main window in the sample plays an animation and some background music when it is loaded, and I want to do something similar. I use the following snippet for this:
<i:Interaction.Triggers>
    <i:EventTrigger EventName="Loaded">
        <ei:PlaySoundAction Source="some_sound_which_does_not_exist" Volume="1"/>
    </i:EventTrigger>
</i:Interaction.Triggers>
Don't worry about the weird-looking sound path. I want to make sure the event is triggered and my sound callback is called properly before hooking up an actual sound. My current problem is that I get the following error when loading the xaml file if I use the above snippet: Unknown type 'NoesisApp.Interaction'. Here are my questions:

1. I assume I get the error because I am not linking to NoesisApp and thus the Interaction classes have not been registered. Where does it get the 'NoesisApp.Interaction' type name? Is the core Noesis library hardwired to look for such an object type when using the interaction functionality in xaml? I am asking because I don't think I have used "NoesisApp' anywhere but still it complains about that type name, so I wonder where it comes from.

2. The NoesisApp library seems to contain a lot of code I don't need, such as the renderers, the window etc. I have my own versions of those already and it seems I only need the interaction functionality. Should I still link to NoesisApp or should I extract the code for the interaction functionality and build it into my own binaries?

Thank you for your help, so far Noesis seems very nice! I have worked with a few other UI libraries before and Noesis is a breath of fresh air in many ways!
 
unvestigate
Topic Author
Posts: 32
Joined: 17 Jan 2018, 09:55

Re: Sub-menus on separate xaml files?

27 Mar 2019, 09:19

Allright, I got a little further with this. Now I am linking to NoesisApp, and I have to decide how to register the classes found in the library. My first attempt was simply to call
NoesisApp::Launcher::RegisterAppComponents();
Before registering my own classes. This, however, resulted in a clash between the window registered by NoesisApp and my own window class:
"Reflection TypeId 'Window' for type '.?AVNoesisWindow@Slide@@' already used to register type '.?AVWindow@NoesisApp@@'"
Here we see the problem that NoesisApp, by default, registers a lot more than I need or want. My second attempt was extracting the code that registers the interactivity classes into my own app. Something like this. The header:
namespace Noesis
{
	class ComponentFactory;
}

// These are generated through the NS_REGISTER_REFLECTION, NS_INIT_PACKAGE and 
// NS_SHUTDOWN_PACKAGE macros on the cpp side.

extern "C" void NsRegisterReflectionAppInteractivity(Noesis::ComponentFactory*, bool);
extern "C" void NsInitPackageAppInteractivity();
extern "C" void NsShutdownPackageAppInteractivity();
And the cpp:
#include "NoesisAppInteractivityInit.h"

#include <NsCore/Package.h>
#include <NsCore/EnumConverter.h>
#include <NsApp/Interaction.h>
#include <NsApp/StyleInteraction.h>
#include <NsApp/TriggerCollection.h>
#include <NsApp/BehaviorCollection.h>
#include <NsApp/EventTrigger.h>
#include <NsApp/PropertyChangedTrigger.h>
#include <NsApp/DataTrigger.h>
#include <NsApp/KeyTrigger.h>
#include <NsApp/StoryboardCompletedTrigger.h>
#include <NsApp/TimerTrigger.h>
#include <NsApp/MouseDragElementBehavior.h>
#include <NsApp/TranslateZoomRotateBehavior.h>
#include <NsApp/ConditionBehavior.h>
#include <NsApp/ConditionalExpression.h>
#include <NsApp/ComparisonCondition.h>
#include <NsApp/GoToStateAction.h>
#include <NsApp/InvokeCommandAction.h>
#include <NsApp/ChangePropertyAction.h>
#include <NsApp/ControlStoryboardAction.h>
#include <NsApp/RemoveElementAction.h>
#include <NsApp/LaunchUriOrFileAction.h>
#include <NsApp/PlaySoundAction.h>
#include <NsApp/SetFocusAction.h>
#include <NsApp/SelectAction.h>
#include <NsApp/SelectAllAction.h>

using namespace Noesis;

////////////////////////////////////////////////////////////////////////////////////////////////////
NS_REGISTER_REFLECTION(App, Interactivity)
{
	// Force creation of metadata
	TypeOf<NoesisApp::Interaction>();
	TypeOf<NoesisApp::StyleInteraction>();

	NS_REGISTER_COMPONENT(NoesisApp::BehaviorCollection)
	NS_REGISTER_COMPONENT(NoesisApp::TriggerCollection)
	NS_REGISTER_COMPONENT(NoesisApp::StyleBehaviorCollection)
	NS_REGISTER_COMPONENT(NoesisApp::StyleTriggerCollection)
	NS_REGISTER_COMPONENT(NoesisApp::EventTrigger)
	NS_REGISTER_COMPONENT(NoesisApp::PropertyChangedTrigger)
	NS_REGISTER_COMPONENT(NoesisApp::DataTrigger)
	NS_REGISTER_COMPONENT(NoesisApp::KeyTrigger)
	NS_REGISTER_COMPONENT(NoesisApp::StoryboardCompletedTrigger)
	NS_REGISTER_COMPONENT(NoesisApp::TimerTrigger)
	NS_REGISTER_COMPONENT(NoesisApp::MouseDragElementBehavior)
	NS_REGISTER_COMPONENT(NoesisApp::TranslateZoomRotateBehavior)
	NS_REGISTER_COMPONENT(NoesisApp::ConditionBehavior)
	NS_REGISTER_COMPONENT(NoesisApp::ConditionalExpression)
	NS_REGISTER_COMPONENT(NoesisApp::ComparisonCondition)
	NS_REGISTER_COMPONENT(NoesisApp::GoToStateAction)
	NS_REGISTER_COMPONENT(NoesisApp::InvokeCommandAction)
	NS_REGISTER_COMPONENT(NoesisApp::ChangePropertyAction)
	NS_REGISTER_COMPONENT(NoesisApp::ControlStoryboardAction)
	NS_REGISTER_COMPONENT(NoesisApp::RemoveElementAction)
	NS_REGISTER_COMPONENT(NoesisApp::LaunchUriOrFileAction)
	NS_REGISTER_COMPONENT(NoesisApp::PlaySoundAction)
	NS_REGISTER_COMPONENT(NoesisApp::SetFocusAction)
	NS_REGISTER_COMPONENT(NoesisApp::SelectAction)
	NS_REGISTER_COMPONENT(NoesisApp::SelectAllAction)
	NS_REGISTER_COMPONENT(EnumConverter<NoesisApp::ComparisonConditionType>)
	NS_REGISTER_COMPONENT(EnumConverter<NoesisApp::ForwardChaining>)
	NS_REGISTER_COMPONENT(EnumConverter<NoesisApp::KeyTriggerFiredOn>)
	NS_REGISTER_COMPONENT(EnumConverter<NoesisApp::ControlStoryboardOption>)
}

////////////////////////////////////////////////////////////////////////////////////////////////////
NS_INIT_PACKAGE(App, Interactivity)
{
}

////////////////////////////////////////////////////////////////////////////////////////////////////
NS_SHUTDOWN_PACKAGE(App, Interactivity)
{
}
Then I can simply call
NsRegisterReflectionAppInteractivity(nullptr, true);
to register the classes. This gave me the following linker errors:
Error	LNK2019	unresolved external symbol "public: static class Noesis::TypeClass const * __cdecl NoesisApp::StyleBehaviorCollection::StaticGetClassType(struct Noesis::TypeTag<class NoesisApp::StyleBehaviorCollection> *)" (?StaticGetClassType@StyleBehaviorCollection@NoesisApp@@SAPEBVTypeClass@Noesis@@PEAU?$TypeTag@VStyleBehaviorCollection@NoesisApp@@@4@@Z) referenced in function "class Noesis::TypeClass const * __cdecl Noesis::TypeOf<class NoesisApp::StyleBehaviorCollection>(void)" (??$TypeOf@VStyleBehaviorCollection@NoesisApp@@@Noesis@@YAPEBVTypeClass@0@XZ)	Slide	D:\Projects\Basis\build\Slide\NoesisAppInteractivityInit.obj	1	

Error	LNK2019	unresolved external symbol "public: static class Noesis::TypeClass const * __cdecl NoesisApp::StyleTriggerCollection::StaticGetClassType(struct Noesis::TypeTag<class NoesisApp::StyleTriggerCollection> *)" (?StaticGetClassType@StyleTriggerCollection@NoesisApp@@SAPEBVTypeClass@Noesis@@PEAU?$TypeTag@VStyleTriggerCollection@NoesisApp@@@4@@Z) referenced in function "class Noesis::TypeClass const * __cdecl Noesis::TypeOf<class NoesisApp::StyleTriggerCollection>(void)" (??$TypeOf@VStyleTriggerCollection@NoesisApp@@@Noesis@@YAPEBVTypeClass@0@XZ)	Slide	D:\Projects\Basis\build\Slide\NoesisAppInteractivityInit.obj	1	

Error	LNK2019	unresolved external symbol "public: virtual class Noesis::TypeClass const * __cdecl NoesisApp::StyleBehaviorCollection::GetClassType(void)const " (?GetClassType@StyleBehaviorCollection@NoesisApp@@UEBAPEBVTypeClass@Noesis@@XZ) referenced in function "[thunk]:public: virtual class Noesis::TypeClass const * __cdecl NoesisApp::StyleBehaviorCollection::GetClassType`adjustor{24}' (void)const " (?GetClassType@StyleBehaviorCollection@NoesisApp@@WBI@EBAPEBVTypeClass@Noesis@@XZ)	Slide	D:\Projects\Basis\build\Slide\NoesisAppInteractivityInit.obj	1	

Error	LNK2019	unresolved external symbol "public: virtual class Noesis::TypeClass const * __cdecl NoesisApp::StyleTriggerCollection::GetClassType(void)const " (?GetClassType@StyleTriggerCollection@NoesisApp@@UEBAPEBVTypeClass@Noesis@@XZ) referenced in function "[thunk]:public: virtual class Noesis::TypeClass const * __cdecl NoesisApp::StyleTriggerCollection::GetClassType`adjustor{24}' (void)const " (?GetClassType@StyleTriggerCollection@NoesisApp@@WBI@EBAPEBVTypeClass@Noesis@@XZ)	Slide	D:\Projects\Basis\build\Slide\NoesisAppInteractivityInit.obj	1	
If I comment out the following two lines it now builds:
NS_REGISTER_COMPONENT(NoesisApp::StyleBehaviorCollection)
NS_REGISTER_COMPONENT(NoesisApp::StyleTriggerCollection)
I am not sure if I actually will need those two collections later on, but this seems like an awful lot of hoops to jump through to get it working, so I am back to wondering if I am doing this all wrong? Is there an easier way to register just a few of the NsApp classes?

One way to handle this would be to pull out the actual code from NsApp and bring it into my own app. However, I would like to avoid that if possible as it makes updating to newer versions of Noesis more work. Another way would be to make RegisterAppComponents() only register the classes I want/need and rebuild the NsApp library locally. Is that perhaps the best way to handle this?

Thanks!
 
User avatar
sfernandez
Site Admin
Posts: 2984
Joined: 22 Dec 2011, 19:20

Re: Sub-menus on separate xaml files?

27 Mar 2019, 11:01

If you are using Unity, NoesisApp is not required, you can just include in your project the folder NoesisGUI/Samples/Interactivity/ from our Unity package.

If you are working with the Native C++ SDK it is not necessary to link against NoesisApp.dll, we provide all the source code for the application framework as reference, so you can take what you need to your application and build it along with it. For example, you have the source code for the Interactivity package under Src/Packages/App/Interactivity/ folder. You just need to register the interactivity classes as you will do for your own application classes (https://www.noesisengine.com/docs/Gui.C ... ng-classes):
NsRegisterComponent<MyGame::App>();
NsRegisterComponent<MyGame::MainWindow>();
...
NsRegisterComponent<NoesisApp::BehaviorCollection>();
NsRegisterComponent<NoesisApp::TriggerCollection>();
NsRegisterComponent<NoesisApp::StyleBehaviorCollection>();
NsRegisterComponent<NoesisApp::StyleTriggerCollection>();
NsRegisterComponent<NoesisApp::EventTrigger>();
NsRegisterComponent<NoesisApp::PropertyChangedTrigger>();
NsRegisterComponent<NoesisApp::DataTrigger>();
NsRegisterComponent<NoesisApp::KeyTrigger>();
NsRegisterComponent<NoesisApp::StoryboardCompletedTrigger>();
NsRegisterComponent<NoesisApp::TimerTrigger>();
NsRegisterComponent<NoesisApp::MouseDragElementBehavior>();
NsRegisterComponent<NoesisApp::TranslateZoomRotateBehavior>();
NsRegisterComponent<NoesisApp::ConditionBehavior>();
NsRegisterComponent<NoesisApp::ConditionalExpression>();
NsRegisterComponent<NoesisApp::ComparisonCondition>();
NsRegisterComponent<NoesisApp::GoToStateAction>();
NsRegisterComponent<NoesisApp::InvokeCommandAction>();
NsRegisterComponent<NoesisApp::ChangePropertyAction>();
NsRegisterComponent<NoesisApp::ControlStoryboardAction>();
NsRegisterComponent<NoesisApp::RemoveElementAction>();
NsRegisterComponent<NoesisApp::LaunchUriOrFileAction>();
NsRegisterComponent<NoesisApp::PlaySoundAction>();
NsRegisterComponent<NoesisApp::SetFocusAction>();
NsRegisterComponent<NoesisApp::SelectAction>();
NsRegisterComponent<NoesisApp::SelectAllAction>();
NsRegisterComponent<Noesis::EnumConverter<NoesisApp::ComparisonConditionType>>();
NsRegisterComponent<Noesis::EnumConverter<NoesisApp::ForwardChaining>>();
NsRegisterComponent<Noesis::EnumConverter<NoesisApp::KeyTriggerFiredOn>>();
NsRegisterComponent<Noesis::EnumConverter<NoesisApp::ControlStoryboardOption>>();
Noesis::TypeOf<NoesisApp::Interaction>(); // Force the creation of its reflection type
Noesis::TypeOf<NoesisApp::StyleInteraction>(); // Force the creation of its reflection type
Please let me know if you need further assistance setting up this.
 
unvestigate
Topic Author
Posts: 32
Joined: 17 Jan 2018, 09:55

Re: Sub-menus on separate xaml files?

27 Mar 2019, 11:11

Well, I listed some reasons for why I might not want to do that, but it's fine I'll include the code in my game.

Thanks!
 
User avatar
jsantos
Site Admin
Posts: 3906
Joined: 20 Jan 2012, 17:18
Contact:

Re: Sub-menus on separate xaml files?

27 Mar 2019, 13:40

Hi! I want to clarify a few things in this thread.

Effectively, we do not recommend using NoesisApp library in your projects because it was designed exclusively for our samples. So, we don't have plans to extend it to support all scenarios. There are many ways, our Display implementations could be improved for example, but each client must adapt and improve the code accordingly. Even if the implementations we provide are enough for you, NoesisApp includes many things, as you discovered, that you don't need. So, we recommend picking the .cpp files you exactly need, include them into your project and register them in the factory as you are doing with the rest of your classes. Following this way, you can always update the SDK and the corresponding .cpp's from NoesisApp will also be updated into your project.

If you find this a bit complex, and you want to use NoesisApp as is, then I recommend changing the class names that are conflicting
1. I assume I get the error because I am not linking to NoesisApp and thus the Interaction classes have not been registered. Where does it get the 'NoesisApp.Interaction' type name? Is the core Noesis library hardwired to look for such an object type when using the interaction functionality in xaml? I am asking because I don't think I have used "NoesisApp' anywhere but still it complains about that type name, so I wonder where it comes from.
The namespaces i: and ei: are automatically mapped to NoesisApp. If you create your own behaviors you shoudn't use those namespaces.
I am not sure if I actually will need those two collections later on, but this seems like an awful lot of hoops to jump through to get it working, so I am back to wondering if I am doing this all wrong? Is there an easier way to register just a few of the NsApp classes?
Not sure why you are getting those linker errors, maybe you forgot to include the corresponding sources? Anyway, I recommend registering only the things you really need. And keep adding as your project grows. Registering classes in the factory, even if you don't use them, do increase the binary size of your application.

As always, we are open to suggestions here. For example, we have been suggested many times that NoesisApp should be a static library. That's something we are considering although I don't think it will change much the scenario described here.
 
unvestigate
Topic Author
Posts: 32
Joined: 17 Jan 2018, 09:55

Re: Sub-menus on separate xaml files?

27 Mar 2019, 14:10

Thanks for the clarifications. The current setup is just fine. I was mostly asking because I was afraid I was doing things the "wrong way" and I would have to change it later on.

Regarding the linker errors, I am not sure if this is the problem but I noticed the StyleBehaviorCollection and StyleTriggerCollection don't have the NS_APP_INTERACTIVITY_API specifier, so I guess they were not exported from the dll...?
The namespaces i: and ei: are automatically mapped to NoesisApp. If you create your own behaviors you shoudn't use those namespaces.
Yeah, I figured you had something like this going on. It might be worth adding this to the documentation somewhere (unless it already is and I just missed it) because I spent a bit of time going through my solution trying to spot the place where I had copy-pasted a reference to NoesisApp, before I realized I had not registered the classes and it really had nothing to do with NoesisApp (other than the fact that the classes are included in NoesisApp for the samples).

FWIW I included all the interaction sources in my game project and after defining NS_APP_INTERACTIVITY_PRIVATE everything now builds, even StyleBehaviorCollection and StyleTriggerCollection.

Thanks!
 
User avatar
jsantos
Site Admin
Posts: 3906
Joined: 20 Jan 2012, 17:18
Contact:

Re: Sub-menus on separate xaml files?

27 Mar 2019, 14:53

FWIW I included all the interaction sources in my game project and after defining NS_APP_INTERACTIVITY_PRIVATE everything now builds, even StyleBehaviorCollection and StyleTriggerCollection.
Good point about NS_APP_INTERACTIVITY_PRIVATE, that must be also documented.

Who is online

Users browsing this forum: No registered users and 94 guests