Saltar al contenido

Establecer el foco en TextBox en WPF desde el modelo de vista

Solución:

Déjame responder a tu pregunta en tres partes.

  1. Me pregunto qué es “cs.txtCompanyID” en su ejemplo. ¿Es un control TextBox? Si es así, entonces está en el camino equivocado. En términos generales, no es una buena idea tener ninguna referencia a la interfaz de usuario en su ViewModel. Puedes preguntar “¿Por qué?” pero esta es otra pregunta para publicar en Stackoverflow :).

  2. La mejor manera de rastrear problemas con Focus es … depurar el código fuente .Net. En serio. Me ahorró mucho tiempo muchas veces. Para habilitar la depuración del código fuente .net, consulte el blog de Shawn Bruke.

  3. Finalmente, el enfoque general que utilizo para establecer el enfoque desde ViewModel es Propiedades adjuntas. Escribí una propiedad adjunta muy simple, que se puede establecer en cualquier UIElement. Y se puede vincular a la propiedad “IsFocused” de ViewModel, por ejemplo. Aquí está:

    public static class FocusExtension
    {
        public static bool GetIsFocused(DependencyObject obj)
        {
            return (bool) obj.GetValue(IsFocusedProperty);
        }
    
        public static void SetIsFocused(DependencyObject obj, bool value)
        {
            obj.SetValue(IsFocusedProperty, value);
        }
    
        public static readonly DependencyProperty IsFocusedProperty =
            DependencyProperty.RegisterAttached(
                "IsFocused", typeof (bool), typeof (FocusExtension),
                new UIPropertyMetadata(false, OnIsFocusedPropertyChanged));
    
        private static void OnIsFocusedPropertyChanged(
            DependencyObject d, 
            DependencyPropertyChangedEventArgs e)
        {
            var uie = (UIElement) d;
            if ((bool) e.NewValue)
            {
                uie.Focus(); // Don't care about false values.
            }
        }
    }
    

    Ahora en su Vista (en XAML) puede vincular esta propiedad a su ViewModel:

    <TextBox local:FocusExtension.IsFocused="{Binding IsUserNameFocused}" />
    

Espero que esto ayude :). Si no se refiere a la respuesta n. ° 2.

Salud.

Sé que esta pregunta ha sido respondida mil veces hasta ahora, pero hice algunas modificaciones a la contribución de Anvaka que creo que ayudarán a otros que tenían problemas similares a los que yo tuve.

En primer lugar, cambié la propiedad adjunta anterior así:

public static class FocusExtension
{
    public static readonly DependencyProperty IsFocusedProperty = 
        DependencyProperty.RegisterAttached("IsFocused", typeof(bool?), typeof(FocusExtension), new FrameworkPropertyMetadata(IsFocusedChanged){BindsTwoWayByDefault = true});

    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 IsFocusedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var fe = (FrameworkElement)d;

        if (e.OldValue == null)
        {
            fe.GotFocus += FrameworkElement_GotFocus;
            fe.LostFocus += FrameworkElement_LostFocus;
        }

        if (!fe.IsVisible)
        {
            fe.IsVisibleChanged += new DependencyPropertyChangedEventHandler(fe_IsVisibleChanged);
        }

        if (e.NewValue != null && (bool)e.NewValue)
        {
            fe.Focus();
        }
    }

    private static void fe_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
    {
        var fe = (FrameworkElement)sender;
        if (fe.IsVisible && (bool)fe.GetValue(IsFocusedProperty))
        {
            fe.IsVisibleChanged -= fe_IsVisibleChanged;
            fe.Focus();
        }
    }

    private static void FrameworkElement_GotFocus(object sender, RoutedEventArgs e)
    {
        ((FrameworkElement)sender).SetValue(IsFocusedProperty, true);
    }

    private static void FrameworkElement_LostFocus(object sender, RoutedEventArgs e)
    {
        ((FrameworkElement)sender).SetValue(IsFocusedProperty, false);
    }
}

Mi razón para agregar las referencias de visibilidad fueron las pestañas. Aparentemente, si usó la propiedad adjunta en cualquier otra pestaña fuera de la pestaña inicialmente visible, la propiedad adjunta no funcionó hasta que enfocó manualmente el control.

El otro obstáculo fue crear una forma más elegante de restablecer la propiedad subyacente a falsa cuando perdió el foco. Ahí es donde entraron los eventos de enfoque perdido.

<TextBox            
    Text="{Binding Description}"
    FocusExtension.IsFocused="{Binding IsFocused}"/>

Si hay una mejor manera de manejar el problema de visibilidad, hágamelo saber.

Nota: Gracias a Apfelkuacha por la sugerencia de poner BindsTwoWayByDefault en DependencyProperty. Lo había hecho hace mucho tiempo en mi propio código, pero nunca actualicé esta publicación. El Mode = TwoWay ya no es necesario en el código WPF debido a este cambio.

Creo que la mejor manera es mantener limpio el principio MVVM, así que básicamente debes usar la clase Messenger proporcionada con MVVM Light y aquí se explica cómo usarla:

en su modelo de vista (ejemploViewModel.cs): escriba lo siguiente

 Messenger.Default.Send<string>("focus", "DoFocus");

ahora en su View.cs (no el XAML el view.xaml.cs) escriba lo siguiente en el constructor

 public MyView()
        {
            InitializeComponent();

            Messenger.Default.Register<string>(this, "DoFocus", doFocus);
        }
        public void doFocus(string msg)
        {
            if (msg == "focus")
                this.txtcode.Focus();
        }

ese método funciona bien y con menos código y manteniendo los estándares MVVM

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *