Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
687 views
in Technique[技术] by (71.8m points)

c# - WPF: Update button if text in TextBox changes

To learn WPF Command and CommandParameter I have a small WPF application with one TextBox and one Button. Whenever the button is pressed, ICommandTest should be called with the text of the text box as parameter.

This works fine. The next step is: if the text becomes too small, the button should be disabled.

I use MVVMLight to implement the command. The code below is enough to call method Test whenever the button is pressed.

Code so far

The following works: At startup the text box gets its proper initial text. The button asks the view model whether this text can be used as parameter for the test:

public class MyViewModel
{
    public ICommand CommandTest {get;}

    public MyViewModel()
    {
        this.CommandTest = new RelayCommand<string>(this.Test, this.CanTest); 
    }

    private bool CanTest(string text)
    {
        // text should have a minimum length of 4
        return text != null && text.Length >= 4;
    }
    private void Test(string text)
    {
        //...
    }

    // ...

}

XAML: An editable text box and a button in a horizontal StackPanel.

<StackPanel Name="Test" Orientation="Horizontal" Background="AliceBlue">
    <TextBox Name="ProposedTestValue"
             Text="Alle eendjes zwemmen in het water"
             Width="500" Height="20"/>

    <Button x:Name="ButtonTest" Content="Change"
                    Height="auto" Width="74"
                    Padding="5,2"
                    Command="{Binding Path=CommandTest}"
                    CommandParameter="{Binding ElementName=ProposedTestValue, Path=Text}"/>
</StackPanel>

Text Changes

If I change the text and press the button, the command is called with the changed text. So Command and CommandParameter work.

However, if the text becomes smaller than 4 characters, the button doesn't disable.. Every time that the value of the bound CommandParameter of the button changes, the button should ask its command if it can be executed.

How to do this?

NotifyOnSourceUpdated

Yosef Bernal suggested to add NotifyOnSourceUpdated:

<Button x:Name="ButtonChangeTestText" Content="Change"
                Height="30" Width="74" Padding="5,2"
                Command="{Binding Path=CommandTest}"
                CommandParameter="{Binding ElementName=ProposedTestTextValue,
                    Path=Text, NotifyOnSourceUpdated=True}"/>

Alas, that didn't change anything: at startup an initial CanTest is called, with the correct parameter. Changing the text doesn't cause a CanTest. If I press the button CanTest is called with the correct value. If the text is small, CanTest returns false, and thus the command is not execute. However, even though CanExecute returned false, the button remains enabled.

Should I tell the Button what to do if not CanExecute? Or is disabling the button the default behaviour?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

You can bind the Text property of your TextBox to a Text property on MyViewModel.

<TextBox Name="ProposedTestValue" Text="{Binding Text}" Width="500" Height="20"/>

Create a corresponding Text property in your MyViewModel with a backing field _text.

private string _text;

public string Text
{
   get => _text;
   set
   {
      if (_text != value)
      {
         _text = value;
         CommandTest.RaiseCanExecuteChanged();
      }
   }
}

The RaiseCanExecuteChanged method will force a re-evaluation of CanExecute whenever the Text property is updated, which depends on your UpdateSourceTrigger. You do not need the CommandParameter anymore, since you can use the Text property in your view model.

public MyViewModel()
{
   this.CommandTest = new RelayCommand(this.Test, this.CanTest); 
}

private bool CanTest()
{
   return Text != null && Text.Length >= 4;
}

private void Test()
{
   // ...use "Text" here.
}

Note: If you intend to update the Text property from your view model, you have to implement INotifyPropertyChanged, otherwise the changed value will not be reflected in the view.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...