WPF MVVM C# Input Bindings With TextBox key presses - c#

I am currently stuck on an issue that I have been unable to find an answer for. It involves 'overriding' built-in TextBox keyboard functions using MVVM. Here's my issue:
I have a TextBox that the users enters text into during runtime. I'm looking to implement keyboard shortcuts, or input bindings with this TextBox. I started out by using what seems to be the standard ICommand interface based approach, which I implemented simply as:
<TextBox.InputBindings>
<KeyBinding Key="Up" Command="{Binding testCommand}" Modifiers="Ctrl" />
</TextBox.InputBindings>
The idea is that I execute the command associated with the ICommand property as set in the ViewModel. However, the TextBox class already contains a baked in function for CTRL+UP which, as you may know, moves the caret to the beginning of the TextBox entry field. This function executes in addition to my Command, resulting in my desired changes, but also the caret moving.
Before MVVM, I would simply use the PreviewKeyDown event in Code-Behind, detecting the desired key combinations and using
e.Handled = true;
to stop the TextBox from firing its built in Command. This isn't an optimal solution, however, as it probably violates MVVM principles. It would also be difficult to implement in tandem with InputBindings declared in XAML.
During my research, I found an article that describes using a class provided by Blend that allows for executing a Command based off an event, potentially allowing me to listen for the PreviewKeyDown event, which fires before the built-in functions, but this would mean that I would not be declaring my key bindings in XAML, as the syntax does not seem to support keypress specific conditions, or InputBindings. I would have to do all key combination processing logic in the ViewModel, which seems like something the View should be doing.
Further research has led me to an interesting new area which involves intercepting and replacing certain 'ApplicationCommands' with a Command that always returns false on CanExecute, effectively removing the function. I was able to locate a case where someone wanted to replace the default CTRL+Z functionality. An abridged version of the full question shows the basic idea:
textBox.CommandBindings.Add(new CommandBinding(ApplicationCommands.Undo,
UndoCommand, CanUndoCommand));
Research of this ApplicationCommands class led me to a few other classes, one of which relates more directly to my issue: ComponentCommands. MSDN describes that class as containing (among other things)
ComponentCommands.MoveToHome
which would fit my Ctrl+Up command's built-in function. Using the syntax in the SO question I linked previously, I could theoretically prevent that command from executing, which is a step in the right direction. However, I'm hoping to make the key combinations that trigger my Command in my ViewModel customizable via ViewModel properties that the InputBindings would be bound to in XAML. If I implemented this approach, it would mean that I could not know ahead of time which built in functions might conflict with the user's chosen key bindings.
This was naturally resolved for me before I switched to MVVM by handling the arguments in the event handler in Code-Behind, as mentioned previously. Any key combinations I wrote into the PreviewKeyDown event handler that I had a special action for set the e.Handled to true, effectively preventing any possible built-in command that would follow once the method finished from executing after the event handler finished.
Is there some way I could implement this functionality, using InputBindings declared in XAML? What are my options?
Some ideas:
Perhaps I could expose the event handler for PreviewKeyDown on my TextBox, and inside the method I iterate through all of the TextBox's InputBindings, looking for provided key combinations that match the provided key press, and if found, I execute the associated command and set e.handled to true? I'm not familiar with manipulating InputBindings from Code-Behind, so I'm not sure how practical this would be, or if it would place too much load on the application (imagine a user holding down a key). It also seems a bit strange in terms of organization to set it up this way. I could see a situation happening where the input bindings fire twice.
I could also make a list of all the built-in commands that I'd want to always have around, even if the user set a key combination that conflicted, and disable the rest. That seems like a bad idea, as it would be quite laborious, and also could mess with something I couldn't anticipate.
Perhaps there's a way that I could calculate which built-in commands would conflict with the current input bindings and disable those, to be calculated each time the user sets the bindings?
I'm still learning MVVM and WPF, so I suspect that I may be missing something obvious or simply looking at it the wrong way. Any help would be greatly appreciated.
Edit:
It has been suggested that my question is a duplicate of this one. I have reviewed the answer and determined that the approach used is definitely a step in the right direction. I could use the attached object to implement the PreviewKeyDown handling without losing functionality of InputBindings in XAML. However, I do have some concerns.
It seems that the resolution was to move the InputBindings to the UserControl, and implement an attached object that would handle PreviewKeyDown. I have multiple TextBoxes in my UserControl which will need their own set of InputBindings, some of which would conflict with one another should they be moved to the UserControl level.
I can only conclude that the reason it was moved away from the TextBox was that the attached object could not be applied directly to the TextBox for some reason. If I was to attempt this, would I have to create some encompassing element that had the attached object that would hold each TextBox? Why can't the TextBox use the attached object itself?

Related

WPF - Common event fired for value changed

Ok. This seems like an incredibly basic use case but fore some reason I am having an issue finding a common solution across control types.
Heres the use case:
A form is presented to the user with any editable controls. (Text box, combo, grid etc.).
The user edits a value in the control and tabs out.
Expectation is that I can wire to an event like Lost Focus and do "foo" with the changed value.
The user then gives focus back to the control and tabs out without making an edit.
Expectation is that whatever event I am wired to I can check if the value has been changed.
Is there one common event across controls that will only fire when the user has finished editing( such as tab out or enter ) and allow me to check previous state vs. current state?
Jason, you may want to look into Binding and DependencyProperties in WPF instead of tracking events in your form. You would bind a class to your form which exposes properties to be changed. Using DependancyProperties a single event is fired called "PropertyChanged".
Unfortunately is is a broad topic, but you will really get the full benefit of the WPF programming model. Searches on "dependency properties in wpf" will give you some good examples.
I think maybe this is Focus issue. There exist two different focus types: keyboard focus and logical focus. The the control that has keyboard focus is the one that has the caret, in what the user press a key and the control process that input. The a control may have the logical focus but not having the keyboard focus. Please check this in the MSDN article "Input Overview". About the other question, maybe you could process the TabControl.SelectedItemChanged for taking the event when a tab item selection changed.
Hope this is helpful to you...
What you may be interested in is implementing INotifyPropertyChanging (not just INotifyPropertyChanged).
As noted in the answer of this question, the INotifyPropertyChangING does not prevent you from changing a value, but to detect WHEN something DOES change, and what it's new value is going to be.
Hope it helps in your solution needs.
As the previous answers suggested, you would be better off by implementing a view - viewmodel structure, with your viewmodel having implemented INotifyPropertyChanged, and thus allowing you to bind to properties that will announce their changes to the UI.
If you don't want to do this, you can eventually subscribe on your input elements to the PreviewKeyUp event, check if the Tab key has been pressed and proceed from there.

Controlling event-driven navigation in a WPF application

I think the title for this question is probably wrong, but I'm not sure quite how to phrase it. I have a C# 4.0 (VS2010) WPF application.
This application consists of a single window with a header including the basics (logos, captions, etc) and a set of navigation buttons (back, retry, next, etc). The rest of the window is comprised of a listbox that is populated with one or more usercontrols based on what mode the app is currently in.
The way the code is currently written when the mode changes the listbox is cleared, all new user controls are added, and the buttons are set to their required state. This is fine for the initial state of each window mode but I'm having trouble deciding a good approach to update the navigation buttons as the contents of the controls change.
For example one screen is a configuration screen and there are three user controls contained within the listbox. These controls are custom classes that inherit from UserControl. Additionally they implement an interface that defines a method 'bool Validate' which determines if the control has been completely filled out.
This same scenario could apply to lots of other situations but this is a generic use case that is pretty straightforward to understand. When the screen initially loads the 'Next' button, whose visibility is controled by the parent window, is visible but disabled as the child controls can't possibly yet be valid. At some point as the user fills out arbitrary data within one or more controls each one would return true if its Validate method was called.
At the point where all controls are valid, the next button would then become enabled. Fairly straightforward design.
The problem is each control doesn't know what screen it is on, and this is by design. I don't want the controls having to be aware of each other and updating a button status in the parent window. I also don't want the parent window to run a polling thread to call Validate every second because in some cases the validation could be complex.
I'm thinking that the change event of each control within the UserControl (text boxes, radio buttons, etc) would all call a trigger a private validate event and this would set some public property on the interface or class.
f I can do that is there a way for the parent window to respond in an event-driven manner to the change of that property? I'm not looking to do this in WPF, doing this in C# code is preferable as I don't want to get into the complexity of WPF quite yet. I'm just not sure, other than constant polling, how to tell when every control's 'IsValid' property will have synchronized all to 'true', if that is even a good approach.
EDIT:
Okay, here is another way to ask the question. I have a List of something (in this case a list of an interface) and want to be able to respond to a public property change on each item in the list so I can take an action when all items are (bool in this case) true. The above explains the use case, but this is a more generic version of the question.
EDIT:
#Vincent "you might do it in an even simpler way with a custom "ValidatedChanged()" event that you can hook in the same way."
It turns out that this is really what I was looking for. The property notification approach seems to be more for ease of use with data-bound controls. I read a lot of posts on this site about how to implement that but it really wasn't what I wanted. I just wanted my objects to notify that an event occured, which happened to be a property change, but that is beside the point. I found documentation on implementing an event in an interface and I have it working now. Thanks for pointing me in the right direction and helping me realize what is really is that I needed.
So you have a ListBox which contains all your controls, and when all controls are validated, the Next button should be enabled ?
If so, when one of your control validates, you might search all sons of the ListBox to check them for validation, using VisualTreeHelper.GetChildren to get them all.
If you don't want / can't have a handle on the ListView, you might find it by searching up the visual tree starting from the control that just validated.
Each 'Validated' event of each control would be handled by a 'CheckIfAllValidated' event handler, and when all are validated, you could raise a 'AllValidated' events that would be handled by the button (and maybe some other controls as well) to enable it.
Edit : I understood that you did not want each component to know about their children, but notice that even the quite common PropertyChanged event has a 'sender' fields that tells who did raise the event. So any listener of a PropertyChanged on, say, the 'validated' property, can go up the visual tree, stop when it encounters a ListView, then search downstairs if all control that have a validated property do have this property set to true...
Edit 2 :
To be more clear about how to do it, either in your window new or on the window loaded event
or maybe on the ContentRendered Event, depending on how your controls are loaded, you
might use once that code to hook a handler to all your controls :
For Each ThisControl In MainListView.
Dim ThisControlType = ThisControl.GetType
Dim ThisControlPropertyChangedEvent = ThisControlType.GetEvent("PropertyChanged")
' you might wanna check here if event is not null / nothing
ThisControlPropertyChangedEvent.AddEventHandler(ThisControl, New PropertyChangedEventHandler(AddressOf APropChanged))
Next
and you write the APropChanged somehow like that :
Public Sub APropChanged(ByVal sender As Object, ByVal e As PropertyChangedEventArgs)
If e.PropertyName = "Validated" Then
Dim ValidatedForAll = True
For Each ThisControl In MainListView.Items
Dim ThisControlType = ThisControl.GetType
Dim ThisControlValidatedProperty = ThisControlType.GetProperty("Validated")
'you might wanna check for non null here
If Not ThisControlValidatedProperty.GetValue(ThisControl, Nothing) Then
ValidatedForAll = False
Exit For
End If
Next
If ValidatedForAll Then
MessageBox.Show("Yeeppee") ' you might send an event instead.
End If
End If
End Sub
Edit 3 : you might do it in an even simpler way with a custom "ValidatedChanged()" event that you can hook in the same way.

Detecting default button on a control

This seems very simple, but I can find nothing on a web concerning the behaviour I want to add to my custom control.
My custom control is a textBox with a list of choices. When the text entered by the user is not part of the list, a popup will appear with the list allowing the user to select a correct choice.
Sometimes, there may be a default button on the container in wich the custom control has been added. If so, when the enter key has been pressed, if the text is wrong, The popup must been displayed. If there is no default button, on enter, nothing must happen even if the text is wrong.
To be able to create this behaviour, I must be able to detect the presence of a defaultbutton in the container, and it must be done inside the c# code of the cutom control.
I hope the description is clear enough.
Thanks in advance
Have you thought about implementing an MVVM approach and the Command pattern? So long as your view model knows what the choices are, you can bind the default button to a command. So long as the commands CanExecute handler returns false, i.e., an appropriate choice has not been entered/selected, the button will be disabled and won't respond to the user pressing enter.
Since I was unable to know what other controls I had from the custom control I chose to go like this:
I made a recursive function to find the first parent using FrameworkElement.Parent
Having the parent, I could take a look at every controls it contains.
As soon as I saw a button, I had to verify if IsDefault.
For this one, I used the VisualTreeHelper GetChildrenCount(DependencyObject obj_Parent) and GetChild(DependencyObject obj_Parent, int childIndex). Recursivity once again...
It works very well even though it means more code to execute.

ListBox.SelectedIndexChanged - can you determine if it was user initiated?

My question is similar to this: How to prevent ListBox.SelectedIndexChanged event?, but I want to ask it a different way.
Is there a simple way to determine if the 'SelectedIndexChanged' is coming from the user as opposed to initiated through code (e.g. ListBox.SelectedIndex = x)?
As far as I know, no, there's no simple way built-in. The best I've been able to do is set a flag just before changing it in code and then letting the event handler reset the flag and return.
I suppose you could start examining the call stack and see if it's originating somewhere in your own code or not, but I'm not sure how much it's worth the effort.
For me, the 'SelectionChangeCommitted' event was better suited for my purposes. It fires when a selection in the drop down is selected. This is the easiest way to handle the specific case when the end-user initiates the change. SelectedIndexChanged is to capture all cases.
Property change listeners don't distinguish between causes of a property change. It's a common problem. Setting a flag is the way to do it.
I do wish that there was a way to set values without firing property change events. But then, people argue that it breaks the whole object-oriented model, because it effectively allows you to change a field directly, without using a property.

C#: What is the value added by commanding?

When looking into MVC frameworks for flex, as3, silverlight, and wpf... a common concept of ICommand / commanding keeps appearing... Can anyone explain the advantage of using ICommand / Execute() ?
Where I dont see the value added is - Why can't the controller map the input (ie: a click event) to the correct method inside of the model? I'm assuming it is because commanding buys you something - like removing business logic from the controller / the would-be event handler in the controller.
Thx.
Here's a couple of cases that demonstrate the value commands add:
Suppose you have a simple form with a text box and Submit button. You want a button to become enabled only if some text is entered into the text box. With commands all you have to do is to implement CanExecute method (to return true or false depending on the value in a text field) A framework will automagically disable/enable button accordingly. With code-behind (or controller) approach you'd have to write a code do enable/disable button manually.
Suppose later you decided you don't like the button control you used, and decide to switch to a new control (being that a button, or something more exotic) from a different library. All you have to do is make a change in XAML. Any control that supports Command binding will know what to do. In code-behind approach you'd have also modify your button click handler (since new control will probably require different event handler signature)
Suppose later you decide to add a checkbox to your text field that would visually indicate to user whether the content of that field is acceptable. All you have to do is to bind this new checkbox to your command's CanExecute, and now you have two controls already that would automatically change their visual appearance depending on whether form is submittable. With code-behind approach (or controller) addition of a new control would require adding more code.
Suppose you want to test your action. Since commands don't depend on any visual elements, and don't need them, you can easily write a unit test that will not require user clicking any buttons, or entering any text. With controller approach you'd have emulate controller's events, and mock the view.
Summarizing:
Commands provide a well-defined interface between the business logic and the presentation. Business logic implementor doesn't care about how visually certain action (e.g. command) will be implemented. He simply provides the action implementation and an ability for a presentation to query the state of the action. He doesn't care what particular UI element (or elements) will trigger that action, how exactly (in)ability to execute that action would reflect in UI, and what changes UI might go through in the future. At the same time presentation designer doesn't need to know anything about event handlers, controllers, etc. He has a Command and he plugs it in to any UI element (or elements) he chooses without the need to go to C# code at all.
What controller are you talking about?
The Commanding concept in Silverlight and WPF is used to tie together (through binding mostly) the UI to business logic (be it a controller/viewmodel/model/etc).
That is the point, to move the functionality of the command outside of the UI.
Example. Saving a widget in your application is probably always done the same way. Sure, you might let the user change the name, or this or that, but the overall behavior is always going to be the same. Now, in your application you might actually initiate saving a widget through a lot of different UI avenues such as Page 1 has a button on the right hand side that saves the widget on that page, Page 2 has a menu item on the top that saves the widget on that page. The UI is different but the behavior remains the same.
You can accomplish the same goal by using Event Handling (such as grabbing the click event on a button), but now you're back into the context of dealing with UI specific issues. Commanding, arguably, has a cleaner separation.
The simple answer is that commands are bindable whereas events are not. So if you want to respond to a button click event you can either:
Attach an event handler in the code behind.
Create a click command and bind it to the ViewModel's command.
Since one of the goals of MVVM (which is the more common pattern for Silverlight and WPF over MVC) is to seperate code and UI. So if you take the first approach you end up with code in the View. If you take the second approach you can seperate the code from your view using commands and bindings.

Categories