WPF MVVM:需要格式的TextBox和IsDefault设置为True的Button

时间:2010-08-31 14:45:27

标签: c# wpf mvvm binding .net-4.0

我发现这个link有关类似的问题,除了我的文本框需要在焦点丢失后需要格式化值的附加扭曲。

<TextBox Text="{Binding Value}" MaxLength="{Binding MaskLength}"/>
<Button Command="{Binding ExecuteCommand}" IsDefault="True"/>

用户在文本框中输入文本后,我想用用户定义的掩码格式化它。例如,如果掩码为“00000”,则约定为右对齐和零填充。

  

123 =&gt; 00123
  A01 =&gt; 00A01
  等...

我遇到的问题是,我应该只在用户输入完成后将文本格式化一次。目前,如果用户点击按钮,则用户输入的值被推送到绑定并执行命令。但是,如果按下“Enter”键,则不会将值推送到绑定,并且命令仍会执行。

当用户按下回车键时,我发现如何推送绑定的唯一方法是更改​​文本框的绑定并指定UpdateSourceTrigger=PropertyChanged。这不能很好地工作,因为我实际上并不知道用户何时完成输入文本。

最简单的解决方案是在按下回车键时添加代码隐藏来设置按钮的焦点,但我希望将焦点保留在当前所在的文本框中。有没有人可以解决这个问题,也许是附属财产?

修改

以下是我的viewmodel如何格式化输入值的简短示例。

public string Value
{
    get
    {
        return mFieldValue;
    }
    set
    {
        SetValueAndRaisePropertyChange( 
            ref mFieldValue, 
            _ApplyFormat( value ), 
            () => FieldValue );
    }
}

这是我发现的黑客背后最干净的代码。我把它转换成了附属物,但它仍然闻起来不太正确。

private void _HandleTxtKeyDown( object sender, KeyEventArgs e )
{
    if( e.Key == Key.Enter )
    {
        TextBox textBox = (TextBox)sender;
        BindingExpression binding = textBox.GetBindingExpression( TextBox.TextProperty );
        if( binding != null )
        {
            binding.UpdateSource();
        }
    }
}

2 个答案:

答案 0 :(得分:0)

如果我理解你的意图是正确的,那么事实上没有问题。

如果用户按下回车键/右键单击按钮,您只想屏蔽输入?然后,您已找到的解决方案(UpdateSourceTrigger = PropertyChanged)将完全按照您的意图执行。键入时,VM中的属性会更新。如果使用PropertyChanged触发器按Enter /单击按钮,则不会执行该命令。

默认的UpdateSourceTrigger是'LostFocus'。如果用鼠标单击按钮,而不是按Enter键,也会发生这种情况。

希望我能帮助你理解这种机制。

答案 1 :(得分:0)

你不对。如果命令更新文本,则在键入时不会执行该操作,直到您按下Enter /单击按钮。

观点:

<Window x:Class="WpfApplication9.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="300" Width="300">
    <StackPanel>
        <TextBox MaxLength="{Binding Path=MyLength}" 
                 Text="{Binding Path=MyText, UpdateSourceTrigger=PropertyChanged}"/>

        <Button Command="{Binding Path=MyCommand}" IsDefault="True">Enter</Button>
    </StackPanel>
 </Window>

viewmodel,在构造函数中被指定为Window的DataContext:

public class MyViewModel : INotifyPropertyChanged
{
    private string _myText = string.Empty;
    private int _maxLength = 6;
    private ICommand _myCommand;

    public MyViewModel()
    {
        this._myCommand = new MySimpleCommand((obj) => { FormatMyText(); });
    }

    private void FormatMyText()
    {
        this.MyText = this.MyText.PadLeft(this.MyLength, '0');
    }

    public string MyText
    {
        get { return this._myText; }
        set
        {
            this._myText = value;
            PropertyChanged(this, new PropertyChangedEventArgs("MyText"));
        }
    }

    public int MyLength
    {
        get { return this._maxLength; }
        set { }
    }

    public ICommand MyCommand
    {
        get { return this._myCommand; }
        set { }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    public class MySimpleCommand : ICommand
    {
        private Action<object> _action;

        public MySimpleCommand(Action<object> cmdAction)
        {
            this._action = cmdAction;
        }

        public bool CanExecute(object parameter)
        {
            return true;
        }

        public event EventHandler CanExecuteChanged;

        public void Execute(object parameter)
        {
            _action(parameter);
        }

    }
}