wpf 仅使用 XAML 聚焦文本框

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/15783535/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-13 08:27:09  来源:igfitidea点击:

Focus Textbox using only XAML

wpfxamltextboxfocus

提问by John

I'm trying to set the keyboard focus to a textbox that is included in a stackpanel collapsed by default. When the stackpanel becomes visible i want the textbox to become, by default, focused.

我正在尝试将键盘焦点设置为默认情况下折叠的堆栈面板中包含的文本框。当堆栈面板变得可见时,我希望文本框默认成为焦点。

I've tried this code:

我试过这个代码:

<StackPanel Orientation="Vertical" FocusManager.FocusedElement="{Binding ElementName=TxtB}">
  <TextBox x:Name="TxtA" Text="A" />
  <TextBox x:Name="TxtB" Text="B" />
</StackPanel>

However, it didn't work. The type cursor showed up, but it wasn't blinking and didn't allow writing.

然而,它没有用。类型光标出现了,但它没有闪烁,也不允许写入。

Is it possible to solve my problem using only XAML? Perhaps triggers?

是否可以仅使用 XAML 来解决我的问题?也许触发器?

回答by icebat

Yes, as you said yourself, simple trigger seems to do the trick:

是的,正如您自己所说,简单的触发器似乎可以解决问题:

<StackPanel Orientation="Vertical">
    <StackPanel.Style>
       <Style TargetType="StackPanel">
          <Style.Triggers>
              <Trigger Property="Visibility" Value="Visible">
                  <Setter Property="FocusManager.FocusedElement" 
                          Value="{Binding ElementName=TxtA}" />
              </Trigger>
          </Style.Triggers>
       </Style>
    </StackPanel.Style>

    <TextBox x:Name="TxtA" Text="A" />
    <TextBox x:Name="TxtB" Text="B" />
</StackPanel>

回答by Pavel Voronin

You need to create attached property IsFocused which will call Focus() method of the attached element when set to true. Wait, I'll add some code.

您需要创建附加属性 IsFocused,该属性将在设置为 true 时调用附加元素的 Focus() 方法。等等,我会添加一些代码。

public static class FocusHelper
    {
        static FocusHelper()
        {
            var fpmd = new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, HandleAttachedIsFocusedChanged) { DefaultUpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged };
            IsFocusedProperty = DependencyProperty.RegisterAttached("IsFocused", typeof(bool?), typeof(FocusHelper), fpmd);
        }

        public static readonly DependencyProperty IsFocusedProperty;

        [Conditional("DEBUG")]
        public static void StartFocusTracing()
        {
            FocusManager.FocusedElementProperty.OverrideMetadata(typeof(FrameworkElement), new PropertyMetadata(HandleFocusedElementChanged));
        }

        private static void HandleFocusedElementChanged(DependencyObject o, DependencyPropertyChangedEventArgs args)
        {
            var element = args.NewValue as FrameworkElement;
            if (element == null)
            {
                Debug.WriteLine("Focus is lost");
                return;
            }

            Debug.WriteLine("Focus moved to {0} type {1}", element.Name, element.GetType().Name);

            var fs = FocusManager.GetFocusScope(element) as FrameworkElement;
            if (fs == null)
                return;

            Debug.WriteLine("Focus scope {0} of type {1}", fs.Name, fs.GetType().Name);
        }

        public static bool? GetIsFocused(DependencyObject element)
        {
            if (element == null)
            {
                throw new ArgumentNullException("element");
            }

            return (bool?)element.GetValue(IsFocusedProperty);
        }

        public static void SetIsFocused(DependencyObject element, bool? value)
        {
            if (element == null)
                throw new ArgumentNullException("element");

            element.SetValue(IsFocusedProperty, value);
        }

        private static void HandleAttachedIsFocusedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            WriteDependencyPropertyBindingInformation(d, IsFocusedProperty);

            var fe = (UIElement)d;

            // значение ранее было не задано
            if (e.OldValue == null)
            {
                var pd = DependencyPropertyDescriptor.FromProperty(UIElement.IsFocusedProperty, typeof(UIElement));
                pd.AddValueChanged(fe, HandleUIElementIsFocusedChanged);
            }

            if (e.NewValue == null)
            {
                var pd = DependencyPropertyDescriptor.FromProperty(UIElement.IsFocusedProperty, typeof(UIElement));
                pd.RemoveValueChanged(fe, HandleUIElementIsFocusedChanged);
                return;
            }

            if ((bool)e.NewValue)
            {
                Action setFocus = () =>
                    {
                        IInputElement elementToBeFocused = null;
                        IInputElement finalyFocusedElement = null;
                        // If current element is Focus Scope we try to restore logical focus
                        if (FocusManager.GetIsFocusScope(fe))
                        {
                            elementToBeFocused = FocusManager.GetFocusedElement(fe);
                            if (elementToBeFocused != null)
                            {
                                finalyFocusedElement = Keyboard.Focus(elementToBeFocused);
                            }
                        }

                        // If focus was not restored we try to focus
                        if (finalyFocusedElement == null
                            || (elementToBeFocused != finalyFocusedElement))
                        {
                            fe.FocusThisOrChild();
                        }
                    };
                if (ReflectionHelper.IsInMethod("MeasureOverride", typeof(FrameworkElement))) // hack of layout issue
                    Dispatcher.CurrentDispatcher.BeginInvoke(setFocus);
                else
                    setFocus();
            }
        }

        [Conditional("DEBUG")]
        private static void WriteDependencyPropertyBindingInformation(DependencyObject d, DependencyProperty property)
        {
            var binding = BindingOperations.GetBindingBase(d, IsFocusedProperty);

            if (binding == null)
            {
                Debug.WriteLine("Property {1} of object {0} has no bindings.", d, property.Name);
            }
            else
            {
                Debug.WriteLine("Property {1} of object {0} has binding.", d, property.Name);
                Debug.WriteLine("Type {0}", binding.GetType());

                var expressionBase = BindingOperations.GetBindingExpressionBase(d, IsFocusedProperty);
                Debug.Assert(expressionBase != null);

                Debug.WriteLine("Status {0}", expressionBase.Status);

                var expression = expressionBase as BindingExpression;
                if (expression != null)
                {
                    Debug.WriteLine("Source type {0}", expression.DataItem.GetType());
                    Debug.WriteLine("Source {0}",expression.DataItem);
                }
            }
        }   


        private static void HandleUIElementIsFocusedChanged(object sender, EventArgs e)
        {
            var uiElement = sender as UIElement;
            var isFocused = uiElement.IsFocused;
            ((DependencyObject)sender).SetCurrentValue(IsFocusedProperty, isFocused);
        }

        /// <summary>
        /// Tries to set focus to the element or any child element inside this one.
        /// Tab index is respected
        /// </summary>
        public static bool FocusThisOrChild(this DependencyObject element)
        {
            if (element == null)
                throw new ArgumentNullException("element");

            var inputElement = element as IInputElement;
            var wasFocused = inputElement != null && inputElement.Focus();

            if (!wasFocused)
            {
                element.SetFocusWithin();
            }

            return true;
        }

        public static bool SetFocusWithin(this DependencyObject element)
        {
            if (element == null)
                throw new ArgumentNullException("element");

            var children = element.GetVisualChildrenSortedByTabIndex();
            return children.Any(FocusThisOrChild);
        }
    }

and helper methods:

和辅助方法:

public static IEnumerable<DependencyObject> GetVisualChildrenSortedByTabIndex(this DependencyObject parent)
        {
            if (parent == null)
                throw new ArgumentNullException("parent");

            return parent.GetVisualChildren().OrderBy(KeyboardNavigation.GetTabIndex);
        }



public static bool IsInMethod(string methodName, Type ownerType, bool isStatic = false)
        {
            if (string.IsNullOrWhiteSpace(methodName))
                throw new ArgumentNullException("methodName");

            if (ownerType == null)
                throw new ArgumentNullException("ownerType");

            var stackTrace = new StackTrace(false);
            var isInMethod = stackTrace.GetFrames().Skip(1).Any(frame =>
                       {
                           var method = frame.GetMethod();
                           return method.Name == methodName
                                  && method.IsStatic == isStatic
                                  && ownerType.IsAssignableFrom(method.ReflectedType);
                       });

            return isInMethod;
        }