How to get name of element with focus in WPF - wpf

I'm building a Mahjong game that has more buttons than Sgt. Pepper's band. The movement of the tile is simulated by showing the background of the button (tile) in question. I'd like to leverage the use of x:Name="button"and have only one click event, than 200 but the problem is in getting the name of the focused button. I can get the element with the focus but can not access the name property, if I could I would save a lot of inelegant drudgery. Here's what I'd like to do;
Private Sub b15_Click(sender As Object, e As RoutedEventArgs) Handles b15.Click
Dim brush As Brush
Dim vButton As Button
Dim InputElement As IInputElement = Keyboard.FocusedElement
vButton.Name = InputElement.name '!! here's the problem !!
If vTog = 0 Then 'background brush transferred from
brush = vButton.Background
vButton.Background = Nothing
vTog = 1
Else 'background brush transferred to
vButton.Background = brush
vTog = 0
End If
End Sub
Maybe I've missed an easy way to get the button's name so I can use it directly in the code behind. Thank you.

I recommend learning more about the basics of WPF.
As well as "regular" events WPF has routed events. See the signature of your click handler? Notice Routedeventargs rather than eventargs?
That click event is a routed event.
Routed events bubble ( up the visual tree ) and or tunnel (down the visual tree).
https://learn.microsoft.com/en-us/dotnet/framework/wpf/advanced/routed-events-overview
Because of this mechanism, you can handle a click event of buttons at a container further up the visual tree. That could be a grid, stackpanel or window.
In the handler, cast the originalsource of the event to button and that will have a name property.
I do c# but there is very little code to this and if you have trouble following it then you could put it through an online code converter.
Markup:
Title="MainWindow"
ButtonBase.Click="Window_Button_Click"
>
<StackPanel>
<Button Name="b1" Content="b1"/>
<Button Name="b2" Content="b2"/>
<Button Name="b3" Content="b3"/>
</StackPanel>
</Window>
Handler in code behind:
private void Window_Button_Click(object sender, RoutedEventArgs e)
{
Button btn = e.OriginalSource as Button;
if(btn!=null)
{
Debug.WriteLine(btn.Name ?? "No Name for this button");
}
}
If I spin that up with an f5, I see the name of each button clicked output to my output window when I click on them.
As an aside.
I'm not clear what the player clicks and what that does.
Maybe this could work in a generic way and the datacontext of each button would be a viewmodel holding x,y location or some such.

Related

WPF: ListBoxItem with expander cannot expand after adding PreviewMouseLeftButtonDown event handler to parent ListBox

I have a ListBox, where child items are expanders. I need realize DragDrop event for this. If I write in XAML
<ListBox PreviewMouseLeftButtonDown="StartDragDrop">
, StartDragDrop method is works good, but child expanders are cannot be expanded.
If I write
<ListBox MouseLeftButtonDown="StartDragDrop">
, child expanders are works correct, but StartDragDrop method is not works.
I think the problem is relates with bubble and tunnel events, but I dont know clear solution.
I need both, StartDragDrop method and ListBox child expanders Expand method, are work correct. What should I do?
You're partially right supposing, that it has to do something with tunneling and bubbling. The tunneling (with preview) event for the outer control is executed before the bubbling (without preview) event. But it doesn't prevent the latter from being executed. This only holds true, when somewhere in the whole event chain e.Handled is set to true. See this example:
XAML:
<Border Background="Red" PreviewMouseMove="OnPreviewMouseMove">
<Border Background="Blue" MouseMove="OnMouseMove" />
</Border>
C#
private void OnPreviewMouseMove(object sender, MouseEventArgs e)
{
Debug.WriteLine("Preview outer");
e.Handled = true; // this prevents OnMouseMove from being executed
}
private void OnMouseMove(object sender, MouseEventArgs e)
{
Debug.WriteLine("NoPreview inner");
}
If you delete the line "e.Handled = true;", OnMouseMove will be hit. If you don't set this yourself, consider, that a call to base."event-name" might do it.
The main idea is call DoDragDrop mathod at PreviewMouseMove() event, when moving offset is larger than somehow value.
1) Here the list box:
<ListBox AllowDrop="True" Drop=" ListBox_Drop" PreviewMouseLeftButtonDown="ListBox_PreviewMouseLeftButtonDown" PreviewMouseMove="ListBox_PreviewMouseMove">
ListBoxItems are Expanders, that cannot expand if we implement DragAndDrop.
2) Now we must add 2 variables (I use VB.NET):
Private isDragging As Boolean = False 'flag: is drag operation in process?'
Private dragStartPoint As Point 'coords of dragging start.'
3) Remember start point coords by preview mouse click:
Private Sub ListBox_PreviewMouseLeftButtonDown(sender As Object, e As MouseButtonEventArgs)
dragStartPoint = e.GetPosition(Me)
End Sub
4) On PreviewMouseMove get moving start point to current moving point offset. If offset is larger than some value, we initiate DragAndDrop operation and set flag isDragging to remember this.
Private Sub ListBox_PreviewMouseMove(sender As System.Object, e As MouseEventArgs)
If e.LeftButton = MouseButtonState.Pressed Then
     Dim diff As Vector = Point.Subtract(dragStartPoint, e.GetPosition(Me))
        If (Math.Abs(diff.X) > SystemParameters.MinimumHorizontalDragDistance) OrElse (Math.Abs(diff.Y) > SystemParameters.MinimumVerticalDragDistance) Then
If Not isDragging Then
             isDragging = True 'the flag is active until drop event raises.'
                Dim lstBox As ListBox = TryCast(sender, ListBox) 'get sender ListBox'
                If lstBox IsNot Nothing Then
                 Dim data As Object = GetDataFromListBox(lstBox, e.GetPosition(lstBox)) 'get data for drag-and-drop; need to be realized; there are some realizations at Stackoverflow.com presented.'
Dim effects As DragDropEffects = DragDrop.DoDragDrop(lstBox, data, DragDropEffects.Move) 'initiate drag-and-drop.'
                 End If
             End If
         End If
     End If
End Sub
5) Proccessing drop operation:
Private Sub ListBox_Drop(sender As Object, e As DragEventArgs)
     isDragging = False 'reset isDragging flag.'
        Dim lstBox As ListBox = TryCast(sender, ListBox) 'get sender ListBox.'
        If lstBox IsNot Nothing Then
         Dim myObj As MyClass = TryCast(e.Data.GetData(GetType(MyClass)), MyClass)
'...some actions'
        End If
End Sub
I've realized this idea and it's works exactly I was need:
on MouseLeftButtonClick ListBoxItems with Expanders are expands and
collapses,
on MouseMove with pressed left button DragAndDrop operation is
works, ListBoxItems are able to be sorted.

Button click event not responding after collapsing parent

I have a UserControl with a number of StackPanel's. I like to hide specific panels depending on the user action. A StackPanel which is visible on startup gives me a number of working buttons. The buttons have click events in the code behind file. After collapsing the panel and then making it visible again the buttons no longer work. Here is a part of my UserControl:
<StackPanel x:Name="buttonPanel" Orientation="Horizontal">
<Button x:Name="ReMindNodeNotes" Content=""
FontFamily="Segoe UI Symbol" FontSize="14" Foreground="#FF292323"
HorizontalAlignment="Left" BorderThickness="1" Padding="0"
UseLayoutRounding="True" Click="NoteClicked" />
<Button x:Name="ReMindNodeRemove" Content=""
FontFamily="Segoe UI Symbol" FontSize="14" Foreground="#FF292323"
HorizontalAlignment="Left" BorderThickness="1" Padding="0"
UseLayoutRounding="True" Click="RemoveClicked" />
</StackPanel>
And here is the code (for now just some text):
private void NoteClicked(object sender, RoutedEventArgs e)
{
System.Diagnostics.Debug.WriteLine("NoteClicked...");
}
private void RemoveClicked(object sender, RoutedEventArgs e)
{
System.Diagnostics.Debug.WriteLine("RemoveClicked...");
}
I have been looking for a solution the last two days. No luck so far. Who can help...?
THX Peter
Follow up 1...
Here is the code for collapsing the panel:
private void MoreClicked(object sender, RoutedEventArgs e)
{
System.Diagnostics.Debug.WriteLine(this.nodeName);
this.buttonPanel.Visibility =
this.buttonPanel.Visibility ==
Visibility.Visible ? Visibility.Collapsed : Visibility.Visible;
}
It works if the buttonPanel has focus. If the focus is on another panel it does not. Furthermore, what I probably should have mentioned... is that users can create multiple instances of the user control.
THX
Follow up 2...
I continue working on a solution of course... ;-) and I found a solution, which however is not the solution I want. Let me explain.
Users can interactively create multiple instances of the user control mentioned before. When a new instance is created, that instance gets focus. Now every instance has its own set of buttons which are on a stackpanel. When the focus goes to another instance I want the panel of the previous instance to collapse. The focus should then be set to the new (or selected existing) instance.
When I do this manually, it works! When I try to achieve this through the GotFocus and LostFocus events however, it does not. Here is the code for the manual solution (which works):
private void MoreClicked(object sender, RoutedEventArgs e)
{
this.buttonPanel.Visibility =
this.buttonPanel.Visibility ==
Visibility.Visible ? Visibility.Collapsed : Visibility.Visible;
}
Here are the LostFocus and GotFocus events:
private void NodeGotFocus(object sender, RoutedEventArgs e)
{
this.buttonPanel.Visibility = Visibility.Visible;
}
private void NodeLostFocus(object sender, RoutedEventArgs e)
{
this.buttonPanel.Visibility = Visibility.Collapsed;
}
I really appreciate your help! THX again...
Thanks for your sample morincer. The problem however is a little more complex. Let me try to explain the solution which I found after some more research. Maybe other developers can benefit from it as well.
I added the GotFocus and LostFocus events to my userconctrol. If I click somewhere inside the usercontrol the focus changes every time. Strange as these events are only defined on the usercontrol itself and not it's children. I have several buttons and a textbox inside the usercontrol and when I for example click on one of the buttons of the usercontrol that has focus the LostFocus and GotFocus events are fired for usercontrol anyway.
The most important event for me in this case is the LostFocus event. When the usercontrol looses focus - for example to another control - I want the button panel to disappear. Since the LostFocus event fires every time a object inside the usercontrol is touched, I cannot distinguish between the situation in which I want to hide and show the buttons.
I got a little closer to a solution by changing the LostFocus event as follows:
private void LostFocus(object sender, RoutedEventArgs e)
{
Object fo = FocusManager.GetFocusedElement();
if (fo.GetType().ToString().Contains("TextBox") ||
fo.GetType().ToString().Contains("ScrollViewer"))
{
this.buttonPanel.Visibility = Visibility.Collapsed;
}
}
This covers most of the situations. When the cursor is positioned in the TextBox the button panel is closed. The button panel is also closed when the user clicks on the background. This seems to be a ScrollViewer (found through debugging the code). Can anyone explain this...?
The situation which is not covered however, is when a user clicks on another usercontrol. It does of course when the user clicks on the TextBox (see the code) but not when the user clicks on a button. I tried to compare sender and FocusManager.GetFocusedElement(). Problem is that the sender returns the usercontrol (which is what I am looking for) but the FocusManager.GetFocusedElement() returns the button that was pressed. Now I could ask for it's parent which is a border then ask for the borders parent which is a stack panel and so on until I arrive at the usercontrol. A code behind file however was introduced with the idea to split design and logic while this solution would tie them together again. If I would change the XAML I would have to change the logic as well. Doesn't seem to be the right solution to me.
I found a solotion by giving every usercontrol a unique name in the constructor. I then give all the buttons unique names as well (I don't use them in my code anyway) starting with the name of the usercontrol. This then gives me the possibility to compare names at runtime and determine whether the focus has changed to another instance of the usercontrol. Here is the code:
private void NodeLostFocus(object sender, RoutedEventArgs e)
{
Object fo = FocusManager.GetFocusedElement();
if (fo.GetType().ToString().Contains("ScrollViewer"))
{
this.buttonPanel.Visibility = Visibility.Collapsed;
}
else if (fo.GetType().ToString().Contains("TextBox"))
{
if (!((TextBox)fo).Name.Contains(this.nodeName))
{
this.buttonPanel.Visibility = Visibility.Collapsed;
}
}
else if (fo.GetType().ToString().Contains("Button"))
{
if (!((Button)fo).Name.Contains(this.nodeName))
{
this.buttonPanel.Visibility = Visibility.Collapsed;
}
}
}
Now this works! But…I don't like the solution. I am depending on names instead of a good architecture. Does anyone hove an idea how to compare the actual sender with the usercontrol that is the parent of the button pressed (FocusManager.GetFocusedElement())? Or any other solution that relies on good programming?
THX again

WPF ListView ScrollViewer Double-Click Event

Doing the below will reproduce my problem:
New WPF Project
Add ListView
Name the listview: x:Name="lvList"
Add enough ListViewItems to the ListView to fill the list completely so a vertical scroll-bar appears during run-time.
Put this code in the lvList.MouseDoubleClick event
Debug.Print("Double-Click happened")
Run the application
Double-click on the LargeChange area of the scroll-bar (Not the scroll "bar" itself)
Notice the Immediate window printing the double-click happened message for the ListView
How do I change this behavior so MouseDoubleClick only happens when the mouse is "over" the ListViewItems and not when continually clicking the ScrollViewer to scroll down/up in the list?
You can't change the behaviour, because the MouseDoubleClick handler is attached to the ListView control, so it has to occur whenever the ListView is clicked -- anywhere. What you can do it detect which element of the ListView first detected the double-click, and figure out from there whether it was a ListViewItem or not. Here's a simple example (omitting error checking):
private void lv_MouseDoubleClick(object sender, MouseButtonEventArgs e)
{
DependencyObject src = (DependencyObject)(e.OriginalSource);
while (!(src is Control))
src = VisualTreeHelper.GetParent(src);
Debug.WriteLine("*** Double clicked on a " + src.GetType().Name);
}
Note the use of e.OriginalSource to find the actual element that was double-clicked. This will typically be something really low level like a Rectangle or TextBlock, so we use VisualTreeHelper to walk up to the containing control. In my trivial example, I've assumed that the first Control we hit will be the ListViewItem, which may not be the case if you're dealing with CellTemplates that contain e.g. text boxes or check boxes. But you can easily refine the test to look only for ListViewItems -- but in that case don't forget to handle the case there the click is outside any ListViewItem and the search eventually hits the ListView itself.
Maybe this helps?
Private Sub LstView_MouseDoubleClick(ByVal sender As Object, ByVal e As System.Windows.Input.MouseButtonEventArgs) Handles LstView.MouseDoubleClick
Dim source As FrameworkElement = TryCast(e.OriginalSource, FrameworkElement)
If IsNothing(source) Then Return
Dim TmplParent As DependencyObject = TryCast(source.TemplatedParent, DependencyObject)
If IsNothing(TmplParent) Then Return
If Not TmplParent.GetType.Equals(GetType(System.Windows.Controls.ListViewItem)) Then e.Handled = True
End Sub
I don't have VS handy to test if this works, but have you tried handling the double-click event on the ListViewItems rather than the ListView itself?
<ListView ListViewItem.MouseDoubleClick="lv_MouseDoubleClick" ... />
That should handle the MouseDoubleClick event on any child ListViewItem controls inside the ListView. Let us know if it works!
<Style TargetType="{x:Type ListViewItem}">
<EventSetter Event="MouseDoubleClick" Handler="OnListViewDoubleClick" />
</Style>
If you apply this style, it works. Just double click on item in the listview will work.
also, you have to remove the double click from the listview.

No events passed to WPF adorner layer

I am trying to make a nice "drag and drop zone" in WPF that is displayed in the adorner layer when something is being dragged into the main application. The problem is that I do not get any events from my adorner, even though it according to documentation should receive all input events since it is in a higher z-order.
To debug my problem I created a really simple example where I have a user control with only a button in it. This user control is displayed in the adorner layer, but I cannot click the button. Why? What have I done wrong?
My adorner class is constructed like this:
public ShellOverlayAdorner(UIElement element, AdornerLayer adornerLayer)
:base(element)
{
_adornerLayer = adornerLayer;
_overlayView = new AdornedElement();
_overlayView.AllowDrop = true;
_adornerLayer.Add(this);
}
and is created in the main window by
private void Window_Loaded(object sender, RoutedEventArgs e)
{
adornerLayer = AdornerLayer.GetAdornerLayer(MyTopGridWithButtonInIt);
ShellOverlayAdorner shell = new ShellOverlayAdorner(MyTopGridWithButtonInIt, adornerLayer);
}
I do not get any events at all from my control, i.e. no mouse clicks, mouse over, button clicks. I cannot even click the button in the adorner layer. What have I done wrong?
I don't know if you already tried that:
If you want the element added to react to events, I think that the element must be bound to the visual tree of the adorner.
The way to do it is to use a VisualCollection, intitialized to the adorner itself, or at least, this way it seems to be working:
VisualCollection visualChildren;
FrameworkElement #object;
public CustomAdorner(UIElement adornedElement) :
base(adornedElement)
{
visualChildren = new VisualCollection(this);
#object = new Button {Content = "prova"};
visualChildren.Add(#object);
}
protected override Visual GetVisualChild(int index)
{
return visualChildren[index];
}
This way the events are correctly routed.
I just had the same issue. Following the advice from MSDN sorted it for me:
Adorners receive input events just
like any other FrameworkElement.
Because an adorner always has a higher
z-order than the element it adorns,
the adorner receives input events
(such as Drop or MouseMove) that may
be intended for the underlying adorned
element. An adorner can listen for
certain input events and pass these on
to the underlying adorned element by
re-raising the event.
To enable pass-through hit testing of
elements under an adorner, set the hit
test IsHitTestVisible property to
false on the adorner.
i.e In the adorner itself, make sure IsHitTestVisible = false

Can't set focus to a child of UserControl

I have a UserControl which contains a TextBox. When my main window loads I want to set the focus to this textbox so I added Focusable="True" GotFocus="UC_GotFocus" to the UserControls definition and FocusManager.FocusedElement="{Binding ElementName=login}" to my main windows definition. In the UC_GotFocus method i simply call .Focus() on the control i want to focus on but this doesn't work.
All i need to do is have a TextBox in a UserControl receive focus when the application starts.
Any help would be appreciated, thanks.
I recently fixed this problem for a login splash screen that is being displayed via a storyboard when the main window is first loaded.
I believe there were two keys to the fix. One was to make the containing element a focus scope. The other was to handle the Storyboard Completed event for the storyboard that was triggered by the window being loaded.
This storyboard makes the username and password canvas visible and then fades into being 100% opaque. The key is that the username control was not visible until the storyboard ran and therefore that control could not get keyboard focus until it was visible. What threw me off for awhile was that it had "focus" (i.e. focus was true, but as it turns out this was only logical focus) and I did not know that WPF had the concept of both logical and keyboard focus until reading Kent Boogaart's answer and looking at Microsoft's WPF link text
Once I did that the solution for my particular problem was straightforward:
1) Make the containing element a focus scope
<Canvas FocusManager.IsFocusScope="True" Visibility="Collapsed">
<TextBox x:Name="m_uxUsername" AcceptsTab="False" AcceptsReturn="False">
</TextBox>
</Canvas>
2) Attach a Completed Event Handler to the Storyboard
<Storyboard x:Key="Splash Screen" Completed="UserNamePassword_Storyboard_Completed">
...
</Storyboard>
and
3) Set my username TextBox to have the keyboard focus in the storyboard completed event handler.
void UserNamePassword_Storyboard_Completed(object sender, EventArgs e)
{
m_uxUsername.Focus();
}
Note that calling item.Focus() results in the call Keyboard.Focus(this), so you don't need to call this explicitly. See this question about the difference between Keyboard.Focus(item) and item.Focus.
Its stupid but it works:
Pop a thread that waits a while then comes back and sets the focus you want. It even works within the context of an element host.
private void ListView_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
System.Threading.ThreadPool.QueueUserWorkItem(
(a) =>
{
System.Threading.Thread.Sleep(100);
someUiElementThatWantsFocus.Dispatcher.Invoke(
new Action(() =>
{
someUiElementThatWantsFocus.Focus();
}));
}
);
}
Just recently I had a list-box that housed some TextBlocks. I wanted to be able to double click on the text block and have it turn into a TextBox, then focus on it and select all the text so the user could just start typing the new name (Akin to Adobe Layers)
Anyway, I was doing this with an event and it just wasn't working. The magic bullet for me here was making sure that I set the event to handled. I figure it was setting focus, but as soon as the event went down the path it was switching the logical focus.
The moral of the story is, make sure you're marking the event as handled, that might be your issue.
“When setting initial focus at application startup, the element to
receive focus must be connected to a PresentationSource and the
element must have Focusable and IsVisible set to true. The recommended
place to set initial focus is in the Loaded event handler"
(MSDN)
Simply add a "Loaded" event handler in the constructor of your Window (or Control), and in that event handler call the Focus() method on the target control.
public MyWindow() {
InitializeComponent();
this.Loaded += new RoutedEventHandler(MyWindow_Loaded);
}
void MyWindow_Loaded(object sender, RoutedEventArgs e) {
textBox.Focus();
}
since i tried a fuzquat's solution and found it the most generic one, i thought i'd share a different version, since some complained about it looking messy. so here it is:
casted.Dispatcher.BeginInvoke(new Action<UIElement>(x =>
{
x.Focus();
}), DispatcherPriority.ApplicationIdle, casted);
no Thread.Sleep, no ThreadPool. Clean enough i hope.
UPDATE:
Since people seem to like pretty code:
public static class WpfExtensions
{
public static void BeginInvoke<T>(this T element, Action<T> action, DispatcherPriority priority = DispatcherPriority.ApplicationIdle) where T : UIElement
{
element.Dispatcher.BeginInvoke(priority, action);
}
}
now you can call it like this:
child.BeginInvoke(d => d.Focus());
WPF supports two different flavors of focus:
Keyboard focus
Logical focus
The FocusedElement property gets or sets logical focus within a focus scope. I suspect your TextBox does have logical focus, but its containing focus scope is not the active focus scope. Ergo, it does not have keyboard focus.
So the question is, do you have multiple focus scopes in your visual tree?
I found a good series of blog posts on WPF focus.
Part 1: It’s Basically Focus
Part 2: Changing WPF focus in code
Part 3: Shifting focus to the first available element in WPF
They are all good to read, but the 3rd part specifically deals with setting focus to a UI element in a UserControl.
Set your user control to Focusable="True" (XAML)
Handle the GotFocus event on your control and call yourTextBox.Focus()
Handle the Loaded event on your window and call yourControl.Focus()
I have a sample app running with this solution as I type. If this does not work for you, there must be something specific to your app or environment that causes the problem. In your original question, I think the binding is causing the problem.
I hope this helps.
After having a 'WPF Initial Focus Nightmare' and based on some answers on stack, the following proved for me to be the best solution.
First, add your App.xaml OnStartup() the followings:
EventManager.RegisterClassHandler(typeof(Window), Window.LoadedEvent,
new RoutedEventHandler(WindowLoaded));
Then add the 'WindowLoaded' event also in App.xaml :
void WindowLoaded(object sender, RoutedEventArgs e)
{
var window = e.Source as Window;
System.Threading.Thread.Sleep(100);
window.Dispatcher.Invoke(
new Action(() =>
{
window.MoveFocus(new TraversalRequest(FocusNavigationDirection.First));
}));
}
The threading issue must be use as WPF initial focus mostly fails due to some framework race conditions.
I found the following solution best as it is used globally for the whole app.
Hope it helps...
Oran
I converted fuzquat's answer to an extension method. I'm using this instead of Focus() where Focus() did not work.
using System;
using System.Threading;
using System.Windows;
namespace YourProject.Extensions
{
public static class UIElementExtension
{
public static void WaitAndFocus(this UIElement element, int ms = 100)
{
ThreadPool.QueueUserWorkItem(f =>
{
Thread.Sleep(ms);
element.Dispatcher.Invoke(new Action(() =>
{
element.Focus();
}));
});
}
}
}
I've noticed a focus issue specifically related to hosting WPF UserControls within ElementHosts which are contained within a Form that is set as an MDI child via the MdiParent property.
I'm not sure if this is the same issue others are experiencing but you dig into the details by following the link below.
Issue with setting focus within a WPF UserControl hosted within an ElementHost in a WindowsForms child MDI form
I don't like solutions with setting another tab scope for UserControl. In that case, you will have two different carets when navigating by keyboard: on the window and the another - inside user control. My solution is simply to redirect focus from user control to inner child control. Set user control focusable (because by default its false):
<UserControl ..... Focusable="True">
and override focus events handlers in code-behind:
protected override void OnGotFocus(RoutedEventArgs e)
{
base.OnGotFocus(e);
MyTextBox.Focus();
}
protected override void OnGotKeyboardFocus(KeyboardFocusChangedEventArgs e)
{
base.OnGotKeyboardFocus(e);
Keyboard.Focus(MyTextBox);
}
What did the trick for me was the FocusManager.FocusedElement attribute. I first tried to set it on the UserControl, but it didn't work.
So I tried putting it on the UserControl's first child instead:
<UserControl x:Class="WpfApplication3.UserControl1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid FocusManager.FocusedElement="{Binding ElementName=MyTextBox, Mode=OneWay}">
<TextBox x:Name="MyTextBox"/>
</Grid>
... and it worked! :)
I have user control - stack panel with two text boxes.The text boxes were added in contructor, not in the xaml. When i try to focus first text box, nothing happend.
The siggestion with Loaded event fix my problem. Just called control.Focus() in Loaded event and everthing.
Assuming you want to set focus for Username textbox, thus user can type in directly every time it shows up.
In Constructor of your control:
this.Loaded += (sender, e) => Keyboard.Focus(txtUsername);
After trying combinations of the suggestions above, I was able to reliably assign focus to a desired text box on a child UserControl with the following. Basically, give focus to the child control and have the child UserControl give focus to its TextBox. The TextBox's focus statement returned true by itself, however did not yield the desired result until the UserControl was given focus as well. I should also note that the UserControl was unable to request focus for itself and had to be given by the Window.
For brevity I left out registering the Loaded events on the Window and UserControl.
Window
private void OnWindowLoaded(object sender, RoutedEventArgs e)
{
ControlXYZ.Focus();
}
UserControl
private void OnControlLoaded(object sender, RoutedEventArgs e)
{
TextBoxXYZ.Focus();
}
I set it in the PageLoaded() or control loaded, but then I'm calling WCF async service and doing stuff that seems to lose the focus. I have to to set it at the end of all the stuff I do. That's fine and all, but sometimes I make changes to the code and then I forget that I'm also setting the cursor.
I had same problem with setting keyboard focus to canvas in WPF user control.
My solution
In XAML set element to Focusable="True"
In element_mousemove event create simple check:
if(!element.IsKeyBoardFocused)
element.Focus();
In my case it works fine.

Resources