Tutorial: Handling UI navigation with MVVM and Common Activatable Widgets

This tutorial shows how to handle UI navigation on a screen in a simple and flexible way, using MVVM (the Model View ViewModel pattern) to create a Selection View Model and Common Activatable Widgets to manage focus. The process requires zero coding, and will be focused on UMG and blueprint-based MVVM.

We will implement a focus-based navigation in a simple screen where elements like lists, tiles and buttons communicate with each other using the Selection View Model and with the help of Common Activatable Widgets.

https://dev.epicgames.com/community/learning/tutorials/ep4k/unreal-engine-handling-ui-navigation-with-mvvm-and-common-activatable-widgets

Excellent tutorial, thank you. wish for more cause the 2023 talk is hard to follow for newcomers.

1 Like

Hi,
I finished the tutorial and when I press the button “Equip” or “Mark as Junk” without triggering the modal, the selected Item loses focus. Or when I click somewhere on the screen the item loses focus too. Is there a way to keep the focus on the item after pressing on the screen/button?

1 Like

Hello! Great catch.
The whole keyboard-mouse input management in UE isn’t handled the same way it’s handled with gamepad unfortunately, which means:

  • When you switch between mouse and gamepad, GetDesiredFocusTarget() is called and focus is re-evaluated. This doesn’t happen when you switch between mouse and keyboard. That’s because UE assumes you might still be using mouse-based navigation alongside keyboard shortcuts.
  • This is annoying when we want to implement a focus-based navigation, because we have no way of automatically refreshing the focus when switching from mouse to keyboard.

The other annoying thing is that when you click on a non-focusable widget (like a background image or border, or even a button that is hit-testable but not focusable, like our Equip and Junk buttons), Unreal sets focus to the viewport instead of maintaining focus within the UI.
Then, when you switch to keyboard, no widget is focused, so navigation doesn’t work, but if you switch to gamepad, Unreal detects an input method change, so it will trigger a focus re-evaluation calling the various GetDesiredFocusTarget() functions.

I can tell you in advance that there is no elegant way of solving this that I know of (and I suppose it’s not a surprise that in many games keyboard navigation is poorly supported), but there are still a couple of workarounds we can implement that use our SelectionVM and GetDesiredFocusTarget().

So there are 2 issues we need to fix:

  1. not lose focus when clicking on a background element, like a background image or the text in the item details panel
  2. not lose focus when clicking on a non-focusable button (the Equip and Junk buttons)

keeping in mind that:

  1. we want to avoid using events and delegates, keeping loose dependencies
  2. we want to avoid calling SetFocus() and instead prefer RequestRefreshFocus() and GetDesiredFocusTarget()

So here’s what we’re going to do:

  1. Add a utility function in the SelectionVM to request a focus refresh (this is so that any widget might request a focus refresh, and not only Common Activatable Widgets)
  2. Add a new FieldNotify property in the SelectionVM so that the widgets that can handle focus can also listen to external refresh focus requests from other widgets
  3. Introduce a FocusCatcher button to catch click events to the inventory background. This way we can catch the focus and redirect it before losing it
  4. Have our non-focusable buttons use the new utility function in the SelectionVM to re-evaluate the focus when they’re clicked, instead of just allowing Slate to panic

So let’s go:

  1. In the SelectionVM view model class, add the new function RequestRefreshFocus() and a new property bool FocusRefreshRequested
    image
  2. In WBP_Inventory add a new button to the hierarchy (Button_FocusCatcher) that spans the whole viewport, set it as Focusable and Visible

    image
    image
    image
  3. When the new button is clicked (= when we click somewhere on the screen), we now call the RequestRefreshFocus() function of the SelectionVM
  4. We now create a new function in WBP_Inventory to listen to the View Binding of our new property. We call this ForceFocusEvaluation() and it will take the new property as input. If the bool is true, means we have a focus refresh request, so we can now use a widget that is Common Activatable Widget to actually call the proper RequestRefreshFocus() function of activatable widgets.
    But there’s a catch! One thing I haven’t mentioned in the tutorial (didn’t want to overload with information) is that RequestRefreshFocus() will trigger a focus re-evaluation ONLY if requested by the leaf-most active activatable widget. What does this mean? It means that in our case our activatable widgets are WBP_Inventory and WBP_Category, and the leaf-most active is WBP_Category (because it’s deeper in the hierarchy). So if we call RequestRefreshFocus() from WBP_Inventory, nothing will happen, because WBP_Inventory isn’t our leaf-most active widget. So instead we need to call it from WBP_Category.
    So we can either add our ForceFocusEvaluation() function to WBP_Category, or we can just implement the function in a way that it will call RequestRefreshFocus() on WBP_Category instead of self - which is what I chose for the screenshot.
  5. We can now create the view binding that binds the SelectionVM property to the ForceFocusEvaluation() function
    image

So this part takes case of the case when you click somewhere on a screen. You’ll now see that when you click around instead of losing focus, the focus will be refresh to the currently selected item tile.

Next is solving the bug when clicking on the Equip and Junk buttons.

  1. We open WBP_ItemDetails and simply call RequestRefreshFocus() of the SelectionVM on the OnCliked events of both buttons.

And this should fix those issues! As I said, not the most elegant solution, but should do the trick for the moment. At Epic we’re discussing focus issues and how to improve this on a regular basis, so I hope we’ll get to better keyboard support as soon as possible.
Let me know how this goes - I might add this as an appendix to the tutorial.

1 Like

Hello! I’m glad this was helpful.
I’m considering making a new tutorial using the same project, but instead of showing how to use MVVM to handle navigation, I would show how to use MVVM to populate our widgets. So it would basically be creating view bindings, functions, conversion functions and so on.
Would that be helpful?

2 Likes

Thanks for the detailed response. It works like charm.

1 Like

Thank you very much for this tutorial! It’s a very good resource! :smiley:

It would be nice to delve deeper into the topic of resolvers. Specifically, how to use them to retrieve viewmodels in a multiplayer context where I need to display information about other players.

1 Like

Hello! Thanks for the feedback, I noted it down as a follow-up topic!

1 Like

yes! that would be very helpful Irene!

1 Like

+1 on extra tutorial about how to fill the views with the data. (or how to set this up…I am checking the files with your tutorial, and have the feeling there is still quite some BP graphs to get everything working)

1 Like

Hi Irene,

I have a question regarding how unral handles unused ViewModels. For example: When initializing them on a Widget creation each time it loads an inventory UI, The best way i have found so far is to create a viewmodel for ac item when activating the widget. Problem is creating a new viewmodel for each item everytime that ui is activated. I dont see any options to "destroy the viewmodel when you deactivate the widget, so in theory each viewmodel is still somewhere in memory. COuld you elaborate a bit more on how to reference a large amount of viewmodels instead of having to recreate them every time? Or does unreal garbage collect somewhere behind the scenes.

Thanks!

Simon

Am the the only one confused by this tutorial? Would have wanted to see how MVVM works in a simple practical example instead of hearing basic explanations of icons you see on the screen?

Personally could not find out what MVVM is used for after watching 3 videos. “We see an rpg fantasy inventory screen” yeah we see, please move on and show how to use MVVM.

Hello, excellent tutorial, this was very helpful for seeing a more practical usecase for setting up and sharing data with viewmodels.

I was wondering, what methods do y’all use for resolving VM methods? You mention an alternative to using global viewmodels (something about a technique someone figured out in Orlando?), but also that on the Fortnite UI team, resolvers are the primary method of setting up and accessing VMs.

I often seem to be getting errors or VMs in a bad state when relying on a global viewmodel collection, and would love to know more about alternatives or intended ways to handle this.

Thanks again, it’s really helpful to have more examples showing how powerful MVVM can be.

This is awesome! I especially loved that you talked about you thought process. “What’s the data that we need to track?” “Who needs to know about the selected category being updated?”

I’m working on an RTS and I’m stumbling over getting the correct set of widgets to display. I think what you did here is a much better solution than what I was doing. I tried repurposing a command pattern I set up for units, and then I had an interface with a function that had a struct as a param, and the struct keeps getting random things added to it as I need them. This looks more promising.

Side note. I had no idea that you could bind a widget’s function to a VM’s array. Blew my mind. I’ve been binding to a delegate, the old school way.

In general thanks! Your other content is great. I use grid box and wrap box and cool things with the common visual attachment when I want to avoid taking up layout space. Never would’ve known about them had you not told me.


“But I’m also considering creating an additional tutorial showing the standard usage of MVVM to represent data and populate our widgets: a deep dive into view bindings, conversion functions and more!”

There’s a few ways to organize, maintain, and deliver learning content. I have a suggestion. There’s a few “Your first 60 minutes with __”. The “Your first 60 minutes with GAS” is a good example. Additionally, the same guy wrote a few following on guides, because you can’t cover everything in 60 minutes. There’s a best practices that covers some edge cases & decisions and a guide on advanced debugging.
What I’m suggesting is a First 60 min with MVVM and CommonUI. With some follow on guides like slate debugging, umg performance profiling, deep dive into whatever floats your boat.

Alternatively, there are no sample projects using MVVM. Cropout, Lyra, ParrotGame, StackOBot, the new templates are not using it. A sample project would be epic. Arran Langmead, Sam, and Sebastian, work for Epic and are always goofing around, and could make a project. A RTS / RPG hybrid project would have a lot of UI things among other stuff.

Hi and thanks for your feedback! Would you mind giving me some details on how it didn’t match the expectations? Was the goal of the tutorial unclear or did you not find the information you were looking for (or both? XD) ?
I’m suspecting you might have been looking for a basic tutorial on how to use MVVM to populate a screen, whereas this is a tutorial on how to use MVVM to handle navigation on a screen, where the data has already been populated.

Thank you Cody! I’m glad this was helpful!
And thank you for the suggestions on the educational content, that’s great advice and I think a “your first 60 minutes with MVVM” would be a great starter topic.
Thanks again!

Hello! Thanks for your comment!
I’m going to organize some brief content about resolvers, so that I can answer all the questions I received about them.
During the Unreal Fest in Orlando, one of the attendees was able to create a resolver using the resolver asset completely in blueprint. I wouldn’t necessarily suggest that for a full project and instead I’d go the C++ route, creating a Global VM Resolver (UMVVMViewModelContextResolver).
I want to sync up with our UI engineers on Fortnite so that I can get accurate information. :slight_smile:

Thanks for the great tutorial! It was very good to refresh what I knew about the MVVM and also learned some stuff. Missed more details about the conversion functions, as I recall it has to be a const and only one input of the same type? Sometimes I struggle a bit with it.
I have a question… can I use the viewmodel to store and calculate gameplay status like health and mana in a PlayerController or it is something that should be strict to widgets?

To update, I thought it was better to add my PlayerStatusVM in a PlayerState, had to add it with C++ to be better accessed by the PlayerController, I think I will do the calculations there and update the VM when it is completed.
A bit of experimenting with the conversion functions, it needs the input and output values to be of the same type and the function needs to be const and pure. I was able to make it work with two inputs, didn’t test further because thats what I need for now. :ok_hand:

Thanks,great tutorial