3

那么如何使用 MVVM 模式将文本框聚焦在按钮单击上?

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

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
}

这是一个下载链接,其中包含一个可供懒惰者使用的项目(VS2010);)

4

3 回答 3

7

在覆盖初始默认值后,您的附加属性值永远不会回到 false。因此,您的FocusExtension课程没有调用Focus()TextBox因为在您的 VM 中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}"

工作下载链接

另一个更新

在类开关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));

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

于 2013-06-06T15:23:31.737 回答
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 移动到您的属性的设置器

于 2013-06-06T15:01:20.813 回答
1

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

if(IsFocus == true)
   IsFocus = false;
IsFocus = true;
于 2013-06-07T07:47:55.313 回答