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.
Related
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?
I'd like to control which button is focused in my view. User must be able to perform a job without need to use mouse. And job is going through all elements. Depending on element, some buttons will appears, some disappears.
I could do it with dependency properties. To example, if there are buttons Previous and Next, then I can provide IsPreviousFocused and IsNextFocused to set focus to them after certain event. Events can be: showing window for the first time (something should have focus already), reaching 1 element (hiding Previous button, setting IsNextFocused), reaching last element (opposite), etc.
This looks reasonable more or less.
But, if I have, to example, 10 buttons (different operations), then all of them will have to have dependency property!
So I was thinking about much easier approach: when I hide button, there will be no focus
if(FocusManager.FocusedElement == null) { ... }
If I can detect, when there are no focus, then I can try to set it to one of the buttons somehow. This way, I don't really need any complicated focus management
Question is: how to deal with FocusManager.FocusedElement in MVVM scenario? How to detect when there is no focus (when window is shown first time, when certain button is clicked and become invisible, etc)?
P.S.: I actually hate ms for making another technology without thinking fully into it; focus is very basic feature (and everybody care about it in their software), but there is no direct support for it (in xaml); looks like "oh, its too complicated, lets skip it" solution.
You could control your focus from your ViewModel by using the approach shown here:
Set focus on textbox in WPF from view model (C#)
Even if I associate the button with a class derived from ICommand, I am still left with figuring out how the button should trigger the CanExecute method and refresh its enabled state. I do know about the CanExecuteChanged event for which a button with an associated command registers, but see the following paragraph for why this is troublesome.
On a plain old dialog consisting of some 10-15 controls, it seems haphazard to have to process every change notification for every single one of those controls, triggering the CanExecuteChanged event on the button's command, causing the button's enabled state to be affected by the CanExecute method's return value. Even stating what needs to be done in the last sentence was quite cumbersome.
There must be a better way of coding a WPF dialog, so that the confirmation button (e.g., OK) is grayed out until all controls have valid information and is enabled at that point in time (i.e., when all controls are properly filled in). Sample code, ideas and pointers to articles would be immensely appreciated.
Thanks
I don't see anything haphazard here. Since your condition is "all controls have valid information", this can occur after any control is edited, and therefore you need to listen to change notifications from all controls.
On a plain old dialog consisting of some 10-15 controls, it seems
haphazard to have to process every change notification for every
single one of those controls,
I don't think so. Every Textbox, checkbox changed event is handled by the same handler, say SetState(), which calculates the overall state of the dialog. Every time a control is edited, the entire state is recalculated.
until all controls have valid information
Then that object would have a boolean property EnableOKButton, let's say, which is set according to the updated state. Then that property is bound to the button's Enabled property so it automagically changes - without dealing with extraneous events.
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.
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.