Proper MVVM approach for my UI
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:
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,
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:
- 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.
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,
-
sfernandez
Site Admin
- Posts: 2997
- Joined:
Re: Proper MVVM approach for my UI
Hi,
From a layout point of view this is just a Grid with 2 columns and 3 rows arranged like this:
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.
From a layout point of view this is just a Grid with 2 columns and 3 rows arranged like this:
Code: Select all
<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>
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.
Re: Proper MVVM approach for my UI
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,
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,
-
sfernandez
Site Admin
- Posts: 2997
- Joined:
Re: Proper MVVM approach for my UI
Each control has a number of properties to know when they are focused:how can I use this information for resizing them?
- 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.
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.And where should controller input be managed?
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:Is there some way I can get bindings to reference the local variables in my custom control
Code: Select all
public class MyUserControl : UserControl
{
public string Description { get; set; }
...
}
Code: Select all
<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>
Re: Proper MVVM approach for my UI
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!
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 13 guests