You are not binding to an expression, you are binding to a computed property. This property is not automatically reevaluated. In your case, it is retrieved once when the button is loaded, never again. You have to implement the INotifyPropertyChanged
interface and raise the PropertyChanged
event in order to trigger an update of the current value of your property in the user interface. As a side note, it is the same for the SomeText
property, if you tried to change it in code, it would not update the text box.
Here is a sample implementation of the interface. Note that you have to trigger the property change for the EnableSubmit
property in the setter of the SomeText
property, because it depends on it.
public class YourViewModel : INotifyPropertyChanged
{
// ...your other code.
private string _someText;
public string SomeText
{
get => _someText;
set
{
if (_someText == value)
return;
_someText = value;
// This will trigger an update wherever SomeText is bound in the UI, if you need it
OnPropertyChanged();
// This will trigger the IsEnabled binding update
OnPropertyChanged(nameof(EnableSubmit));
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
In the specific case of enabling the button only if the text is not empty, you could also use a style.
<Button Content="Submit">
<Button.Style>
<Style TargetType="{x:Type Button}">
<Setter Property="IsEnabled" Value="True"/>
<Style.Triggers>
<DataTrigger Binding="{Binding Text.Length, ElementName=MyText}" Value="0">
<Setter Property="IsEnabled" Value="False"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
Since you are using a button which eventually triggers an action, probably the best way is to use a command instead. A command implements the ICommand
interface which contains a CanExecute
method, which determines if the command can be executed or not. There are many implementations, e.g. RelayCommand
in this related post. In your view model, you would add:
public class YourViewModel : INotifyPropertyChanged
{
public YourViewModel()
{
// ...other constructor code.
DoSomething = new RelayCommand(ExecuteDoSomething, CanExecuteDoSomething);
}
// ...your other code.
public RelayCommand DoSomething { get; }
private bool CanExecuteDoSomething(object obj)
{
return !string.IsNullOrWhiteSpace(SomeText);
}
private void ExecuteDoSomething(object obj)
{
// ...your action.
}
}
In your XAML code, you would remove the IsEnabled
binding and add the command instead.
<Button Content="Submit" Command="{Binding DoSomething}"/>
That is it, no need for exposing an EnableSubmit
property. If you do not really need the text from the text box in your view model apart from the action, you could even remove the SomeText
property and pass the text directly as CommandParameter
in XAML (which is passed to the execute and can execute methods).