Okay, I know this title looks like it has answers all around SO, but none of the answers found here worked for me. So, here goes.
I have this layout:
<Window>
<Grid>
<DockPanel>
<TabControl>
<TabItem>
<Page x:Name="p">
<Grid x:Name="g2">
<TabControl x:Name="tc">
<TabItem x:Name="ti1">
<StackPanel x:Name="sp">
<C:TextBox x:Name="txt"/>
</StackPanel>
</TabItem>
<TabItem x:Name="ti2">
<C:DataGrid x:Name="dg"/>
</TabItem>
</TabControl>
</Grid>
</Page>
</TabItem>
</TabControl>
</DockPanel>
</Grid>
</Window>
Now, my goal is to put focus on txt
TextBox
when ti1
TabItem
gets selected and on dg
DataGrid
when ti2
TabItem
gets selected. Also, I would really love to set this in XAML
.
Note: I can only use controls that are named here, so up until Page
control.
What have I tried so far:
FocusManager.FocusedElement="{Binding ElementName=txt}"
on all of the parent controls in the parent tree of the txt
Control
(up until Page
).FocusManager.FocusedElement="{Binding RelativeSource={RelativeSource Self}}"
on the txt
and dg
controls.setting focus in code through TabControl
's SelectionChanged
event:
TextBox
and DataGrid
controls are created like UserControl
s, but are actually classes that inherit TextBox
and DataGrid
, like this:
<TextBox ... </TextBox>
and
public partial class TextBox : System.Windows.Controls.TextBox
As I said, XAML
solution is desired, but I will also settle for a code one, if former is not possible.
Okay, the Dispatcher part from Keyur PATEL's answer was the solution for me, although not the complete one. The answer for me was to update TabControl
layout with the Dispatcher
and than invoke the Focus
Dispatcher
. So, the complete answer for me was:
Dispatcher.BeginInvoke( (Action) (() => tc.UpdateLayout()) );
Dispatcher.BeginInvoke( (Action) (() => txt.Focus() ) );
or you can use just Invoke
instead, for the UI thread to wait for your Action
.
And for the reason why I had to use a Dispatcher
, it is because I used it to change the selected tab in the first place. That is my best guess, at least.