Establecer foco en TextBox en WPF desde ver modelo

129

Tengo una TextBoxy una Buttonen mi opinión.

Ahora estoy verificando una condición al hacer clic en el botón y si la condición resulta ser falsa, mostrar el mensaje al usuario, y luego tengo que configurar el cursor para el TextBoxcontrol.

if (companyref == null)
{
    var cs = new Lipper.Nelson.AdminClient.Main.Views.ContactPanels.CompanyAssociation(); 

    MessageBox.Show("Company does not exist.", "Error", MessageBoxButton.OK,
                    MessageBoxImage.Exclamation);

    cs.txtCompanyID.Focusable = true;

    System.Windows.Input.Keyboard.Focus(cs.txtCompanyID);
}

El código anterior está en ViewModel.

El CompanyAssociationes el nombre de la vista.

Pero el cursor no se está configurando en el TextBox.

El xaml es:

<igEditors:XamTextEditor Name="txtCompanyID" 
                         KeyDown="xamTextEditorAllowOnlyNumeric_KeyDown"
                         ValueChanged="txtCompanyID_ValueChanged"
                         Text="{Binding Company.CompanyId,
                                        Mode=TwoWay,
                                        UpdateSourceTrigger=PropertyChanged}"
                         Width="{Binding ActualWidth, ElementName=border}"
                         Grid.Column="1" Grid.Row="0"
                         VerticalAlignment="Top"
                         HorizontalAlignment="Stretch"
                         Margin="0,5,0,0"
                         IsEnabled="{Binding Path=IsEditable}"/>

<Button Template="{StaticResource buttonTemp1}"
        Command="{Binding ContactCommand}"
        CommandParameter="searchCompany"
        Content="Search"
        Width="80"
        Grid.Row="0" Grid.Column="2"
        VerticalAlignment="Top"
        Margin="0"
        HorizontalAlignment="Left"
        IsEnabled="{Binding Path=IsEditable}"/>
priyanka.sarkar
fuente
Cuando usa caliburn.micro, esta es una solución excelente.
matze8426

Respuestas:

264

Déjame responder a tu pregunta en tres partes.

  1. Me pregunto qué es "cs.txtCompanyID" en tu ejemplo. ¿Es un control TextBox? Si es así, entonces estás en el camino equivocado. En general, 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 foco desde ViewModel es Propiedades adjuntas. Escribí una propiedad adjunta muy simple, que se puede configurar en cualquier UIElement. Y puede vincularse a la propiedad de ViewModel "IsFocused", 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 Modelo de vista:

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

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

Salud.

Anvaka
fuente
55
Buena idea. Necesito establecer IsUserNameFocused en verdadero, luego falso nuevamente para que esto funcione, ¿es correcto?
Sam
19
También debe llamar Keyboard.Focus(uie);desde su OnIsFocusedPropertyChangedevento si desea que su control reciba Keyboard Focus y Logical Focus
Rachel
66
¿Cómo se supone que debe usarse? Si configuro mi propiedad en true, el control está enfocado. Pero siempre volverá a centrarse cuando vuelva a esta vista. Restablecerlo desde OnIsFocusedPropertyChanged no cambia esto. Restablecerlo directamente después de configurarlo desde ViewModel ya no enfoca nada. No funciona ¿Qué han hecho exactamente esos 70 votantes?
ygoe
44
También cambié la devolución de llamada a esto: a ...if ((bool)e.NewValue && uie.Dispatcher != null) { uie.Dispatcher.BeginInvoke(DispatcherPriority.Normal, (Action)(() => uie.Focus())); // invoke behaves nicer, if e.g. you have some additional handler attached to 'GotFocus' of UIE. uie.SetValue(IsFocusedProperty, false); // reset bound value if possible, to allow setting again ... veces incluso tengo que restablecer 'IsFocused' a falso en ViewModel, si quiero establecer el foco varias veces. Pero luego funciona, donde algunos otros métodos fallaron.
Simon D.
3
después de establecer el enfoque y otro control obtiene el enfoque, establecer el enfoque nuevamente no funcionará porque IsFocused sigue siendo cierto. Necesito forzarlo a falso y luego a verdadero. public bool IsFocused { get { return _isFocused; } set { if (_isFocused == value) { _isFocused = false; OnPropertyChanged(); } _isFocused = value; OnPropertyChanged(); } }
walterhuang
75

Sé que esta pregunta ha sido respondida mil veces por ahora, pero hice algunas modificaciones a la contribución de Anvaka que creo que ayudarán a otros que tuvieron problemas similares.

En primer lugar, cambié la propiedad adjunta anterior de la siguiente manera:

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 ((bool)e.NewValue)
        {
            fe.Focus();
        }
    }

    private static void fe_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
    {
        var fe = (FrameworkElement)sender;
        if (fe.IsVisible && (bool)((FrameworkElement)sender).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 concentró manualmente el control.

El otro obstáculo fue crear una forma más elegante de restablecer la propiedad subyacente a falso 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, avíseme.

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

Zamotic
fuente
9
Esto funciona bien para mí, excepto que necesito agregar una verificación "if (e.Source == e.OriginalSource)" en GotFocus / LostFocus o de lo contrario se acumula (literalmente) cuando se usa en mi UserControl, lo que redirige el foco al interior componente. Eliminé los controles visibles, aceptando el hecho de que funciona igual que el método .Focus (). Si .Focus () no funciona, el enlace no debería funcionar, y eso está bien para mi escenario.
HelloSam
1
Estoy usando esto en WF 4.5. En IsFocusedChanged tengo un escenario (una Actividad se recarga) donde e.NewValue es nulo y arroja una excepción, así que verifíquelo primero. Todo funciona bien con este cambio menor.
Olaru Mircea
1
Gracias a este wprks Genial :) Acabo de agregar '{BindsTwoWayByDefault = true}' en 'FrameworkPropertyMetadata' para establecer el modo predeterminado en TwoWayBinding para que no sea necesario en cada enlace
R00st3r
1
Me doy cuenta de que esta es una respuesta anterior, pero me encuentro con una situación en la que la propiedad IsEnabled del control al que quiero cambiar el enfoque está vinculada a un convertidor de valores múltiples. Aparentemente, se llama al controlador de eventos GotFocus antes que el convertidor de valores múltiples ... lo que significa que el control, en ese punto, está deshabilitado, por lo que tan pronto como se completa GotFocus, se llama a LostFocus (supongo que porque el control todavía está deshabilitado) . ¿Alguna idea sobre cómo manejar eso?
Mark Olbert
1
@MarkOlbert usa fe.Dispatcher.BeginInvoke(new Action(() => { fe.Focus(); }), DispatcherPriority.Loaded);que se actualiza después de cargarse. Más información aquí: telerik.com/forums/isfocused-property#OXgFYZFOg0WZ2rxidln61Q
Apfelkuacha
32

Creo que la mejor manera es mantener limpio el principio de MVVM, por lo que básicamente debe usar la clase Messenger provista con la luz MVVM y aquí está cómo usarla:

en su modelo de vista (exampleViewModel.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

Adán
fuente
9
Bueno, si desea mantener limpio el principio MVVM, no estaría escribiendo código en su código detrás en primer lugar. Creo que el enfoque de propiedad adjunto es mucho más limpio. Tampoco introduce muchas cadenas mágicas en su modelo de vista.
Ε Г И І И О
32
El Niño: ¿De dónde sacaste exactamente la idea de que no debería haber nada detrás de tu código? Cualquier cosa relacionada con la interfaz de usuario debe estar en el código subyacente de la vista. Definir el foco de los elementos de la IU debería estar definitivamente en el código subyacente de la vista. Deje que el modelo de vista descubra cuándo enviar el mensaje; deje que la vista descubra qué hacer con el mensaje. Eso es lo que hace MV-VM: separa las preocupaciones del modelo de datos, la lógica de negocios y la interfaz de usuario.
Kyle Hale
Basado en esta sugerencia, he implementado mi propio ViewCommandManager que maneja invocar comandos en vistas conectadas. Básicamente es la otra dirección de los Comandos regulares, para estos casos cuando un ViewModel necesita realizar alguna acción en su (s) Vista (s). Utiliza la reflexión como comandos vinculados a datos y WeakReferences para evitar pérdidas de memoria. dev.unclassified.de/source/viewcommand (también en CodeProject)
ygoe
Utilicé este método para imprimir WPF FlowDocuments. Funcionó muy bien. Gracias
Gordon Slysz
Quiero uno en Silverlight? ¿Podemos usarlo?
Bigeyes
18

Ninguno de estos funcionó exactamente para mí, pero para el beneficio de otros, esto es lo que terminé escribiendo en base al código que ya se proporciona aquí.

El uso sería el siguiente:

<TextBox ... h:FocusBehavior.IsFocused="True"/>

Y la implementación sería la siguiente:

/// <summary>
/// Behavior allowing to put focus on element from the view model in a MVVM implementation.
/// </summary>
public static class FocusBehavior
{
    #region Dependency Properties
    /// <summary>
    /// <c>IsFocused</c> dependency property.
    /// </summary>
    public static readonly DependencyProperty IsFocusedProperty =
        DependencyProperty.RegisterAttached("IsFocused", typeof(bool?),
            typeof(FocusBehavior), new FrameworkPropertyMetadata(IsFocusedChanged));
    /// <summary>
    /// Gets the <c>IsFocused</c> property value.
    /// </summary>
    /// <param name="element">The element.</param>
    /// <returns>Value of the <c>IsFocused</c> property or <c>null</c> if not set.</returns>
    public static bool? GetIsFocused(DependencyObject element)
    {
        if (element == null)
        {
            throw new ArgumentNullException("element");
        }
        return (bool?)element.GetValue(IsFocusedProperty);
    }
    /// <summary>
    /// Sets the <c>IsFocused</c> property value.
    /// </summary>
    /// <param name="element">The element.</param>
    /// <param name="value">The value.</param>
    public static void SetIsFocused(DependencyObject element, bool? value)
    {
        if (element == null)
        {
            throw new ArgumentNullException("element");
        }
        element.SetValue(IsFocusedProperty, value);
    }
    #endregion Dependency Properties

    #region Event Handlers
    /// <summary>
    /// Determines whether the value of the dependency property <c>IsFocused</c> has change.
    /// </summary>
    /// <param name="d">The dependency object.</param>
    /// <param name="e">The <see cref="System.Windows.DependencyPropertyChangedEventArgs"/> instance containing the event data.</param>
    private static void IsFocusedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        // Ensure it is a FrameworkElement instance.
        var fe = d as FrameworkElement;
        if (fe != null && e.OldValue == null && e.NewValue != null && (bool)e.NewValue)
        {
            // Attach to the Loaded event to set the focus there. If we do it here it will
            // be overridden by the view rendering the framework element.
            fe.Loaded += FrameworkElementLoaded;
        }
    }
    /// <summary>
    /// Sets the focus when the framework element is loaded and ready to receive input.
    /// </summary>
    /// <param name="sender">The sender.</param>
    /// <param name="e">The <see cref="System.Windows.RoutedEventArgs"/> instance containing the event data.</param>
    private static void FrameworkElementLoaded(object sender, RoutedEventArgs e)
    {
        // Ensure it is a FrameworkElement instance.
        var fe = sender as FrameworkElement;
        if (fe != null)
        {
            // Remove the event handler registration.
            fe.Loaded -= FrameworkElementLoaded;
            // Set the focus to the given framework element.
            fe.Focus();
            // Determine if it is a text box like element.
            var tb = fe as TextBoxBase;
            if (tb != null)
            {
                // Select all text to be ready for replacement.
                tb.SelectAll();
            }
        }
    }
    #endregion Event Handlers
}
Leo Vildosola
fuente
11

Este es un hilo viejo, pero no parece haber una respuesta con un código que aborde los problemas con la respuesta aceptada de Anavanka: no funciona si establece la propiedad en el modelo de vista en falso, o si establece su propiedad en cierto, el usuario hace clic manualmente en otra cosa y luego lo configura en verdadero nuevamente. Tampoco pude lograr que la solución de Zamotic funcionara de manera confiable en estos casos.

Reunir algunas de las discusiones anteriores me da el código a continuación que aborda estos problemas, creo:

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, null, OnCoerceValue));

    private static object OnCoerceValue(DependencyObject d, object baseValue)
    {
        if ((bool)baseValue)
            ((UIElement)d).Focus();
        else if (((UIElement) d).IsFocused)
            Keyboard.ClearFocus();
        return ((bool)baseValue);
    }
}

Dicho esto, esto sigue siendo complejo para algo que se puede hacer en una línea en código subyacente, y CoerceValue no está destinado a ser utilizado de esta manera, por lo que tal vez el código subyacente sea el camino a seguir.

Rico n
fuente
1
Esto funciona de manera consistente, mientras que la respuesta aceptada no. ¡Gracias!
NathanAldenSr
4

En mi caso, FocusExtension no funcionó hasta que cambié el método OnIsFocusedPropertyChanged. El original solo funcionaba en la depuración cuando un punto de interrupción detenía el proceso. En tiempo de ejecución, el proceso es demasiado rápido y no pasa nada. Con esta pequeña modificación y la ayuda de nuestro amigo Task, esto está funcionando bien en ambos escenarios.

private static void OnIsFocusedPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
  var uie = (UIElement)d;
  if ((bool)e.NewValue)
  {
    var action = new Action(() => uie.Dispatcher.BeginInvoke((Action)(() => uie.Focus())));
    Task.Factory.StartNew(action);
  }
}
Vincent Rithner
fuente
3

El problema es que una vez que IsUserNameFocused se establece en verdadero, nunca será falso. Esto lo resuelve manejando GotFocus y LostFocus para FrameworkElement.

Estaba teniendo problemas con el formato del código fuente, así que aquí hay un enlace

Shawn
fuente
1
Cambié "object fe = (FrameworkElement) d;" a "FrameworkElement fe = (FrameworkElement) d;" así funciona el intellisense
Todavía no resuelve el problema. El elemento permanece enfocado cada vez que vuelvo a él.
ygoe
3

El código brillante de Anvakas es para aplicaciones de escritorio de Windows. Si eres como yo y necesitas la misma solución para las aplicaciones de la Tienda Windows, este código puede ser útil:

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 PropertyMetadata(false, OnIsFocusedPropertyChanged));


    private static void OnIsFocusedPropertyChanged(DependencyObject d,
        DependencyPropertyChangedEventArgs e)
    {
        if ((bool)e.NewValue)
        {
            var uie = d as Windows.UI.Xaml.Controls.Control;

            if( uie != null )
            {
                uie.Focus(FocusState.Programmatic);
            }
        }
    }
}
PEK
fuente
1

Para aquellos que intentaban usar la solución de Anvaka anterior, tenía problemas con el enlace que solo funcionaba la primera vez, ya que lostfocus no actualizaría la propiedad a falso. Puede establecer manualmente la propiedad en falso y luego en verdadero cada vez, pero una mejor solución podría ser hacer algo como esto en su propiedad:

bool _isFocused = false;
    public bool IsFocused 
    {
        get { return _isFocused ; }
        set
        {
            _isFocused = false;
            _isFocused = value;
            base.OnPropertyChanged("IsFocused ");
        }
    }

De esta manera, solo necesita establecerlo en verdadero, y se enfocará.

Kyeotic
fuente
¿Por qué tienes una declaración if? _isFocused una vez establecido en false solo se cambiará al valor en la siguiente línea.
Damien McGivern
1
@Tyrsius Puede solucionar este problema enviando la propiedad de dependencia a Coerce, consulte aquí- social.msdn.microsoft.com/Forums/en-US/wpf/thread/…
RichardOD
1

He encontrado solución editando el código según lo siguiente. No es necesario establecer primero la propiedad de enlace Falso y luego Verdadero.

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)
    {
        if (d != null && d is Control)
        {
            var _Control = d as Control;
            if ((bool)e.NewValue)
            {
                // To set false value to get focus on control. if we don't set value to False then we have to set all binding
                //property to first False then True to set focus on control.
                OnLostFocus(_Control, null);
                _Control.Focus(); // Don't care about false values.
            }
        }
    }

    private static void OnLostFocus(object sender, RoutedEventArgs e)
    {
        if (sender != null && sender is Control)
        {
            (sender as Control).SetValue(IsFocusedProperty, false);
        }
    }
}
Bharat Mendapara
fuente
0

Para Silverlight:

using System.Windows;
using System.Windows.Controls;
using System.Windows.Interactivity;

namespace MyProject.Behaviors
{
    public class FocusBehavior : Behavior<Control>
    {
        protected override void OnAttached()
        {
            this.AssociatedObject.Loaded += AssociatedObject_Loaded;
            base.OnAttached();
        }

        private void AssociatedObject_Loaded(object sender, RoutedEventArgs e)
        {
            this.AssociatedObject.Loaded -= AssociatedObject_Loaded;
            if (this.HasInitialFocus || this.IsFocused)
            {
                this.GotFocus();
            }
        }

        private void GotFocus()
        {
            this.AssociatedObject.Focus();
            if (this.IsSelectAll)
            {
                if (this.AssociatedObject is TextBox)
                {
                    (this.AssociatedObject as TextBox).SelectAll();
                }
                else if (this.AssociatedObject is PasswordBox)
                {
                    (this.AssociatedObject as PasswordBox).SelectAll();
                }
                else if (this.AssociatedObject is RichTextBox)
                {
                    (this.AssociatedObject as RichTextBox).SelectAll();
                }
            }
        }

        public static readonly DependencyProperty IsFocusedProperty =
            DependencyProperty.Register(
                "IsFocused",
                typeof(bool),
                typeof(FocusBehavior),
                new PropertyMetadata(false, 
                    (d, e) => 
                    {
                        if ((bool)e.NewValue)
                        {
                            ((FocusBehavior)d).GotFocus();
                        }
                    }));

        public bool IsFocused
        {
            get { return (bool)GetValue(IsFocusedProperty); }
            set { SetValue(IsFocusedProperty, value); }
        }

        public static readonly DependencyProperty HasInitialFocusProperty =
            DependencyProperty.Register(
                "HasInitialFocus",
                typeof(bool),
                typeof(FocusBehavior),
                new PropertyMetadata(false, null));

        public bool HasInitialFocus
        {
            get { return (bool)GetValue(HasInitialFocusProperty); }
            set { SetValue(HasInitialFocusProperty, value); }
        }

        public static readonly DependencyProperty IsSelectAllProperty =
            DependencyProperty.Register(
                "IsSelectAll",
                typeof(bool),
                typeof(FocusBehavior),
                new PropertyMetadata(false, null));

        public bool IsSelectAll
        {
            get { return (bool)GetValue(IsSelectAllProperty); }
            set { SetValue(IsSelectAllProperty, value); }
        }

    }
}

LoginViewModel.cs:

    public class LoginModel : ViewModelBase
    {
        ....

        private bool _EmailFocus = false;
        public bool EmailFocus
        {
            get
            {
                return _EmailFocus;
            }
            set
            {
                if (value)
                {
                    _EmailFocus = false;
                    RaisePropertyChanged("EmailFocus");
                }
                _EmailFocus = value;
                RaisePropertyChanged("EmailFocus");
            }
        }
       ...
   }

Login.xaml:

xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:beh="clr-namespace:MyProject.Behaviors"

<TextBox Text="{Binding Email, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
    <i:Interaction.Behaviors>
        <beh:FocusBehavior IsFocused="{Binding EmailFocus}" IsSelectAll="True"/>
    </i:Interaction.Behaviors>
</TextBox>

O

<TextBox Text="{Binding Email, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
    <i:Interaction.Behaviors>
        <beh:FocusBehavior HasInitialFocus="True" IsSelectAll="True"/>
    </i:Interaction.Behaviors>
</TextBox>

Para establecer el foco solo debes hacerlo en código:

EmailFocus = true;

Recuerde que este complemento es parte de una página html, por lo que otros controles en la página pueden tener el foco

if (!Application.Current.IsRunningOutOfBrowser)
{
    System.Windows.Browser.HtmlPage.Plugin.Focus();
}
ADMITIR
fuente
0

Puede usar el patrón de diseño ViewCommand . Describe un método para el patrón de diseño MVVM para controlar una vista desde un modelo de vista con comandos.

Lo implementé en base a la sugerencia del Rey A.Majid de usar la clase MVVM Light Messenger. La clase ViewCommandManager maneja los comandos de invocación en vistas conectadas. Básicamente es la otra dirección de los Comandos regulares, en estos casos cuando un ViewModel necesita realizar alguna acción en su Vista. Utiliza la reflexión como comandos vinculados a datos y WeakReferences para evitar pérdidas de memoria.

http://dev.unclassified.de/source/viewcommand (también publicado en CodeProject)

ygoe
fuente
0

Nadie parece haber incluido el paso final para facilitar la actualización de atributos a través de variables enlazadas. Esto es lo que se me ocurrió. Avíseme si hay una mejor manera de hacerlo.

XAML

    <TextBox x:Name="txtLabel"
      Text="{Binding Label}"
      local:FocusExtension.IsFocused="{Binding txtLabel_IsFocused, Mode=TwoWay}" 
     />

    <Button x:Name="butEdit" Content="Edit"
        Height="40"  
        IsEnabled="{Binding butEdit_IsEnabled}"                        
        Command="{Binding cmdCapsuleEdit.Command}"                            
     />   

ViewModel

    public class LoginModel : ViewModelBase
    {

    public string txtLabel_IsFocused { get; set; }                 
    public string butEdit_IsEnabled { get; set; }                


    public void SetProperty(string PropertyName, string value)
    {
        System.Reflection.PropertyInfo propertyInfo = this.GetType().GetProperty(PropertyName);
        propertyInfo.SetValue(this, Convert.ChangeType(value, propertyInfo.PropertyType), null);
        OnPropertyChanged(PropertyName);
    }                


    private void Example_function(){

        SetProperty("butEdit_IsEnabled", "False");
        SetProperty("txtLabel_IsFocused", "True");        
    }

    }
Hugh
fuente
0

En primer lugar, me gustaría agradecer a Avanka por ayudarme a resolver mi problema de enfoque. Sin embargo, hay un error en el código que publicó, es decir, en la línea: if (e.OldValue == null)

El problema que tuve fue que si primero haces clic en tu vista y enfocas el control, e.oldValue ya no es nulo. Luego, cuando configura la variable para enfocar el control por primera vez, esto da como resultado que no se configuren los controladores de enfoque perdido y enfocado. Mi solución a esto fue la siguiente:

public static class ExtensionFocus
    {
    static ExtensionFocus()
        {
        BoundElements = new List<string>();
        }

    public static readonly DependencyProperty IsFocusedProperty =
        DependencyProperty.RegisterAttached("IsFocused", typeof(bool?),
        typeof(ExtensionFocus), new FrameworkPropertyMetadata(false, IsFocusedChanged));

    private static List<string> BoundElements;

    public static bool? GetIsFocused(DependencyObject element)
        {
        if (element == null)
            {
            throw new ArgumentNullException("ExtensionFocus GetIsFocused called with null element");
            }
        return (bool?)element.GetValue(IsFocusedProperty);
        }

    public static void SetIsFocused(DependencyObject element, bool? value)
        {
        if (element == null)
            {
            throw new ArgumentNullException("ExtensionFocus SetIsFocused called with null element");
            }
        element.SetValue(IsFocusedProperty, value);
        }

    private static void IsFocusedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
        var fe = (FrameworkElement)d;

        // OLD LINE:
        // if (e.OldValue == null)
        // TWO NEW LINES:
        if (BoundElements.Contains(fe.Name) == false)
            {
            BoundElements.Add(fe.Name);
            fe.LostFocus += OnLostFocus;
            fe.GotFocus += OnGotFocus;
            }           


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

        if ((bool)e.NewValue)
            {
            fe.Focus();             
            }
        }

    private static void fe_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
        {
        var fe = (FrameworkElement)sender;

        if (fe.IsVisible && (bool)((FrameworkElement)sender).GetValue(IsFocusedProperty))
            {
            fe.IsVisibleChanged -= fe_IsVisibleChanged;
            fe.Focus();
            }
        }

    private static void OnLostFocus(object sender, RoutedEventArgs e)
        {
        if (sender != null && sender is Control s)
            {
            s.SetValue(IsFocusedProperty, false);
            }
        }

    private static void OnGotFocus(object sender, RoutedEventArgs e)
        {
        if (sender != null && sender is Control s)
            {
            s.SetValue(IsFocusedProperty, true);
            }
        }
    }
user2127475
fuente
0

Solo haz esto:

<Window x:class...
   ...
   ...
   FocusManager.FocusedElement="{Binding ElementName=myTextBox}"
>
<Grid>
<TextBox Name="myTextBox"/>
...
Zoltan
fuente
Me gusta esto. Esto funciona bien si desea establecer el foco inicial.
user2430797
0

Después de implementar la respuesta aceptada, me encontré con un problema que al navegar por las vistas con Prism el TextBox todavía no se enfocaba. Un pequeño cambio en el controlador PropertyChanged lo resolvió

    private static void OnIsFocusedPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var uie = (UIElement)d;
        if ((bool)e.NewValue)
        {
            uie.Dispatcher.BeginInvoke(DispatcherPriority.Input, new Action(() =>
            {
                uie.Focus();
            }));
        }
    }
Joe H
fuente
0

Un enfoque alternativo basado en @Sheridan responde aquí

 <TextBox Text="{Binding SomeText, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
        <TextBox.Style>
            <Style>
                <Style.Triggers>
                    <DataTrigger Binding="{Binding SomeTextIsFocused, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Value="True">
                        <Setter Property="FocusManager.FocusedElement" Value="{Binding RelativeSource={RelativeSource Self}}" />
                    </DataTrigger>
                </Style.Triggers>
            </Style>
        </TextBox.Style>
    </TextBox>

En su modelo de vista, configure su enlace de la manera habitual y luego configure SomeTextIsFocused en true para establecer el foco en su cuadro de texto

stuicidle
fuente
-1

La solución de Crucial para el problema de IsVisible me pareció muy útil. No resolvió completamente mi problema, pero sí lo hizo un código adicional que seguía el mismo patrón para el patrón IsEnabled.

Al método IsFocusedChanged agregué:

    if (!fe.IsEnabled)
    {
        fe.IsEnabledChanged += fe_IsEnabledChanged;
    }

Y aquí está el controlador:

private static void fe_IsEnabledChanged(object sender, DependencyPropertyChangedEventArgs e)
{
    var fe = (FrameworkElement)sender;
    if (fe.IsEnabled && (bool)((FrameworkElement)sender).GetValue(IsFocusedProperty))
    {
        fe.IsEnabledChanged -= fe_IsEnabledChanged;
        fe.Focus();
    }
}
Wayne Maurer
fuente
-1
public class DummyViewModel : ViewModelBase
    {
        private bool isfocused= false;
        public bool IsFocused
        {
            get
            {
                return isfocused;
            }
            set
            {
                isfocused= value;
                OnPropertyChanged("IsFocused");
            }
        }
    }
Jayasri
fuente
-7
System.Windows.Forms.Application.DoEvents();
Keyboard.Focus(tbxLastName);
KitWest
fuente
1
OP está utilizando WPF. El código de enfoque para WinForms no va a ayudar.
Josh G