【问题标题】:Focus Textbox using only XAML仅使用 XAML 聚焦文本框
【发布时间】:2013-03-24 21:27:16
【问题描述】:

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

我试过这段代码:

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

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

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

【问题讨论】:

    标签: wpf xaml textbox focus


    【解决方案1】:

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

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

    【讨论】:

    • 我不认为你知道这样一个简单的解决方案,只在 Silverlight 中用 xaml 做同样的事情,对吗?我尝试了相同的概念,但没有这样的运气,并且一直在为此寻找一个简单的临时解决方案。
    • @ChrisW.,我知道没有这么简单的 Silverlight 解决方案。
    【解决方案2】:

    您需要创建附加属性 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);
            }
        }
    

    和辅助方法:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-10-19
      • 2023-03-29
      • 2023-03-26
      • 1970-01-01
      相关资源
      最近更新 更多