Set focus on TextBox in WPF from view model

后端 未结 21 2216
爱一瞬间的悲伤
爱一瞬间的悲伤 2020-11-22 06:21

I have a TextBox and a Button in my view.

Now I am checking a condition upon button click and if the condition turns out to be false, displ

相关标签:
21条回答
  • 2020-11-22 06:32

    I have found solution by editing code as per following. There is no need to set Binding property first False then True.

    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);
            }
        }
    }
    
    0 讨论(0)
  • 2020-11-22 06:34

    Nobody seems to have included the final step to make it easy to update attributes via binded variables. Here's what I came up with. Let me know if there is a better way of doing this.

    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");        
        }
    
        }
    
    0 讨论(0)
  • 2020-11-22 06:35

    In my case, the FocusExtension didn't work until I change the method OnIsFocusedPropertyChanged. The original one was working only in debug when a break point stopped the process. At runtime, the process is too quick and nothing happend. With this little modification and the help of our friend Task, this is working fine in both scenarios.

    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);
      }
    }
    
    0 讨论(0)
  • 2020-11-22 06:37

    I think the best way is to keep the MVVM principle clean, so basically you must use the Messenger Class provided with the MVVM Light and here is how to use it:

    in your viewmodel(exampleViewModel.cs):write the following

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

    now in your View.cs(not the XAML the view.xaml.cs) write the following in the constructor

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

    that method owrks just fine and with less code and maintaining MVVM standards

    0 讨论(0)
  • 2020-11-22 06:38

    You could use the ViewCommand design pattern. It describes a method for the MVVM design pattern to control a View from a ViewModel with commands.

    I've implemented it based on King A.Majid's suggestion to use the MVVM Light Messenger class. The ViewCommandManager class handles invoking commands in connected views. It's basically the other direction of regular Commands, for these cases when a ViewModel needs to do some action in its View. It uses reflection like data-bound commands and WeakReferences to avoid memory leaks.

    http://dev.unclassified.de/source/viewcommand (also published on CodeProject)

    0 讨论(0)
  • 2020-11-22 06:39

    Anvakas brilliant code is for Windows Desktop applications. If you are like me and needed the same solution for Windows Store apps this code might be handy:

    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);
                }
            }
        }
    }
    
    0 讨论(0)
提交回复
热议问题