Reputation: 67
How can I disable button until good textbox validation? I have done some stuff but I don't know how to hide button until good validation in the right way with using MVVM pattern. I am still learning this MVVM pattern. Here are my fragments of code:
ValidationRule Class:
public class NotEmptyValidationRule : ValidationRule
{
public override ValidationResult Validate(object value, CultureInfo cultureInfo)
{
return string.IsNullOrWhiteSpace((value ?? "").ToString())
? new ValidationResult(false, "Field is required")
: ValidationResult.ValidResult;
}
}
xaml:
<TextBox
Style="{StaticResource MaterialDesignFilledTextFieldTextBox}"
AcceptsReturn="True"
TextWrapping="Wrap"
materialDesign:HintAssist.Hint="Content"
IsEnabled="{Binding Path=IsChecked,
ElementName=MaterialDesignOutlinedTextFieldTextBoxEnabledComboBox}"
MaxLength="1000" materialDesign:ValidationAssist.UsePopup="True">
<TextBox.Text>
<Binding Path="Task.Content" UpdateSourceTrigger="PropertyChanged">
<Binding.ValidationRules>
<domain:NotEmptyValidationRule
ValidatesOnTargetUpdated="True" />
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
ViewModel:
private ICommand _submitCommand;
public ICommand SubmitCommand
{
get
{
if (_submitCommand == null)
{
_submitCommand = new RelayCommand(SubmitExecute, anSubmitExecute, false);
}
return _submitCommand;
}
}
private void SubmitExecute(object parameter)
{
Task.Id++;
Tasks.Add(Task);
}
private bool CanSubmitExecute(object parameter)
{
// What can I do to prevent to show this button when validation
// failed
return true;
}
Upvotes: 1
Views: 1489
Reputation: 169160
You should either implement the INotifyDataErrorInfo
interface in your Task
class, or implement it in your view model class and wrap the databound Task.Content
property, e.g.:
private RelayCommand _submitCommand;
public ICommand SubmitCommand
{
get
{
if (_submitCommand == null)
{
_submitCommand = new RelayCommand(SubmitExecute, CanSubmitExecute, false);
}
return _submitCommand;
}
}
private void SubmitExecute(object parameter)
{
Task.Id++;
Tasks.Add(Task);
}
public string Content
{
get { return Task.Content; }
set
{
Task.Content = value;
if (string.IsNullOrEmpty(Task.Content))
_validationErrors[nameof(Content)] = "Field is required";
else
_validationErrors.Remove(nameof(Content));
ErrorsChanged?.Invoke(this, new DataErrorsChangedEventArgs(nameof(Content)));
_submitCommand.RaiseCanExecuteChanged();
}
}
private bool CanSubmitExecute(object parameter)
{
return HasErrors;
}
#region INotifyDataErrorInfo
private readonly Dictionary<string, string> _validationErrors = new Dictionary<string, string>();
public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;
public System.Collections.IEnumerable GetErrors(string propertyName)
{
if (string.IsNullOrEmpty(propertyName)
|| !_validationErrors.ContainsKey(propertyName))
return null;
return new string[1] { _validationErrors[propertyName] };
}
public bool HasErrors
{
get { return _validationErrors.Count > 0; }
}
#endregion
XAML:
<TextBox Text="{Binding Content, UpdateSourceTrigger=PropertyChanged, ValidatesOnNotifyDataErrors=True}" />
You should not use a validation rule. They are not MVVM friendly. Please refer to this blog post for more information.
You also need to raise the CanExecuteChanged
event of the ICommand
. How to do this depends on the implementation. Most implementations have a method called something like RaiseCanExecuteChanged()
or similar.
WPF 4.5: Validating Data in Using the INotifyDataErrorInfo Interface
Upvotes: 2