简体   繁体   English

WPF 每个 TabItem 的初始焦点

[英]WPF Initial focus for each TabItem

Okay, I know this title looks like it has answers all around SO, but none of the answers found here worked for me.好的,我知道这个标题看起来像是在 SO 周围都有答案,但是这里找到的答案都没有对我有用。 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.现在,我的目标是把重点放在txt TextBoxti1 TabItem被选中,并在dg DataGridti2 TabItem被选中。 Also, I would really love to set this in XAML .另外,我真的很想在XAML设置它。

Note: I can only use controls that are named here, so up until Page control.注意:我只能使用此处命名的控件,直到Page控件为止。

What have I tried so far:到目前为止我尝试了什么:

  • setting FocusManager.FocusedElement="{Binding ElementName=txt}" on all of the parent controls in the parent tree of the txt Control (up until Page ).txt Control的父树中的所有父控件上设置FocusManager.FocusedElement="{Binding ElementName=txt}" (直到Page )。
  • setting FocusManager.FocusedElement="{Binding RelativeSource={RelativeSource Self}}" on the txt and dg controls.txtdg控件上设置FocusManager.FocusedElement="{Binding RelativeSource={RelativeSource Self}}"
  • setting focus in code through TabControl 's SelectionChanged event:通过TabControlSelectionChanged事件在代码中设置焦点:

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

TextBox and DataGrid controls are created like UserControl s, but are actually classes that inherit TextBox and DataGrid , like this: TextBoxDataGrid控件的创建方式与UserControl类似,但实际上是继承TextBoxDataGrid ,如下所示:

<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.正如我所说, XAML解决方案是需要的,但如果前者不可能,我也将解决一个代码。

Okay, the Dispatcher part from Keyur PATEL's answer was the solution for me, although not the complete one.好的, Keyur PATEL回答中的 Dispatcher 部分对我来说是解决方案,尽管不是完整的解决方案。 The answer for me was to update TabControl layout with the Dispatcher and than invoke the Focus Dispatcher .我的答案是使用Dispatcher更新TabControl布局,然后调用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 .或者您可以只使用Invoke来让 UI 线程等待您的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.之所以必须使用Dispatcher ,是因为我首先用它来更改选定的选项卡。 That is my best guess, at least.至少,这是我最好的猜测。

You could try something similar to your code-behind solution but with this variation:您可以尝试类似于您的代码隐藏解决方案的方法,但具有以下变化:

<TabControl x:Name="tc" SelectionChanged="tc_selectionChanged">

and in code behind:并在后面的代码中:

InitializeComponent();

//if you know which control to focus by default when page is first loaded
Dispatcher.BeginInvoke(new Action(() => { txt.Focus(); })); 

and

private void tc_selectionChanged(object sender, SelectionChangedEventArgs e)
{
    if (ti1.IsSelected)
    {
        txt.Focus();
    }
    else if (ti2.IsSelected)
    {
        dg.Focus();
    }
}

I tried this exact setup on my own WPF application so I know it works.我在我自己的 WPF 应用程序上尝试了这个确切的设置,所以我知道它有效。

Helpful links:有用的链接:

WPF TabControl On SelectionChanged, set focus to a text field WPF TabControl On SelectionChanged,将焦点设置到文本字段

and

How to focus control in the tabItem ın WPF (although for me it worked without UpdateLayout() )如何在 tabItem ın WPF 中集中控制(虽然对我来说它没有UpdateLayout()

Found solution using extension attribute使用扩展属性找到解决方案

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: XAML:

ctrl:TabItemExtention.IsSelected="{Binding IsTabNewCustomsDelaySelected}"

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM