- unvestigate
- Posts: 32
- Joined:
Sub-menus on separate xaml files?
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!
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!
-
sfernandez
Site Admin
- Posts: 2984
- Joined:
Re: Sub-menus on separate xaml files?
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:
Or you can use data templates so based on the selected screen data type, a content control can show the appropriate screen:
I hope this helps.
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:
Code: Select all
void ShowSettingsScreen()
{
this.container.Content = (UserControl)Noesis.GUI.LoadXaml("SettingsScreen.xaml");
}
Code: Select all
<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>
- unvestigate
- Posts: 32
- Joined:
Re: Sub-menus on separate xaml files?
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:
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!
Code: Select all
<i:Interaction.Triggers>
<i:EventTrigger EventName="Loaded">
<ei:PlaySoundAction Source="some_sound_which_does_not_exist" Volume="1"/>
</i:EventTrigger>
</i:Interaction.Triggers>
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
- Posts: 32
- Joined:
Re: Sub-menus on separate xaml files?
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
Before registering my own classes. This, however, resulted in a clash between the window registered by NoesisApp and my own window class:
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:
And the cpp:
Then I can simply call
to register the classes. This gave me the following linker errors:
If I comment out the following two lines it now builds:
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!
Code: Select all
NoesisApp::Launcher::RegisterAppComponents();
Code: Select all
"Reflection TypeId 'Window' for type '.?AVNoesisWindow@Slide@@' already used to register type '.?AVWindow@NoesisApp@@'"
Code: Select all
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();
Code: Select all
#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)
{
}
Code: Select all
NsRegisterReflectionAppInteractivity(nullptr, true);
Code: Select all
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
Code: Select all
NS_REGISTER_COMPONENT(NoesisApp::StyleBehaviorCollection)
NS_REGISTER_COMPONENT(NoesisApp::StyleTriggerCollection)
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!
-
sfernandez
Site Admin
- Posts: 2984
- Joined:
Re: Sub-menus on separate xaml files?
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):
Please let me know if you need further assistance setting up this.
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):
Code: Select all
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
- unvestigate
- Posts: 32
- Joined:
Re: Sub-menus on separate xaml files?
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!
Thanks!
Re: Sub-menus on separate xaml files?
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
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.
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
The namespaces i: and ei: are automatically mapped to NoesisApp. If you create your own behaviors you shoudn't use those namespaces.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.
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.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?
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
- Posts: 32
- Joined:
Re: Sub-menus on separate xaml files?
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...?
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!
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...?
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).The namespaces i: and ei: are automatically mapped to NoesisApp. If you create your own behaviors you shoudn't use those namespaces.
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!
Re: Sub-menus on separate xaml files?
Good point about NS_APP_INTERACTIVITY_PRIVATE, that must be also documented.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.
Who is online
Users browsing this forum: No registered users and 94 guests