-
- cschedin_ewe
- Posts: 14
- Joined:
Best practices for Focus and input handling
Hey there,
I have been using Noesis for a game project for about 4 months now. By large I am finding it powerful. We have integrated it to our own C++ based engine.
I am struggling to understand how I'm expected to work with Focus handling. The game we are making is primarily aimed at Gamepad input, so this is an important topic for me as we will not be able to move focus with mouse on some platforms, meaning the Focus system must be robust and not drop focus or incorrectly placing focus when opening menus.
In our engine, we pre load XAMLs and create views, but they may not be visible until our visibility system tells them to start drawing.
I am working on a menu now that will at some point be given a list of options and be told to start showing. At this point I will want to set keyboard focus on the listbox of the menu.
However, I find I need to press down on the keyboard/gamepad once to give focus to the list before I can start navigating the list options.
I added an event listener for the Loaded event and fired a SetFocusAction within it, but I suppose the problem is that I may have misunderstood when the Loaded event is fired. I got the impression that it would fire when elements were added to the view (and that should happen after updating the viewmodel array of list options, right?), but I seem to be getting the Loaded event when first setting the view size, which happens only the first time it renders.
I'm attaching something similar to what I'm trying, but obviously I am using databinding for ItemsSource rather than hard coding the list options.
Do you have any suggestions for this?
I'm not sure if there's something wrong in our integration, or if I am thinking about focus the wrong way.
Cheers
I have been using Noesis for a game project for about 4 months now. By large I am finding it powerful. We have integrated it to our own C++ based engine.
I am struggling to understand how I'm expected to work with Focus handling. The game we are making is primarily aimed at Gamepad input, so this is an important topic for me as we will not be able to move focus with mouse on some platforms, meaning the Focus system must be robust and not drop focus or incorrectly placing focus when opening menus.
In our engine, we pre load XAMLs and create views, but they may not be visible until our visibility system tells them to start drawing.
I am working on a menu now that will at some point be given a list of options and be told to start showing. At this point I will want to set keyboard focus on the listbox of the menu.
However, I find I need to press down on the keyboard/gamepad once to give focus to the list before I can start navigating the list options.
I added an event listener for the Loaded event and fired a SetFocusAction within it, but I suppose the problem is that I may have misunderstood when the Loaded event is fired. I got the impression that it would fire when elements were added to the view (and that should happen after updating the viewmodel array of list options, right?), but I seem to be getting the Loaded event when first setting the view size, which happens only the first time it renders.
I'm attaching something similar to what I'm trying, but obviously I am using databinding for ItemsSource rather than hard coding the list options.
Code: Select all
<Grid
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:noesis="clr-namespace:NoesisGUIExtensions;assembly=Noesis.GUI.Extensions"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:b="http://schemas.microsoft.com/xaml/behaviors">
<ListBox
SelectedIndex="0"
Focusable="True"
HorizontalAlignment="Center"
VerticalAlignment="Stretch"
MaxWidth="600"
MaxHeight="800">
<ListBoxItem Content="Test 1" />
<ListBoxItem Content="Test 2" />
<ListBoxItem Content="Test 3" />
<i:Interaction.Triggers>
<b:EventTrigger EventName="Loaded">
<noesis:SetFocusAction />
</b:EventTrigger>
</i:Interaction.Triggers>
</ListBox>
</Grid>
I'm not sure if there's something wrong in our integration, or if I am thinking about focus the wrong way.
Cheers
-
- cschedin_ewe
- Posts: 14
- Joined:
Re: Best practices for Focus and input handling
After debugging and trying to add a custom Behavior to move focus when the listbox has received focus, I am still not succeeding.
It seems as listening for the Loaded event is the only time where everything will be properly populated and moving Focus works as I expect it to.
However the loaded event is only triggered once, when first displaying my view with connected viewmodel data.
This leads me to think that I am meant to unload a view when not in use, is that your intention?
For example; Let's say I'm making some interaction menu in a game. As I approach some game interaction and press a button, I want to display a navigatable menu.
Now as in our integration of Noesis, this menu would get loaded and the view created when loading into the game. However, that makes it impossible to rely on the Loaded event each time I open the menu anew.
Is the intention of Noesis that I unload the view when the menu closes, or is there another way to catch when data has been updated AND the layout tree has been fully populated?
I would prefer to not have to load/unload views as I worry about frame spikes or delays with displaying the views.
It seems as listening for the Loaded event is the only time where everything will be properly populated and moving Focus works as I expect it to.
However the loaded event is only triggered once, when first displaying my view with connected viewmodel data.
This leads me to think that I am meant to unload a view when not in use, is that your intention?
For example; Let's say I'm making some interaction menu in a game. As I approach some game interaction and press a button, I want to display a navigatable menu.
Now as in our integration of Noesis, this menu would get loaded and the view created when loading into the game. However, that makes it impossible to rely on the Loaded event each time I open the menu anew.
Is the intention of Noesis that I unload the view when the menu closes, or is there another way to catch when data has been updated AND the layout tree has been fully populated?
I would prefer to not have to load/unload views as I worry about frame spikes or delays with displaying the views.
-
-
sfernandez
Site Admin
- Posts: 3364
- Joined:
Re: Best practices for Focus and input handling
Hi,
If the menu is loaded once and then you're just hiding/showing it in order to interact with the menu, then you can't rely on the Loaded event (which triggers when the element is connected to the view).
The alternative is either use a DataTrigger for the IsVisible property of the element, or if your ViewModel already specifies some kind of state machine, then listen to changes in that property:
Have you tried something like that already?
If the menu is loaded once and then you're just hiding/showing it in order to interact with the menu, then you can't rely on the Loaded event (which triggers when the element is connected to the view).
The alternative is either use a DataTrigger for the IsVisible property of the element, or if your ViewModel already specifies some kind of state machine, then listen to changes in that property:
Code: Select all
<b:DataTrigger Binding="{Binding State}" Value="ShowMenuState">
<noesis:SetFocusAction TargetName="OptionsList"/>
</b:DataTrigger>-
- cschedin_ewe
- Posts: 14
- Joined:
Re: Best practices for Focus and input handling
Hey, thanks for the reply.
I have tried both methods but it won't work for me.
My ItemContainerStyle uses the IsSelected property to display the highlighted effect. This works fine, however it's navigation that's the problem.
It seems something else has focus when I show the menu, and using an event or datatrigger to set focus won't work.
I don't have access to the Noesis pdb's yet so I have not been able to step through and see what happens but basically I try to focus the listbox, then move focus down with the MoveFocusAction but this does not move focus to the first listbox item. It's not clear to me why that is, as this bug happens even when I am not changing the viewmodel (so when I open menu the 2nd time without changing the bound array).
And what about showing/hiding menus; What is your preferred method? Showing/Hiding or Loading/Unloading and relying on the Loaded event?
I have tried both methods but it won't work for me.
My ItemContainerStyle uses the IsSelected property to display the highlighted effect. This works fine, however it's navigation that's the problem.
It seems something else has focus when I show the menu, and using an event or datatrigger to set focus won't work.
I don't have access to the Noesis pdb's yet so I have not been able to step through and see what happens but basically I try to focus the listbox, then move focus down with the MoveFocusAction but this does not move focus to the first listbox item. It's not clear to me why that is, as this bug happens even when I am not changing the viewmodel (so when I open menu the 2nd time without changing the bound array).
And what about showing/hiding menus; What is your preferred method? Showing/Hiding or Loading/Unloading and relying on the Loaded event?
-
- cschedin_ewe
- Posts: 14
- Joined:
Re: Best practices for Focus and input handling
It seem I was able to solve the issue by adding a custom Behavior.
It sets a focus listener on the listbox, and when triggered it will try to move focus down.
I tried this last week, but the missing piece was calling
before moving focus.
I would still like an answer on my other question however, which is about recommendations for keeping Views in memory vs unloading/recreating the view when it becomes visible again.
I suppose it might be on a case by case basis depending on the complexity of the screen to avoid hitches when loading in large xaml hierarchies.
Code: Select all
<ListBox ItemsSource="{Binding Path=items}" SelectedIndex="0" x:Name="firstControl" Focusable="True" ItemContainerStyle="{StaticResource liStyle}" Height="1200"
KeyboardNavigation.DirectionalNavigation="Cycle">
<b:Interaction.Behaviors>
<noesis:ListboxFocusItemBehavior />
</b:Interaction.Behaviors>
</ListBox>
I tried this last week, but the missing piece was calling
Code: Select all
listBox->UpdateLayout();before moving focus.
I would still like an answer on my other question however, which is about recommendations for keeping Views in memory vs unloading/recreating the view when it becomes visible again.
I suppose it might be on a case by case basis depending on the complexity of the screen to avoid hitches when loading in large xaml hierarchies.
-
-
sfernandez
Site Admin
- Posts: 3364
- Joined:
Re: Best practices for Focus and input handling
This is because the ListBox is populated using data binding, right? so you cannot explicitly set the focus on the first ListBoxItem. And that is why you have to force the UpdateLayout(), so item containers are generated for the collection of items.It sets a focus listener on the listbox, and when triggered it will try to move focus down.
As you mention, it depends on the complexity of your screens. But usually is a combination of both approaches:I would still like an answer on my other question however, which is about recommendations for keeping Views in memory vs unloading/recreating the view when it becomes visible again.
I suppose it might be on a case by case basis depending on the complexity of the screen to avoid hitches when loading in large xaml hierarchies.
- For complex screens you just unload/load the whole screen into a container.
- Inside the screen (or screens with the same context), you just hide/show parts depending on the screen state.
Who is online
Users browsing this forum: No registered users and 1 guest