-
Notifications
You must be signed in to change notification settings - Fork 8.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement MVVM for the Actions page #14292
Conversation
struct KeyBindingViewModelComparator | ||
{ | ||
bool operator()(const Editor::KeyBindingViewModel& lhs, const Editor::KeyBindingViewModel& rhs) const | ||
{ | ||
return lhs.Name() < rhs.Name(); | ||
} | ||
}; | ||
|
||
struct ModifyKeyBindingEventArgs : ModifyKeyBindingEventArgsT<ModifyKeyBindingEventArgs> | ||
{ | ||
public: | ||
ModifyKeyBindingEventArgs(const Control::KeyChord& oldKeys, const Control::KeyChord& newKeys, const hstring oldActionName, const hstring newActionName) : | ||
_OldKeys{ oldKeys }, | ||
_NewKeys{ newKeys }, | ||
_OldActionName{ std::move(oldActionName) }, | ||
_NewActionName{ std::move(newActionName) } {} | ||
|
||
WINRT_PROPERTY(Control::KeyChord, OldKeys, nullptr); | ||
WINRT_PROPERTY(Control::KeyChord, NewKeys, nullptr); | ||
WINRT_PROPERTY(hstring, OldActionName); | ||
WINRT_PROPERTY(hstring, NewActionName); | ||
}; | ||
|
||
struct KeyBindingViewModel : KeyBindingViewModelT<KeyBindingViewModel>, ViewModelHelper<KeyBindingViewModel> | ||
{ | ||
public: | ||
KeyBindingViewModel(const Windows::Foundation::Collections::IObservableVector<hstring>& availableActions); | ||
KeyBindingViewModel(const Control::KeyChord& keys, const hstring& name, const Windows::Foundation::Collections::IObservableVector<hstring>& availableActions); | ||
|
||
hstring Name() const { return _CurrentAction; } | ||
hstring KeyChordText() const { return _KeyChordText; } | ||
|
||
// UIA Text | ||
hstring EditButtonName() const noexcept; | ||
hstring CancelButtonName() const noexcept; | ||
hstring AcceptButtonName() const noexcept; | ||
hstring DeleteButtonName() const noexcept; | ||
|
||
void EnterHoverMode() { IsHovered(true); }; | ||
void ExitHoverMode() { IsHovered(false); }; | ||
void ActionGotFocus() { IsContainerFocused(true); }; | ||
void ActionLostFocus() { IsContainerFocused(false); }; | ||
void EditButtonGettingFocus() { IsEditButtonFocused(true); }; | ||
void EditButtonLosingFocus() { IsEditButtonFocused(false); }; | ||
bool ShowEditButton() const noexcept; | ||
void ToggleEditMode(); | ||
void DisableEditMode() { IsInEditMode(false); } | ||
void AttemptAcceptChanges(); | ||
void AttemptAcceptChanges(const Control::KeyChord newKeys); | ||
void CancelChanges(); | ||
void DeleteKeyBinding() { _DeleteKeyBindingRequestedHandlers(*this, _CurrentKeys); } | ||
|
||
// ProposedAction: the entry selected by the combo box; may disagree with the settings model. | ||
// CurrentAction: the combo box item that maps to the settings model value. | ||
// AvailableActions: the list of options in the combo box; both actions above must be in this list. | ||
// NOTE: ProposedAction and CurrentAction may disagree mainly due to the "edit mode" system in place. | ||
// Current Action serves as... | ||
// 1 - a record of what to set ProposedAction to on a cancellation | ||
// 2 - a form of translation between ProposedAction and the settings model | ||
// We would also need an ActionMap reference to remove this, but this is a better separation | ||
// of responsibilities. | ||
VIEW_MODEL_OBSERVABLE_PROPERTY(IInspectable, ProposedAction); | ||
VIEW_MODEL_OBSERVABLE_PROPERTY(hstring, CurrentAction); | ||
WINRT_PROPERTY(Windows::Foundation::Collections::IObservableVector<hstring>, AvailableActions, nullptr); | ||
|
||
// ProposedKeys: the keys proposed by the control; may disagree with the settings model. | ||
// CurrentKeys: the key chord bound in the settings model. | ||
VIEW_MODEL_OBSERVABLE_PROPERTY(Control::KeyChord, ProposedKeys); | ||
VIEW_MODEL_OBSERVABLE_PROPERTY(Control::KeyChord, CurrentKeys, nullptr); | ||
|
||
VIEW_MODEL_OBSERVABLE_PROPERTY(bool, IsInEditMode, false); | ||
VIEW_MODEL_OBSERVABLE_PROPERTY(bool, IsNewlyAdded, false); | ||
VIEW_MODEL_OBSERVABLE_PROPERTY(Windows::UI::Xaml::Controls::Flyout, AcceptChangesFlyout, nullptr); | ||
VIEW_MODEL_OBSERVABLE_PROPERTY(bool, IsAutomationPeerAttached, false); | ||
VIEW_MODEL_OBSERVABLE_PROPERTY(bool, IsHovered, false); | ||
VIEW_MODEL_OBSERVABLE_PROPERTY(bool, IsContainerFocused, false); | ||
VIEW_MODEL_OBSERVABLE_PROPERTY(bool, IsEditButtonFocused, false); | ||
VIEW_MODEL_OBSERVABLE_PROPERTY(Windows::UI::Xaml::Media::Brush, ContainerBackground, nullptr); | ||
TYPED_EVENT(ModifyKeyBindingRequested, Editor::KeyBindingViewModel, Editor::ModifyKeyBindingEventArgs); | ||
TYPED_EVENT(DeleteKeyBindingRequested, Editor::KeyBindingViewModel, Terminal::Control::KeyChord); | ||
TYPED_EVENT(DeleteNewlyAddedKeyBinding, Editor::KeyBindingViewModel, IInspectable); | ||
|
||
private: | ||
hstring _KeyChordText{}; | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note to other reviewers: this is copy-pasted from Actions.h
kbdVM->PropertyChanged({ this, &ActionsViewModel::_ViewModelPropertyChangedHandler }); | ||
kbdVM->DeleteKeyBindingRequested({ this, &ActionsViewModel::_ViewModelDeleteKeyBindingHandler }); | ||
kbdVM->ModifyKeyBindingRequested({ this, &ActionsViewModel::_ViewModelModifyKeyBindingHandler }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Idk if this is possible, but it'd be nice if we didn't need to register ActionsViewModel
methods to KeyBindingViewModel
objects. Could we just define these methods directly in the KeyBindingViewModel
? This sounds like a pain, but I think it would involve KBVM to store a reference to stuff that ActionsVM owns.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The way I see it, the ActionsViewModel
owns the list of KeyBindingViewModel
s, and so it makes sense for the ActionsVM to be listening to events from the kbdVMs... Why would we want to have a reference to the ActionsVM within each kdbVM?
@@ -4,108 +4,14 @@ | |||
#include "pch.h" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note to other reviewers: go to ...
--> "View File". This file is super short now and is much easier to review that way.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yup, a lot of this is moving things around. Makes sense. Thanks!
Edit: I did download the PR and play around the actions page for a bit. Feels pretty normal, so that's good.
Fixes a regression from the actions MVVM change in #14292 - attempting to overwrite a keybinding was displaying a warning but propagating the change before the user acknowledged it. The overwrite key binding warning in the SUI works like before Closes #17754 (cherry picked from commit ce92b18) Service-Card-Id: PVTI_lADOAF3p4s4AmhmszgSF01Y Service-Version: 1.21
Summary of the Pull Request
Implements an
ActionsViewModel
for theActions
page in the SUIReferences
PR Checklist
Detailed Description of the Pull Request / Additional comments
A few annoyances:
KeyBindingViewModel
s, the page used to manually handle moving focus accordingly so that focus does not get lost. However, the page no longer owns theKeyBindingViewModel
, instead theActionsViewModel
owns them but theActionsViewModel
cannot manually move focus around since it does not own the UI Element. So, theActionsViewModel
emits an event for the page to catch that tells the page to move focus (FocusContainer
).ContainerBackground
of theKeyBindingViewModel
when the kbdVM entersEditMode
. TheActionsViewModel
does not have access to the page's resources though (to determine the correct background brush to use). So, theActionsViewModel
emits another event for the page to catch (UpdateBackground
).Validation Steps Performed
Actions page still works as before