如何在按钮单击上聚焦TextBox

时间:2013-06-06 14:33:35

标签: c# wpf xaml mvvm

那么如何使用MVVM模式在按钮上单击TextBox?

我创建了一个基于this Answer的简单Testproject,它在第一次点击时起作用,但之后它不再设置Focus。我错过了什么?

XAML(查看)

<Grid>
    <TextBox Height='23' HorizontalAlignment='Left' Margin='12,12,0,0' VerticalAlignment='Top' Width='120'
             Text='{Binding TheText}'
             local:FocusExtension.IsFocused="{Binding IsFocused}"/>
    <Button Content='Click' Height='23' HorizontalAlignment='Left' Margin='138,11,0,0' VerticalAlignment='Top' Width='75' 
            Command='{Binding ClickCommand}'/>
    <Button Content='Just to deFocus' Height='28' HorizontalAlignment='Left' Margin='14,44,0,0' Name='button1' VerticalAlignment='Top' Width='199' />
</Grid>

视图模型

public class ViewModel : INotifyPropertyChanged
{
    public string TheText { get; set; }
    public bool IsFocused { get; set; }

    private RelayCommand _clickCommand;
    public ICommand ClickCommand
    {
        get { return _clickCommand ?? (_clickCommand = new RelayCommand(param => this.OnClick())); }
    }
    private void OnClick()
    {
        IsFocused = true;
        RaisePropertyChanged("IsFocused");
    }

    #region INotifyPropertyChanged

    public event PropertyChangedEventHandler PropertyChanged;

    public void RaisePropertyChanged(string propName)
    {
        if (this.PropertyChanged != null)
            this.PropertyChanged(this, new PropertyChangedEventArgs(propName));
    }

    #endregion
}

这是一个Download link,有一个准备好去项目(VS2010)的懒人;)

3 个答案:

答案 0 :(得分:6)

在覆盖初始默认值后,您的附加属性值永远不会返回false。因此,FocusExtension课程未在Focus()上调用TextBox,因为在您的虚拟机中将PropertyChanged设置为true时,IsFocused无需触发。

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

private static void OnIsFocusedPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) {
  var uie = (UIElement)d;
  if (!((bool)e.NewValue))
    return;
  uie.Focus();
  uie.LostFocus += UieOnLostFocus;
}

private static void UieOnLostFocus(object sender, RoutedEventArgs routedEventArgs) {
  var uie = sender as UIElement;
  if (uie == null)
    return;
  uie.LostFocus -= UieOnLostFocus;
  uie.SetValue(IsFocusedProperty, false);
}

<强>更新

随着上述变化也确保

local:FocusExtension.IsFocused="{Binding IsFocused}"

切换到

local:FocusExtension.IsFocused="{Binding IsFocused, Mode=TwoWay}"

Working Download Link

另一次更新

Mode=TwoWay班级开关

中将FocusExtension设置为此附加属性的默认值
public static readonly DependencyProperty IsFocusedProperty = DependencyProperty.RegisterAttached(
  "IsFocused",
  typeof(bool),
  typeof(FocusExtension),
  new UIPropertyMetadata(
    false,
    OnIsFocusedPropertyChanged));

public static readonly DependencyProperty IsFocusedProperty = DependencyProperty.RegisterAttached(
  "IsFocused",
  typeof(bool),
  typeof(FocusExtension),
  new FrameworkPropertyMetadata(
    false,
    FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
    OnIsFocusedPropertyChanged));

您可以使用上述声明跳过在xaml中明确指定Mode=TwoWay

答案 1 :(得分:1)

您应该为lostFocus事件发出命令,当焦点丢失时,将isFocused属性设置为false,然后它将起作用。将交互性和交互图书馆添加到您的项目中,而不是像以下那样编写:

 <i:Interaction.Triggers>
    <i:EventTrigger EventName="LostFocus">
        <ei:CallMethodAction TargetObject="{Binding}" MethodName="OnLostFocus"/>
    </i:EventTrigger>
 </i:Interaction.Triggers>

并在你的viewModel中写:

public void OnLostFocus()
{IsFocused = false;}

并将RaisePropertyChanged移动到您的属性的setter

答案 2 :(得分:1)

之前我遇到过同样的问题。我做了一个技巧。在OnClick方法中,执行以下操作:

if(IsFocus == true)
   IsFocus = false;
IsFocus = true;