I am totally new to Windows 8 development and I am now facing an issue mixing touch and keyboard navigation using MVVM Light.
So I have a list of view models in a grid view and whenever one of those is selected, navigation to the selected view model is activated. This works totally fine with touch or a mouse, but with a keyboard it can get really confusing. Indeed, the natural behavior would be to navigate the list with the arrows and hit enter when I want to display the item, but here instead, navigation will be activated when simply changing item with the arrow keys which is really confusing for the user.
So how could I do so the navigation could be activated on selection with touch and mouse and with a combination of selection and enter key with the keyboard?
Here is the code I use.
ViewModel:
public ReleaseViewModel SelectedRelease
{
get
{
return selectedRelease;
}
set
{
if(selectRelease != value)
{
selectedRelease = value;
}
// Navigation code here
}
}
View:
<GridView
ItemsSource="{Binding Releases}"
ItemTemplate="{StaticResource ReleaseTemplate}"
ItemContainerStyle="{StaticResource GridViewItemStyle}"
Grid.ColumnSpan="2"
Grid.Row="2"
Padding="116,0,40,46"
SelectedItem="{Binding SelectedRelease, Mode=TwoWay}"/>
In my opinion, coding with the MVVM pattern does not mean that everything code-related should be done in the model. Operations which is related UI beaviors (like navigation) should still be done in the view (the codebehind), by using the available events from the control. Like the GridView's events mouse and keyboard events.
Many may not agree with me on that, but after working by the MVVM pattern for several years in both WPF and Silverlight, I must say that a good combination between the UI-behavior (view) and the control's logic/functionability (model), you will also be forced to put several stuff which concerns the UI only to the codebehind. At least, this is my opinion.
What you could do is to create a class which inherits GridView (let's call it MyDataGrid).
Then you can use the OnKeyDown override and have the navigation go vertica when pressing enter.
You can actually make the MyDataGrid look and behave "out-of-the-box" just like you want so there are no extra code if you want to use the same grid behavior another place in your app (or another app).
The best way I finally found is to use some code behind. But instead of directy navigating from the UI I kept navigation logic in the view models.
So I simply hooked up the ItemClick event from the GridView and in the event handler I casted the Page data context to my view model and then I simply executed the command from the view model. This is not easy to maintain but it surely preserve the separation of concerns of MVVM.
private void GridView_ItemClick(object sender, ItemClickEventArgs e)
{
MyViewModel vm = (MyViewModel)this.DataContext;
if(vm.NavigateToSelectionCommand.CanExecute(null))
{
vm.NavigateToSelectionCommand.Execute(e.ClickedItem);
}
}
Still I hope a cleaner and more maintainable solution will come up with time.
Related
Is there a way to force the NSPopover to start in the detached state? I only see isDetached which is a read-only property for the state of the popover and an NSPopoverDelegate method detachableWindow(forPopover:) which lets me override the window that gets created. I'd like to essentially click a button and have the NSPopover start in the state in this photo.
The style of this window is exactly what a product requirement is and I can't seem to find any NSWindow style settings that would make a window do something like this (nor an NSPanel)
This detached popover functionality seems special in that it:
non-modal, but stays above main app. Able to still interact with the main app just like in Messages how you can still click around and type a new message.
Clicking another app, AppFoo, puts both the main app and the helper window behind AppFoo.
The helper window can be moved around and isn't hidden on app deactivation (another app gets selected).
Has the little, native, grey X in the top left.
If you don't mind calling private API, it's actually pretty simple:
let detach = NSSelectorFromString("detach")
if popover.responds(to: detach) {
popover.perform(detach)
}
No need to even add a delegate. I don't know when this private method was added but it's available at least since macOS 10.13. I suspect it's available since the introduction of NSPopover, though.
Here is the trick.
Use the required delegate method detachableWindowForPopover: to do the work for you, like:
- (void) showPopoverDetached
{
NSWindow* detachedWindow = [self detachableWindowForPopover:nil];
[detachedWindow.windowController showWindow:nil];
}
Seems that the Apple engineers implemented detachableWindowForPopover: on a pretty smart way, I guess it uses the content view controller class, and will always create a singleton like instance of the detached window.
Once detachableWindowForPopover: has called the presented window instance will be re-used no matter when and why it is called, called it directly (from a func like my sample above) or indirectly (e.g. when you drag out, detach, the popover from its original position)
This way they can prevent a popover from being detached 'twice' and we can also implement the detached way programmatically, nice job from them!
Here is a tiny demo of how it works in a real life (tested on macOS 10.13 - 13.0)
https://imgur.com/a/sfc7e6d
I am trying to make an App for multiple platforms using Xamarin. The App uses the Mvvm structure and MvvmCross.
Currently, I have various View Models and they all bind great (using MvvmCross), as long as they are in separate pages.
However, I would like to make a single page that references multiple View Models. For example, a page that has few buttons each binding to methods in different View Models.
I understand that to do this I should:
1) Divide the screen to different views.
2) Assign the buttons to different views according to their View Model.
I am not sure how can I divide the screen? Are fragments the answer?
Also, does this mean a View Model that would know about all view models in the page is necessary?
My current work around is having tabs in all pages that change the current view model of that page, as follow:
public ICommand VM1Command
{
get { return new MvxCommand(() => ShowViewModel<ViewModel1>()); }
}
public ICommand VM2Command
{
get { return new MvxCommand(() => ShowViewModel<ViewModel2>()); }
}
public ICommand VM3Command
{
get { return new MvxCommand(() => ShowViewModel<ViewModel3>()); }
}
This is pretty ugly, I would really appreciate if anyone could refer me to somewhere where this is explained or even better tell me how to do it.
Cheers!
The SpheroViewModel is used in the SpheroView (see: SpheroView.cs). This View is a MvxBindingTabActivityView. So it uses an Android TabHost to display the Subviews as Tab. The setup is done in the lines 30 - 48. For each SubViewModel you have an own view (e.g. SpheroAccelMovementView.cs) that binds and displays the separate data.
For more Details on Tabs and MvvMCross and different Platforms have a look at N = 25 - Video Tutorial. There are perhaps some API changes since stuart has recored the video. But it explains the general idea of tabs and subviewmodels.
In my application I have a menu which open a SelectionDialog, this dialog is used to choose an object.
When this object is selected I have to display it in the view.
What is the best way to update my view?
Currently, I call myview.update(object) after the dialog is closed (in the handler of the menu). But I think this solution is not well design.
I have read about update my model and notify my view but my model does not change (no data are changed, I only display different Data ).
Does anyone has some ideas for a well design solution ?
Define model listener ( dataPopulated(Event e))
Make your view implement model listener and register it with the Model.
Define a Model class that can contain the objects that you want to populate in the view
When Model.setInput(Object input) is invoked fire dataPopulated() event on all registered model listeners.
Above steps works properly when you have view activated. You need to consider cases like when if view is deactivated or not visible ( make sure you refresh view is visible else you will have unnecessary overhead of refreshing view though it is notvisible)
Try adding a selection listener in the view and register this selection in the dialog.
In the listener action, add the code to show the selected object.
Where exactly is the limit to adopt VM so it can suite better a particular View? Example:
There should be a command in UI (ex button) that should allow adding new item. Additional requirement can be that new item should be selected, ensured that its visible on control (lets say TreeView control), and to begin edit on the newly added item (in order to change predefined value that was set in VM). Lets assume that control doesn't have automatic mechanism to achieve this, so we need to do it manually. So the execution flow looks like this:
invoke add command on VM - done is View's xaml.
set SelectedItem to new item (usually we bind control's SelectedItem property to VM's CurrentItem property, and then just assign new item to CurrentItem.
ensure that new item is visible on control - this must be done in View's code behind.
Start editing - this must be done in View's code behind.
Now, since everywhere on net there are articles on using messages for almost everything, a question:
What do I break if I do it in the simple old fashion way? I use Click event instead of Command binding on adding new item, and in the method I do this:
// in View's Click event handler
ViewModel.AddCommand.Execute(null);
EnsureVisibleSelectedItem();
BeginEdit();
.. clean and clear! And what do I gain if I do it using messages:
// in ViewModel's AddCommand
AddNewItem();
SetCurrentItem();
SendMessageToEnsureVisibleSelectedItem();
SendMessageToBeginEditSelectedItem();
... where View has registered to receive these two messages.
Any light on this is greatly appreciated. To my opinion, UI can change, and VM should be able to adopt new UI without making changes to itself, so I dont quite understand current MVVM policy that is preached on internet.
I would say "make it simple".
What's really important in MVVM is:
what doesn't depend on the view should go in the ViewModel (your ViewModel must not be aware of the view in any way - not just by object reference)
everything else in the View and its code-behind.
Yes, in its code-behind. There's nothing wrong in writing code-behind if it is code that is related to the view, not logic. For instance, drag & drop management should be written in the code-behind.
To answer your question, you do not break anything in writing:
// in View's Click event handler
ViewModel.AddCommand.Execute(null);
EnsureVisibleSelectedItem();
BeginEdit();
Everything that is not related to the view is in the ViewModel, everything else in the View/code-behind. That's just fine.
No if I look at your second example:
// in ViewModel's AddCommand
AddNewItem();
SetCurrentItem();
SendMessageToEnsureVisibleSelectedItem();
SendMessageToBeginEditSelectedItem();
AddNewItem is OK (not related to the view), SetCurrentItem is OK (not related to the view), but what about SendMessageToEnsureVisibleSelectedItem and SendMessageToBeginEditSelectedItem?
EnsureVisible is typically useful for a treeview, but what if your view wasn't built with a treeview? What if the control would automatically make the new selected item visible? Of course you could ignore the message, but you would have written some useless code in ViewModel because you thought your view would need it for UI display.
You have typically written here some code in the ViewModel that is aware of how the View should be working. Yes, you have reduced the number of lines in the code-behind, but you definitely have broken the pattern.
Your "old fashion way" is actually a good way for your needs. Your ViewModel is not aware of the view, that's what's important.
I am doing a silverlight using the MVVM model, and i am finding it hard to do the events handling via MVVM especially that the events handlers are doing lots of changes in the view like enabling and disabling buttons, update media element functions and position. I am still new to the MVVM and i can't Imagen how can i do this. does anyone already know good article to start with or simple approach to understand :) I'll reply with what i may find interesting while i do my search as well. Thanks
1) Understand that there are different "flavors" of MVVM. Strict/hardcore MVVM patterns, although theoretically desires, isn't necessary.
2) Many view events can be handled via Commands. WPF supports this, and i believe Silverlight 4 does as well. A simple view-event to start with would be Button clicks. This allows you to handle the event in the ViewModel (instead of the View's 'code-behind').
3) For things like enabling/disabling view controls/states via the MVVM model, here is an example/explanation:
Xaml controls (say, a Button) is Data-Bound to the ViewModel for whatever property
(in this case, it will be the button's IsEnabled property).
Your ViewModel has an IsButtonEnabled property.
Whenever you change this property in the VM, raise the PropertyChanged notification, and you will see the binded result in the view (the button's IsEnabled state will be updated).
ps - you can do many things via VM properties in this manner: from text, to various property states, color, you can even play animations in the property setters/getters....etc.
Cheers