ARPP3
Topic Author
Posts: 15
Joined: 20 Jun 2023, 21:22

Proper MVVM approach for my UI

13 Jan 2024, 20:16

Hey! I want to apologize in advance if this topic is too specific, or hard to follow along with.

I've experimented quite a bit now with XAML and styling code, but am just now starting to familiarize myself with MVVM as a whole. I am about to begin tackling some controller-based navigation and I'd like to make sure I am doing things properly from the start! I attached an image, which shows 2 (of a few) possible layouts for my UI. All of these colored boxes, represent list boxes, I have some descriptions below the image:
UI2States.png
  • Red Box: This list box is a constant height and always occupies the left side of the screen. Focus has no effect on its size.
  • Blue Box: This box has its height bound to scale with the amount of elements inside of it. Focus has no effect on its size.
  • Green Box: This list box stays compressed until you select it (example 1). When you select it, it expands (example 2).
  • Pink Box: This one will fill all available space by default. When it's selected, (since the green box is no longer selected) it will expand.
So the obvious part is that, my ViewModel class should contain the necessary data for everything I want ti display in these list boxes, prepared to be connected via a data-binding and put in ListBoxItems. Which I currently have a single ViewModel set as the data-context for the whole page, and the XAML uses a custom template/style for each ListBoxItem type. Since each box has its own rules for how they should scale, my first idea for navigation was to manage controller input in the ViewModel. Then I can take button press from the controller, and via the FocusManager give certain ListBox elements focus. As well, I can have some bindings from some "State" variable in the ViewModel data-context that I use in the XAML to set/animate the heights of the ListBox elements as they share focus back and forth. But I feel like this is probably wrong... Since this is coupling my ViewModel too much to the "layout" and behaviour that is probably just considered, the "View" in MVVM.

Where should this be controlled? I am sure there are multiple answers, but what is the most agreed upon approach typically? For mouse-interactions I can have some click events in the code-behind but, if the user presses "A" on an XBox controller (and assume that this should select the green box), then it should also go into the code-behind as a part of the View/code-behind similar to how mouse clicks are bound to control logical focus? Which also decouples the View-specific navigation functionality from the ViewModel data? But is it correct to have controller input in the View layer even?

I guess I am nervous to start designing this system since I have very little experience with MVVM. I'd appreciate some wisdom 🙂 How would you design this system? Where would the code be for each part? ie: Controller logic, focus logic, and selection state for scaling/animating the heights...

Thank you very much!
David,
 
User avatar
sfernandez
Site Admin
Posts: 2997
Joined: 22 Dec 2011, 19:20

Re: Proper MVVM approach for my UI

15 Jan 2024, 12:08

Hi,

From a layout point of view this is just a Grid with 2 columns and 3 rows arranged like this:
<Grid>
  <Grid.ColumnDefinitions>
    <ColumnDefinition Width="3*"/>
    <ColumnDefinition Width="2*"/>
  </Grid.ColumnDefinitions>
  <Grid.RowDefinitions>
    <RowDefinition Height="Auto"/>
    <RowDefinition Height="*"/>
    <RowDefinition Height="Auto"/>
  </Grid.RowDefinitions>
  <ListBox x:Name="RedBox" Grid.Column="0" Grid.RowSpan="3"/>
  <ListBox x:Name="GreenBox" Grid.Column="1" Grid.Row="0"/>
  <ListBox x:Name="PinkBox" Grid.Column="1" Grid.Row="1"/>
  <ListBox x:Name="BlueBox" Grid.Column="1" Grid.Row="2"/>
</Grid>
As the green box is placed in a cell that adapts to the contents, it will expand if your selection style expands, and the pink box will just fill the remaining space. This is something that should be handled in the layout and with the styles and templates, not the view model.

In a view model you should not be handling focus states unless you need a very complex navigation scenario. Only selection that afects the logic would make sense in a view model (like show different data when selection changes). The view model should expose the properties required to show all the information in the UI and the commands to call back the view model from the UI.

Please let us know if you need further help.
 
ARPP3
Topic Author
Posts: 15
Joined: 20 Jun 2023, 21:22

Re: Proper MVVM approach for my UI

15 Jan 2024, 13:15

Hey @sfernandez, Thanks for the quick response :)

So in my case, I wasn't necessarily worried about the layout of the UI, this part is fine. The boxes were just meant to help illustrate a situation that highlights where my understanding for MVVM breaks down...

My concern is that if the state for which list-box has focus (let's say it's an int from 0-3 corresponding to any of the 4 boxes) is stored in the view (the code-behind class, not in the data-context/view-model), how can I use this information for resizing them? And where should controller input be managed? Since I am using noesis + Unity, and my view-model is also a Unity MonoBehaviour, my instinct is to handle controller input here. And since this is the view-model, if it had some knowledge of the current state of the control it would help to know what each controller button pressed does at any given time.

And ideally I would have some triggers in the styles and templates for the list-boxes that change the height properties based on the state. And as you said, the grid will handle the layout naturally. But if this state should not be in the view-model, then how can this be accomplished? Since bindings would be to the view-model,

Is there some way I can get bindings to reference the local variables in my custom control for the page (in the code-behind), in addition to the view-model that has been set as the data context?

I think I've overcomplicated this topic in my head, or maybe this falls into your category of "complex navigation scenario". But I think I am just missing some concept here to tie my understanding together,
 
User avatar
sfernandez
Site Admin
Posts: 2997
Joined: 22 Dec 2011, 19:20

Re: Proper MVVM approach for my UI

17 Jan 2024, 10:32

how can I use this information for resizing them?
Each control has a number of properties to know when they are focused:
- IsFocused indicates it has the logical focus
- IsKeyboardFocused indicates it has the keyboard focus (only one element in the whole UI can have keyboard focus)
- IsKeyboardFocusWithin indicates the keyboard focus is inside the control (some child of the control is focused or the control itself)
So you can use those properties in the template or style triggers to modify (or animate) the height of your list boxes. There is no need to store the focus in the view code-behind.
And where should controller input be managed?
If you activate "Enable Actions" in the View, you should be able to use a gamepad to move the focus of your UI using the left stick or dpad. This relies on the default directional focus navigation (the same as using the arrow keys in the keyboard). You can also use the interactivity actions like SetFocusAction or MoveFocusAction to manually move the focus in specific situations (in response to any kind of trigger: EventTrigger, KeyTrigger, StoryboardCompletedTrigger...). So usually you don't need to write custom logic in your view to handle the input either.
Is there some way I can get bindings to reference the local variables in my custom control
Any DependencyProperty or public CLR property defined in your code-behind class will be available for you in the associated xaml, you just need to reference the root element in the binding:
public class MyUserControl : UserControl
{
  public string Description { get; set; }
  ...
}
<UserControl x:Class="TheNamespace.MyUserControl"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  x:Name="MyControl">
  <Grid>
    <TextBlock Text="{Binding Description, ElementName=MyControl}"/>
    ...
  </Grid>
</UserControl>
 
ARPP3
Topic Author
Posts: 15
Joined: 20 Jun 2023, 21:22

Re: Proper MVVM approach for my UI

17 Jan 2024, 12:53

Thank you!

In hindsight this is painfully obvious.. I guess practice makers perfect, and I don't think I will forget about this in the future. Binding to the named element, it's really so clear now! yet for some reason I struggled with this 🤷‍♂️

As for the bindings to the new input system, that's really cool! I will try this out, and hopefully it can work for what I need!

Thanks so much!

Who is online

Users browsing this forum: Google [Bot] and 3 guests