开发者

WPF MVVM: TextBox needing format and Button with IsDefault set to True

开发者 https://www.devze.com 2023-01-13 17:05 出处:网络
I have found this link about similar problem, except mine has the added twist of the textbox needing to have a formatted value after focus is lost.

I have found this link about similar problem, except mine has the added twist of the textbox needing to have a formatted value after focus is lost.

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

After the user enters text into the textbox I would like to format it with a user defined mask. For example, if the mask is "00000" the convention would be to right justify and zero fill.

123 => 00123

A01 => 00A01

etc...

The problem that I'm running into is that I should only format the text once, when the user has finished typing. Currently, if the user clicks on the button the value the user e开发者_运维知识库ntered is pushed to the binding and the command is executed. However, if they press the 'Enter' key the value is not pushed to the binding and the command is still executed.

The only way I've found out how to push the binding when the user presses the enter key is to change the textbox's binding and specify UpdateSourceTrigger=PropertyChanged. This does not work nicely because I don't actually know when the user has finished entering their text.

The easiest solution would be to add codebehind to set the button's focus when the enter key is pressed, however I would like focus to remain at the text box they are currently on. Does anybody have a way around this, maybe an attached property?

EDIT:

Here is a brief example of how my viewmodel is formatting the inputted value.

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

Here is the cleanest code behind hack that I've found. I converted this into an attached property but it still doesn't smell quite right.

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


If I understood your intention the right way, there is infact no problem.

You only want to mask the input if the user presses the enter key/clicks the button right? Then the solution you already found (UpdateSourceTrigger=PropertyChanged) will do exactly what you intend. The Property in your VM is updated while you are typing. The command will not be executed until you press enter/click the button if you use the PropertyChanged trigger.

The default UpdateSourceTrigger is 'LostFocus'. This of course also happens if you click the button with the mouse, not when pressing enter.

Hope i could help you understanding the mechanism.


You are not right. If the command updates the text, it is not executed while typing, until you press enter/click the button.

The view:

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

The viewmodel, which is assigned as the Window's DataContext in constructor:

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

    }
}
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号