WPF 每个 TabItem 的初始焦点

问题描述 投票:0回答:4

好吧,我知道这个标题看起来到处都有答案,但这里找到的答案都不适合我。那么,就到这里吧。

我有这个布局:

<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
    事件在代码中设置焦点:

    • if ( ti1.IsSelected ) { tc.UpdateLayout(); FocusManager.SetFocusedElement( sp, txt ); }
    • if ( ti1.IsSelected ) { tc.UpdateLayout(); txt.焦点(); }

TextBox
DataGrid
控件的创建方式与
UserControl
类似,但实际上是继承
TextBox
DataGrid
的类,如下所示:

<TextBox ... </TextBox>

public partial class TextBox : System.Windows.Controls.TextBox

正如我所说,

XAML
解决方案是理想的,但如果前者不可能的话,我也会选择代码一。

c# wpf xaml
4个回答
3
投票

好吧,Keyur PATEL 的答案中的调度程序部分对我来说是解决方案,尽管不是完整的解决方案。我的答案是用 TabControl

 更新 
Dispatcher
 布局,然后调用 
Focus
 
Dispatcher
。所以,对我来说完整的答案是:

Dispatcher.BeginInvoke( (Action) (() => tc.UpdateLayout()) ); Dispatcher.BeginInvoke( (Action) (() => txt.Focus() ) );

或者您可以只使用

Invoke

 来代替,让 UI 线程等待您的 
Action

之所以我必须使用

Dispatcher

,是因为我首先用它来更改选定的选项卡。至少这是我最好的猜测。


2
投票
您可以尝试类似于代码隐藏解决方案的方法,但有以下变体:

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


0
投票
找到使用扩展属性的解决方案

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}"
    

0
投票
对我有用的是扩展方法。有些东西阻止我的元素获得焦点,所以等到上下文空闲修复了这个问题。

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); } } }
    
© www.soinside.com 2019 - 2024. All rights reserved.