Handling selected objects on the GUI in WPF - c#

I've built several user controls in WPF and they all get added to a canvas. I want to add a behaviour that keep tracks of the currently selected usercontrol. A usercontrol should be selected when:
The mouse clicks on it;
when it recieve focus;
when either of the two above happens to a subcontrol of the usercontrol.
Is there any way to handle this purely by using the focus mechanism of WPF or will I need to take care of this myself with assistance of the focus classes?
I've read up upon the new way of handling focus in WPF, and the problem I'm facing is that the keyboard focus determines what the currently selected object is, but some parts of the my control can't recieve keyboard focus so even though these parts are clicked, the usercontrol doesn't recieve focus.
I'm looking for advice on how to implement this feature and how much I could/should rely on the focus mecanisms. Ultimatively I wouldn't mind if only a single object could be selected, but if it's easily extendable to multi-select then I wouldn't mind this either.
Just to clarify, I know I could build this manually by handling a lot of events and keeping track of states, but I was just hoping an easier approach was available.

Combine UIElement.IsKeyboardFocusWithin with a PreviewMouseDown handler:
When PreviewMouseDown is called, set a flag and schedule callback using Dispatcher.BeginInvoke at DispatcherPriority.Input to set focus to the UserControl if the flag is still set.
Set a handler for UIElement.IsKeyboardFocusWithin property changes in your UserControl. When the handler fires, clear the flag.
The idea here is that if you click anywhere on the UserControl and keyboard focus does not result in the focus being moved into the UserControl, force it into the UserControl.
FYI, here's roughtly what step 1 looks like in code:
public override OnPreviewMouseDown(MouseButtonEventArgs e)
{
_mouseClickedButNoFocus = true;
Dispatcher.BeginInvoke(DispatcherPriority.Input, new Action(() =>
{
if(_mouseClickedButNoFocus)
Focus();
});
}

You could use the UIElement.IsKeyboardFocusWithin property, which is true when the UIElement or one of its children has keyboard focus. It is a dependency property, so you can easily use it for a trigger in a style

You can set the logical focus to the control when any of the child gets the keyboard focus using FocusManager.IsFocusScope="True". Setting the keyboard focus to the control or trying to do will eat the keys for the child controls.
You can use UIElement.IsKeyboardFocusWithin to set the focus of the control if any of the children has focus.
You can read this article which I think describes the difference between Logical and Keyboard focus quite well:
http://www.pluralsight.com/community/blogs/eburke/archive/2009/03/18/why-is-focus-in-wpf-so-tricky-managing-and-understanding-focus-in-a-wpf-application.aspx

Related

FocusManager.FocusedElement and MVVM

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#)

WPF, give keyboard focus to control that was previously collapsed

I am trying to give a specific control keyboard focus during a sequence of presentation changes. Say a control was in a visibility state of hidden. In a function call I can change its visibility to visible, set the keyboard focus on it with no problems. However if the control was set to a visibility of collapsed and I try to set the visibility back to visible then set focus on it, it does not take.
Is there a process I can use to allow the control to move from a collapsed state, to a visible state and take keyboard focus?
It's probably a timing issue where the control you set to visible is not ready to accept focus yet. This can happen fairly frequently when dealing with dynamic UI changes.
You should still be able to focus your control but you'll need to queue the focus action until after the control has been properly initialized. Simply using a BeginInvoke call like shown below, should do the trick.
Dispatcher.BeginInvoke(() =>
{
//Set focus here
});
Its not a matter of the control having been initialized. This again this is an issue of transitioning visual states.
Just to close loop on this, the problem is solved by calling the control.UpdateLayout()

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.

WPF usercontrol not allowing lostfocus to change on seperate control

This one is a bit tricky to explain.
I have a usercontrol with some textboxes. I also have a menu just above this usercontrol in the same window. Whenever I tab away, the LostFocus fires correctly on the textbox, and this is what I want. Strangely enough, if I click the Menu button on top of my window, the LostFocus event does not fire on the textbox. Is there an elegant way to make sure that my menu properly allows LostFocus to fire on any controls which last had focus?
I also want to avoid having to Update BindingExpressions otherwise I would likely be doing this for N textboxes, which is undesirable.
I can't imagine it is too difficult to achieve this.. I just don't understand how this doesn't work: in most other situations LostFocus always fires.
Any ideas? Thank you.
Is the menu WPF as well or Winforms / UnManaged? If either of the two then the lost focus event does not fire. This can play havoc with WPF controls as many time a save or other data function is being performed from the menu. To counter this I have had to implement multiple ways to combat this. The easiest way was to implement a mouse leave event on the user control itself and perform any actions you require manually in code.

Categories