好吧,我知道这个标题看起来到处都有答案,但这里找到的答案都不适合我。那么,就到这里吧。
我有这个布局:
<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>
现在,我的目标是当选择
txt
TextBox
时将焦点放在 ti1
TabItem
上,并在选择 dg
DataGrid
时将焦点放在 ti2
TabItem
上。另外,我真的很想将其设置为XAML
。
注意:我只能使用此处命名的控件,所以直到
Page
控件。
到目前为止我尝试过什么:
FocusManager.FocusedElement="{Binding ElementName=txt}"
txt
的父树中的所有父控件上设置 Control
(直到 Page
)。FocusManager.FocusedElement="{Binding RelativeSource={RelativeSource Self}}"
和 txt
控件上设置 dg
。通过
TabControl
的 SelectionChanged
事件在代码中设置焦点:
TextBox
和DataGrid
控件的创建方式与UserControl
类似,但实际上是继承TextBox
和DataGrid
的类,如下所示:
<TextBox ... </TextBox>
和
public partial class TextBox : System.Windows.Controls.TextBox
正如我所说,
XAML
解决方案是理想的,但如果前者不可能的话,我也会选择代码一。
好吧,Keyur PATEL 的答案中的调度程序部分对我来说是解决方案,尽管不是完整的解决方案。我的答案是用 TabControl
更新
Dispatcher
布局,然后调用
Focus
Dispatcher
。所以,对我来说完整的答案是:
Dispatcher.BeginInvoke( (Action) (() => tc.UpdateLayout()) );
Dispatcher.BeginInvoke( (Action) (() => txt.Focus() ) );
或者您可以只使用
Invoke
来代替,让 UI 线程等待您的
Action
。之所以我必须使用
Dispatcher
,是因为我首先用它来更改选定的选项卡。至少这是我最好的猜测。
<TabControl x:Name="tc" SelectionChanged="tc_selectionChanged">
并在后面的代码中:
InitializeComponent();
//if you know which control to focus by default when page is first loaded
Dispatcher.BeginInvoke(new Action(() => { txt.Focus(); }));
和
private void tc_selectionChanged(object sender, SelectionChangedEventArgs e)
{
if (ti1.IsSelected)
{
txt.Focus();
}
else if (ti2.IsSelected)
{
dg.Focus();
}
}
我在自己的 WPF 应用程序上尝试了这个确切的设置,所以我知道它有效。
有用的链接:
WPF TabControl 在 SelectionChanged 上,将焦点设置到文本字段
和
如何在 WPF 中的 tabItem 中集中控制(尽管对我来说,它不需要 UpdateLayout()
)
public static class TabItemExtention
{
public static bool GetIsSelected(DependencyObject obj)
{
return (bool)obj.GetValue(IsSelectedProperty);
}
public static void SetIsSelected(DependencyObject obj, bool value)
{
obj.SetValue(IsSelectedProperty, value);
}
public static readonly DependencyProperty IsSelectedProperty =
DependencyProperty.RegisterAttached(
"IsSelected", typeof(bool), typeof(TabItemExtention),
new UIPropertyMetadata(false, OnIsSelectedPropertyChanged));
private static void OnIsSelectedPropertyChanged(
DependencyObject d,
DependencyPropertyChangedEventArgs e)
{
var uie = (UIElement)d;
var tabItem = uie as TabItem;
if (tabItem != null)
tabItem.IsSelected = (bool)e.NewValue;
if ((bool)e.NewValue)
{
uie.UpdateLayout();
}
}
}
XAML:
ctrl:TabItemExtention.IsSelected="{Binding IsTabNewCustomsDelaySelected}"
public static class UIElementExtensions
{
public static void FocusOnIdle(this UIElement element)
{
var result = element.Focus();
if (result == false)
{
Application.Current.Dispatcher.Invoke(new Action(() =>
{
element.Focus();
}), Threading.DispatcherPriority.ContextIdle);
}
}
}