Using WPF InputBindings and KeyBinding, I am looking to find if there is a way to get when a keyboard input is being held down, and next when its being released (like the standard Preview/KeyUp hooks).
For example, if user was Holding CTRL+Right, I don't want a flood of messages into my ICommand, but instead a single execution is wanted. When the CTRL+Right is released (KeyUp), it would be nice to handle that with another KeyBinding.
I had considered inheriting from KeyBinding or InputBinding, but there are no events I can find to hook into so I can ignore the IsRepeat of a a possible keyboard event.
I am not looking to do this is code-behind, this is entirely MVVM; Goal is to do this strictly with InputBindings. This will be part of multiple controls, so preventing code-behind keeps the code clean without copy/paste.
<UserControl.InputBindings>
<KeyBinding Gesture="CTRL+Right"
Command="{Binding CommandHotKeyExecuted}"
CommandParameter="{x:Static SomeConstantValue}" />
</UserControl.InputBindings>
Would be sweet if this was available via the Gesture, but can't find anything other than simple statements like CTRL+Right;
Reference:
Source for InputBinding
Source for KeyBinding
MSDN KeyBinding
Alternate ideas that are not ideal -
Doesn't handle the KeyUp; Has CodeBehind requirements:
SO: Ignore repetition in KeyBinding (holding the key - execute command just once)
Not talking about holding keys down: SO: Keybinding in WPF
Related
I want to be able to detect using events, when a Window (not necessarily the application I'm creating) changes its title.
My ideas (but none of them uses a specialized event):
Add an event to the mouse click and keyboard strokes, that way I can detect when the title will change, but it's not perfect, since the title may change a few seconds after the last click (e.g. loading a website)
Do some polling only on whitelisted applications
EDIT: I managed to put the EVENT_SYSTEM_CAPTURESTART hook, which captures clicks. It does work for changing tabs, but for loading new pages, it will not capture the change because pages usually take some time to load.
I'm doing this by using UIA (as suggested by Hans). I detect when a new window opens, get the UIA element, and subscribe to the property changed event handler for it for the NameProperty.
Automation.AddAutomationPropertyChangedEventHandler(
<your window AutomationElement>,
TreeScope.Element,
<your delegate>,
AutomationElement.NameProperty);
I wonder if that would break the MVVM pattern and, if so, why and why is it so bad?
WPF:
<Button Click="Button_Click" />
Code Behind:
private void Button_Click(object sender, RoutedEventArgs e)
{
ViewModel.CallMethod();
}
View Model:
public void CallMethod()
{
// Some code
}
IMHO, it keeps the code behind quite simple, the view model is still agnostic about the view and code behind and a change to the view doesn't affect the business logic.
It seems to me more simple and clear than Commands or CallMethodAction.
I don't want the kind of answer "it is not how it should be done". I need a proper and logical reason of why doing so could lead to maintenance or comprehension problems.
Nope, this is perfectly fine.
It's the View's job to handle user input and interact with the ViewModel. A button click event-handler, which calls a method of the ViewModel in response, falls quite cleanly into this role.
What you have posted is clean, readable, efficient, maintainable, and fully in the spirit of the MVVM design pattern.
Now, in a more general sense, what you really want to ask is: "why choose ICommands, vs Event Handlers for MVVM?" Well, you certainly wouldn't be | the | first.
No, it doesn't break MVVM, as long as you don't introduce logic that more appropriately belongs in the viewmodel.
It has the potential to reduce the clarity, IMO, because it breaks the view into XAML and c# files that are tightly coupled and where you can't see everything going on in one place. I find it easier to have zero code behind because it means less context switching when working on the view.
It can also make it more challenging to work in an environment where your UI designer isn't a C# programmer, because then two different people are maintaining the tightly-coupled files.
Edit
Here's an example of what I mean. This is from a weekend project I did to implement Minesweeper in WPF for fun and experience. One of my biggest WPF challenges was mouse input. For anyone who hasn't wasted time on the game before, the left mouse click reveals a cell, the right mouse button toggles a flag on the cell, and the middle mouse button will (conditionally) reveal adjacent cells.
I first started by considering using System.Windows.Interactivity's EventTrigger along with InvokeCommandAction to map events to commands. This sort-of worked for the right mouse button (wasn't a true click event, but a MouseRightButtonUp) but it wouldn't work at all for the middle mouse button which had no specific actions, only the generic MouseDown/MouseUp. I briefly considered prism's variation on InvokeCommandAction which could pass the MouseButtonEventArgs to its handler, but that very much broke the MVVM concept and I quickly discarded it.
I didn't like the idea of directly putting event handlers in the code-behind because that tightly coupled the action (the mouse click) and the response (revealing cells, etc.). It also wasn't a very reusable solution - every time I wanted to handle a middle click I'd be copying, pasting, and editing.
What I settled on was this:
<i:Interaction.Triggers>
<mu:MouseTrigger MouseButton="Middle" MouseAction="Click">
<i:InvokeCommandAction Command="{Binding Path=RevealAdjacentCells}" />
</mu:MouseTrigger>
</i:Interaction.Triggers>
In this case, there's no code in the code behind. I moved it into a MouseTrigger class I created that inherits from System.Windows.Interactivity.TriggerBase which, while being view-layer code, isn't part of any specific view, but a class which any view could utilize. This handler code is as agnostic as possible as to what kind of element it's attached to - anything derived from UIElement will work.
By leveraging this approach, I gained two key things over doing this in the event handlers on the code-behind:
There's a loose coupling between the event and the action. If I had a UXD working on the UI, they could change what mouse button the command was associated to by just editing a line of XAML. For example, swapping right and middle mouse buttons is trivial and requires no .cs changes.
It's reusable on any UIElement, not tied to any particular one. I can pull this out anytime I need to solve this kind of problem in the future.
The main drawback here is that it was initially more work to set up. My MouseTrigger class is more complex than the event handlers by themselves would be (mainly around properly handling dependency properties & changes thereof). XAML can also often be rather verbose for something that would seem simple.
My application is developed using C# (WPF and Prism). It is having 4 projects in it and different regions for each project:
menu region contains menu view
Drawing Region contains drawings
Tree region contains tree view
Status Region contains satus view
I done binding of shortcut keys for menu and it works fine but for that I need to select a menu header first, for example if I want to open new dashBoard window on CTRL+N first i need to select New Menu on the menu bar. If you have a look at other applications like Word, Notepad etc. if you press CTR+N it opens new file and you need not require to go at new menu.
Is it due to different regions in prism?
There is nothing wrong with the code. It is simple input binding code is something like this:
<UserControl.InputBindings>
<KeyBinding Key="A" Command="{Binding AddDashBoardCommand}">
</KeyBinding>
</UserControl.InputBindings>
Is it due to when I press short keys m in different region n m expecting other region to respond? What is the solution for this?
Based on my understanding, it may be related to the focus on a particular region. Anyway, a possible solution that would work is by using Windows's InputBindings, instead of defining the ShortKey on a specified Region.
This way, the Input Binding would take action anytime you would have focus on the Window Application, without needing to open the New menu. However, you would need to take into account that the Command Binding would yield on the Shell's ViewModel.
So, if you would need to delegate the action to a particular ViewModel, you could Publish() an Event through EventAggregator, which its type would depend on the action made by the user (NewWindowEvent, CopyEvent, SaveEvent, ...). And therefore, each corresponding ViewModel would then suscribe to the particular Event/s that it would only know how to handle it.
You should be able to use InputBindings with or without Modifiers attribute.
Regards.
Please try to use it as below:
<UserControl.InputBindings>
<KeyBinding Key="A" Modifiers="Control" Command="{Binding AddDashBoardCommand}">
</KeyBinding>
</UserControl.InputBindings>
So, using above (added Modifiers property): shortcut Ctrl+A should work for Add Dashboard command.
BTW, I would recommend changing your Add Dashboard shortcut to Ctrl+D, as Ctrl+A is already used for selecting all text.
I am trying to learn MVVM and using MVVM light with my phone application but I am kinda confused on how to access some information.
I am trying to not to use code behind events as much as possible as that does not seem to be the true MVVM way but I ran into a problem I don't know how to do.
I am using Google authentication and I am checking the Naviagted Event after each browser load.
public ICommand BrowserNavigated
{
get
{
return new RelayCommand<NavigationEventArgs>(e =>
{
var d = e;
var a = d;
});
}
}
However I also need the actual object control(I want to access the html that page is spitting back out) but I don't know how to get it.
private void wbGoogle_Navigated(object sender, System.Windows.Navigation.NavigationEventArgs e)
{
var d = e;
var d2 = d;
}
in the above code I could just cast "sender" to a web browser object but with me doing it the MVVM way I don't know how to access it.
Should I have another property or something for WebBrowser in my ViewModel?
In MVVM, code behind is allowed, but perhaps bindings are preferred. However, having GUI controls / events (hard coupling) is not allowed.
There may be ways to avoid code behind, but if you have to handle an event, get the data out of the event and set the property on your ViewModel in your code behind, then that is a better way to do it than adding UI code to your ViewModel which is clearly not keeping with MVVM.
Perhaps you can create some sort of EventTrigger which sets a property for a webbrowser that you can databind to create a re-usable Trigger that you can set in your XAML? (There's probably lots of ways to be clever on how to avoid code behind and create reusable code)
Your ViewModel should be totally unaware of the View or particular controls. Whether or not to keep the codebehind of your view clear or not, is a matter of religion.
If you want to keep it clean, which I recommend whenever possible, there are a number of concepts, which allow you to do so.
First, you need to design your View/ViewModel relationship in a way, that all data relevant for the ViewModel is present 'at all times' in the ViewModel or can be passed to the ViewModel via CommandParameter of a ICommand. In your case, if the page of the Webbrowser is controlled by (i.e. might be set from) the ViewModel, the ViewModel should hold a property, which is bound to the Source property of the browser. If the ViewModel just needs to 'know' the Uri when the BrowserNavigated is executed, just pass it as a CommandParameter.
Secondly, for your particular case, you want to execute a command on the ViewModel, when the Navigated event of the WebBrowser is raised. As always, there are several options. I prefer the option which comes with the framework: The EventTrigger in System.Windows.Interactivity allows you to relay any event of any control to commands via bindings.
This way, the Uri can be set from the ViewModel:
<WebBrowser Source="{Binding BrowserPageUri}" Name="wbGoogle">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Navigated" >
<i:InvokeCommandAction Command="{Binding BrowserNavigated}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</WebBrowser>
This way, you can handle the Uri as parameter of the command:
<WebBrowser Name="wbGoogle">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Navigated" >
<i:InvokeCommandAction Command="{Binding BrowserNavigated}"
CommandParameter="{Binding Source, ElementName=wbGoogle}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</WebBrowser>
Of course, this only lets you access the Uri of the page in the WebBrowser, not the page itself. If you need to bind to the page object itself, you need to extend the WebBrowser, with an attached property, that makes the Document property bindable. This is quite straight-forward:
Attached Document property for WebBrowser
After attaching this property to your WebBrowser, you can define the bindings of the WebBrowser just as in the above code, just with the attached property, instead of the Source property.
Note, that the syntax for binding to an attached property would be:
{Binding Path=(WebBrowserExtentions.Document)}
MVVM can be great for data binding and by using toolkits like MVVMLight, events that deal with user interactions can also be neatly dealt with.
However sometimes, controls like WebBrowserControl or ApplicationBar present a challenge to this. They can be difficult or impossible to bind with event triggers, or have complex behaviours. In these cases it is simpler if you handle the process of getting information from the control in your View code behind and send a simple message down to the VM.
Sure you could create an event that updates a property, write an Attached Property, or maybe use a 3rd party library; and there are cases that warrant that approach.
In your example I personally would use code-behind to handle the Navigated event and send down a message (or a method call on your VM) containing everything the VM wants in one go.
For instance:
private void wbGoogle_Navigated(object sender, System.Windows.Navigation.NavigationEventArgs e)
{
var vm = (TypeOfMyViewModel) this.DataContext;
//... read your HTML, get URL etc ...
vm.WebBrowserNavigatedTo(url, html, loadTime);
}
Similarly if an event raised from your VM would cause many things to happen in your View there comes a point where it is simpler to send a message or event to your View and let the View update the controls in code.
The key thing is keep the roles of MVVM distinct, e.g. to avoid a direct dependency of the ViewModel on the View. Interfaces can help here well as Messaging that comes with MVVMLight and its alternatives.
I want to implement different functionalities for single and double click on image.
I was earlier using Manipulationstarted event .What could be used now?
I am using help from click count
but (e.ClickCount) is not supported
You can do this with the gestures in the Silverlight for Windows Phone Toolkit
e.g.:
<Image Source="filename.png" >
<Controls:GestureService.GestureListener>
<Controls:GestureListener
Tap="GestureListener_Tap"
DoubleTap="GestureListener_DoubleTap" />
</Controls:GestureService.GestureListener>
</Image>
Beware that the tap event will always be called even when the double-tap event is also called. You could attempt to work round this by having a check in the tap event. (You'd need to have a short timer running on a different thread and if the double click isn't tirggered in this time then assume a double click.)
HOWEVER
From a usability point of view, you may make it easier on your users by having a tap event and a context (tap and hold) menu. This will make it much harder for the user to accidentally select the wrong option and it also gets rid of the problem above.
Having an object support both a tap (or click) and double tap event is not common because it's harder to discover or indicate to users and is easy to use the wrong action. Adding a context menu (right click menu on a PC) is the common convention for adding multiple options to users.
There is a ContextMenu also included in the Toolkit.
Shaireen,
Check out my simple blog article here: The simplest way to detect DoubleClick in Silverlight. That should give you the ability to detect both single Click's and DoubleClick's.
Good luck,
Jim McCurdy
You can use Tapped event for single click and DoubleTapped event for double click in windows phone 8.1
Why you don't have your own local counter variable.