2013-04-03 4 views
3

Я пытаюсь настроить фокус клавиатуры на текстовое поле, которое включено в стеке стека, рухнувшее по умолчанию. Когда стекная панель становится видимой, я хочу, чтобы текстовое поле стало, по умолчанию, сфокусированным.Фокус Текстовое поле с использованием только XAML

Я попробовал этот код:

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

Однако, это не сработало. Появился курсор типа, но он не мигал и не позволял писать.

Можно ли решить мою проблему, используя только XAML? Возможно, триггеры?

ответ

1

Вам необходимо создать прикрепленное свойство IsFocused, которое вызовет метод Focus() прикрепленного элемента, если установлено значение true. Подождите, я добавлю код.

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

Да, как вы сказали сами, просто триггер, кажется, сделать трюк:

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

Я не думаю, что вы знаете о такой простой решение сделать то же самое с xaml только в Silverlight, не так ли? Я попробовал ту же концепцию, но не имел такой удачи и искал для этого простое решение adhoc. –

+0

@ChrisW., Нет таких простых решений Silverlight, о которых я знаю. – icebat

Смежные вопросы