我的视图中有一个TextBox和一个Button

现在,我在单击按钮时检查条件,如果条件变为假,则向用户显示消息,然后我必须将光标设置到TextBox控件。

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


上面的代码在ViewModel中。

CompanyAssociation是视图名称。

,但是没有在TextBox中设置光标。

xaml是:

<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}"/>


评论

当您使用caliburn.micro时,这是一个绝佳的解决方案。

#1 楼

让我分三个部分回答您的问题。


我想知道您的示例中的“ cs.txtCompanyID”是什么?它是TextBox控件吗?如果是,则说明您的方法错误。一般来说,在ViewModel中对UI进行任何引用不是一个好主意。您可以问“为什么?”但这是在Stackoverflow上发布的另一个问题:)。
跟踪Focus问题的最佳方法是...调试.Net源代码。别开玩笑了它多次节省了我很多时间。要启用.net源代码调试,请参阅Shawn Bruke的博客。最后,我用来从ViewModel设置焦点的一般方法是Attached Properties。我写了非常简单的附加属性,可以在任何UIElement上进行设置。例如,它可以绑定到ViewModel的属性“ IsFocused”。它是:

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


现在,在您的View中(在XAML中),您可以将此属性绑定到您的ViewModel:

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



希望这会有所帮助:)。如果不是,请参考答案2。

干杯。

评论


好主意。我需要将IsUserNameFocused设置为true,然后再次设置为false,以使其正常工作,对吗?

–山姆
2010-4-19的14:19

您还应该调用Keyboard.Focus(uie);。如果希望控件获得键盘焦点和逻辑焦点,则从OnIsFocusedPropertyChanged事件中获取

–雷切尔(Rachel)
2011年10月10日18:14

应该如何使用?如果将属性设置为true,则控件将处于焦点状态。但是,当我回到这种观点时,它总是会再次聚焦。从OnIsFocusedPropertyChanged重置它不会更改此设置。从ViewModel设置它之后直接将其重置将不再关注任何事情。没用那70名支持者到底做了什么?

– ygoe
13年2月26日在23:02

我也将回调更改为:... if((bool)e.NewValue && uie.Dispatcher!= null){uie.Dispatcher.BeginInvoke(DispatcherPriority.Normal,(Action)(()=> uie.Focus( ))); //调用行为会更好,例如您有一些附加的处理程序附加到UIE的“ GotFocus”。 uie.SetValue(IsFocusedProperty,false); //如果可能,请重设界限值,以允许再次设置...有时,如果我想多次设置焦点,我什至必须在ViewModel中将'IsFocused'重设为false。但是随后它起作用了,其他一些方法失败了。

–西蒙·D。
2013年9月30日9:29



设置焦点并且另一个控件获得焦点后,重新设置焦点将不起作用,因为IsFocused仍然为true。需要将其强制为假,然后再为真。公共布尔IsFocused {get {return _isFocused; }设置{如果(_isFocused ==值){_isFocused = false; OnPropertyChanged(); } _isFocused =值; OnPropertyChanged(); }}

– Walterhuang
18年6月29日在17:36

#2 楼

我知道这个问题到目前为止已经被回答了上千次,但是我对Anvaka的贡献进行了一些编辑,我认为这将帮助其他遇到类似问题的人。
首先,我像上面那样更改了上面的附加财产:
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)((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);
    }
}

我添加可见性引用的原因是标签。显然,如果您在最初可见的选项卡之外的任何其他选项卡上使用了附加属性,则直到您手动将控件聚焦后,附加属性才起作用。
另一个障碍是创建一种更优雅的方式来重置基础属性当它失去焦点时为假。
<TextBox            
    Text="{Binding Description}"
    FocusExtension.IsFocused="{Binding IsFocused}"/>

如果有更好的方法来解决可见性问题,请告诉我。
注意:感谢Apfelkuacha提出的将BindsTwoWayByDefault放置的建议在DependencyProperty中。我很早以前已经在自己的代码中做到了这一点,但是从未更新过这篇文章。由于此更改,在WPF代码中不再需要Mode = TwoWay。

评论


这对我来说效果很好,除了我需要在GotFocus / LostFocus中添加“ if(e.Source == e.OriginalSource)”检查,否则在UserControl上使用时(从字面上看)stackoverflows确实会将焦点重定向到内部零件。我删除了Visible检查,接受了它像.Focus()方法一样工作的事实。如果.Focus()不起作用,则绑定不起作用-这对于我的情况是可以的。

– HelloSam
13年3月22日在20:08



我在WF 4.5中使用它。在IsFocusedChanged上,我有一个场景(一个Activity重新加载了),其中e.NewValue为null并引发异常,因此请首先检查该异常。进行此较小的更改,一切正常。

–奥拉鲁(Olaru Mircea)
15年4月24日在9:05

感谢此wprks Great :)我刚刚在'FrameworkPropertyMetadata'处添加了'{BindsTwoWayByDefault = true}'来将默认模式设置为TwoWayBinding,因此在每个绑定中都不需要

–R00st3r
16-10-11在9:04



我意识到这是一个古老的答案,但是我遇到了一种情况,我要将焦点转移到的控件的IsEnabled属性绑定到多值转换器。显然,在多值转换器执行之前会调用GotFocus事件处理程序...这意味着该控件在那时已被禁用,因此,一旦GotFocus完成,就将调用LostFocus(我想是因为该控件仍处于禁用状态) 。关于如何处理的任何想法?

–马克·奥尔伯特
18年3月20日在15:37

@MarkOlbert使用fe.Dispatcher.BeginInvoke(new Action(()=> {fe.Focus();}),DispatcherPriority.Loaded);加载后会更新。此处提供更多信息:telerik.com/forums/isfocused-property#OXgFYZFOg0WZ2rxidln61Q

– Apfelkuacha
18-10-23在8:56

#3 楼

我认为最好的方法是保持MVVM原理的清洁,
因此,基本上,您必须使用MVVM Light随附的Messenger类,以及使用方法:

在您的viewmodel中( exampleViewModel.cs):将以下内容写入
 Messenger.Default.Send<string>("focus", "DoFocus");


现在在您的View.cs中(不是XAML,即view.xaml.cs)在构造函数中写入以下内容/>
 public MyView()
        {
            InitializeComponent();

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


该方法具有很好的功能,并且只需较少的代码并保持MVVM标准。

评论


好吧,如果您想保持MVVM原则的清洁,就不会首先在代码中编写代码。我相信附加的财产方法更加清洁。它也不会在视图模型中引入很多魔术字符串。

–́ГИІИО
2012年3月15日21:15

厄尔尼诺现象:您究竟从哪里得到的想法,您的视图代码中不应包含任何内容?与UI相关的任何内容都应在视图的代码隐藏中。设置UI元素的焦点应该绝对在视图的代码隐藏中。让viewmodel确定何时发送消息;让视图找出如何处理该消息。这就是M-V-VM的作用:将数据模型,业务逻辑和UI的关注点分开。

–凯尔·黑尔(Kyle Hale)
13年2月19日在5:00

基于此建议,我实现了自己的ViewCommandManager来处理连接视图中的调用命令。对于这些情况,当ViewModel需要在其View中执行某些操作时,这基本上是常规Commands的另一个方向。它使用诸如数据绑定命令和WeakReferences之类的反射来避免内存泄漏。 dev.unclassified.de/source/viewcommand(也在CodeProject上)

– ygoe
2014年2月1日,11:50

我使用这种方法来打印WPF FlowDocuments。做得很好。谢谢

–戈登·斯莱兹(Gordon Slysz)
2014年5月2日在20:35

我想要一个Silverlight吗?我们可以使用吗?

–大眼
17年1月6日在19:13

#4 楼

这些都不是对我真正有用的,但是为了他人的利益,这就是我最终根据此处已经提供的一些代码编写的内容。

用法如下:

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


实现如下:

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


#5 楼

这是一个旧线程,但是似乎没有代码的答案可以解决Anavanka接受的答案的问题:如果将viewmodel中的属性设置为false,或者如果将属性设置为false,它将无法正常工作。如果为true,则用户手动单击其他内容,然后再次将其设置为true。在这些情况下,我也无法获得Zamotic的解决方案来可靠地工作。

上面的一些讨论汇集在一起​​,为我提供了下面的代码,这些代码确实解决了我认为的这些问题:

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


话虽如此,这对于可以在代码背后的一行中完成的事情仍然很复杂,而且CoerceValue并不是真的要以这种方式使用,所以也许代码背后就是这种方式去。

评论


这始终如一地工作,而接受的答案却行不通。谢谢!

– NathanAldenSr
16-11-19的3:17

#6 楼

就我而言,在我更改方法OnIsFocusedPropertyChanged之前,FocusExtension不起作用。原始的仅在断点停止进程时才在调试中工作。在运行时,该过程太快,没有任何反应。进行了少量修改并在我们的朋友Task的帮助下,这在两种情况下均能正常工作。

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


#7 楼

问题在于,一旦IsUserNameFocused设置为true,就永远不会为假。这通过处理FrameworkElement的GotFocus和LostFocus来解决。

我在源代码格式方面遇到麻烦,因此这里是一个链接

评论


我更改了“对象fe =(FrameworkElement)d;”改为“ FrameworkElement fe =(FrameworkElement)d;”所以智慧工作

–user755404
13年1月29日在14:15

仍然不能解决问题。每当我回到该元素时,该元素都会保持专注。

– ygoe
13年2月26日在23:11

#8 楼

Anvakas出色的代码适用于Windows桌面应用程序。如果您像我一样,并且对于Windows Store应用程序需要相同的解决方案,则此代码可能会很方便:

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


#9 楼

对于那些尝试使用上面的Anvaka解决方案的人来说,绑定问题仅在第一次使用时有效,因为lostfocus不会将该属性更新为false。您可以每次将属性手动设置为false,然后再设置为true,但是更好的解决方案是在属性中执行以下操作:

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


这样,您只能永远需要将其设置为true,它将获得焦点。

评论


为什么要有if语句? _isFocused一旦设置为false,将仅在下一行更改为value。

–达米恩·麦吉文(Damien McGivern)
2011年10月7日,9:13

@Tyrsius您可以通过将依赖项属性赋予Coerce来解决此问题,请参阅此处-social.msdn.microsoft.com/Forums/en-US/wpf/thread/…

–RichardOD
2012年2月17日15:20

#10 楼

我使用WPF / Caliburn Micro,发现“ dfaivre”已成为通用且可行的解决方案
此处:
http://caliburnmicro.codeplex.com/discussions/222892

#11 楼

我已经按照下面的方法通过编辑代码找到了解决方案。无需先将Binding属性设置为False,然后再设置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);
        }
    }
}


#12 楼

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




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


要设置焦点,只需在代码中执行:

EmailFocus = true;


请记住,此插件是html页面的一部分,因此页面中的其他控件可能具有焦点。

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


#13 楼

您可以使用ViewCommand设计模式。它描述了MVVM设计模式通过命令从ViewModel控制视图的方法。

我基于King A.Majid的建议使用MVVM Light Messenger类来实现它。 ViewCommandManager类处理已连接视图中的调用命令。从本质上讲,这是常规命令的另一个方向,在这种情况下,当ViewModel需要在其View中执行某些操作时。它使用诸如数据绑定命令和WeakReferences之类的反射来避免内存泄漏。

http://dev.unclassified.de/source/viewcommand(也发布在CodeProject上)

#14 楼

似乎没有人包括最后一步,可以很容易地通过绑定变量更新属性。这是我想出的。让我知道是否有更好的方法。

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

    }


#15 楼

首先,我要感谢Avanka帮助我解决了焦点问题。但是,他发布的代码中存在一个错误,即在该行中:
if(e.OldValue == null)

我遇到的问题是,如果您首先单击视图并集中控制,e.oldValue不再为null。然后,当您第一次设置变量以使控件聚焦时,这将导致没有设置lostfocus和getfocus处理程序。
我对此的解决方法如下:

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


#16 楼

只需执行以下操作:

<Window x:class...
   ...
   ...
   FocusManager.FocusedElement="{Binding ElementName=myTextBox}"
>
<Grid>
<TextBox Name="myTextBox"/>
...


评论


我喜欢这个。如果要设置初始焦点,此方法效果很好。

–user2430797
2月20日8:28

#17 楼

在实现了可接受的答案之后,我确实遇到了一个问题,即在使用Prism导航视图时,TextBox仍不会获得焦点。对PropertyChanged处理程序的微小更改即可解决

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


#18 楼

基于@Sheridan的替代方法在这里回答

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


在您的视图模型中,以通常的方式设置绑定,然后将SomeTextIsFocused设置为true以将焦点放在您的文本框

#19 楼

我发现Crucial解决IsVisible问题的方法非常有用。它并不能完全解决我的问题,但是在IsEnabled模式的相同模式下执行了一些额外的代码。

我向IsFocusedChanged方法中添加了:

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


这是处理程序:

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


#20 楼

public class DummyViewModel : ViewModelBase
    {
        private bool isfocused= false;
        public bool IsFocused
        {
            get
            {
                return isfocused;
            }
            set
            {
                isfocused= value;
                OnPropertyChanged("IsFocused");
            }
        }
    }


#21 楼

System.Windows.Forms.Application.DoEvents();
Keyboard.Focus(tbxLastName);


评论


OP正在使用WPF。 WinForms的焦点代码将无济于事。

–乔希(Josh G)
2011年6月8日19:44