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