Reputation: 145
XAML:
<TextBox x:Name="User" Text="{Binding Username}" Margin="0,0,62,0">
<TextBox x:Name="Pass" Text="{Binding Password}" Margin="0,0,62,0">
<Button Command="{Binding Path= SaveCommand}" IsDefault="True" Margin="10,0,1,9" Height="42" VerticalAlignment="Bottom">
If I ever delete the Binding path on the button, the button become enabled again.
ViewModel:
public class XViewModel : INotifyPropertyChanged
{
private string _username;
private string _password;
public XViewModel()
{
SaveCommand = new DelegateCommand(Save, () => CanSave);
}
public string Username
{
get { return _username; }
set
{
_username = value;
NotifyOfPropertyChange("Username");
}
}
public string Password
{
get { return _password; }
set
{
_password = value;
NotifyOfPropertyChange("Password");
}
}
protected void NotifyOfPropertyChange(string name)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(name));
}
}
public ICommand SaveCommand { get; private set; }
public bool CanSave
{
get { return !string.IsNullOrEmpty(Username) && !string.IsNullOrEmpty(Password); }
}
public event PropertyChangedEventHandler PropertyChanged;
public async void Save()
{
SqlConnection con = new SqlConnection(ConfigurationManager.ConnectionStrings["StringConnexion"].ConnectionString);
SqlCommand cmd = con.CreateCommand();
cmd.CommandText = "INSERT INTO Users(Login,password)VALUES(@Username,@Password)";
cmd.Parameters.AddWithValue("@ID", Username);
cmd.Parameters.AddWithValue("@FirstName", Password);
try
{
await con.OpenAsync();
cmd.ExecuteNonQuery();
}
catch (SqlException ex)
{
throw ex;
}
finally
{
con.Close();
}
var sampleMessageDialog1 = new SampleMessageDialog
{
Message = { Text = "Connected" }
};
await DialogHost.Show(sampleMessageDialog1, "RootDialog");
}
public class DelegateCommand : ICommand
{
private readonly Action _execute;
private readonly Func<bool> _canExecute;
public DelegateCommand(Action execute)
: this(execute, () => true)
{
_execute = execute;
}
public DelegateCommand(Action execute, Func<bool> canExecute)
{
_execute = execute;
_canExecute = canExecute;
}
public void Execute(object parameter)
{
_execute();
}
public bool CanExecute(object parameter)
{
return _canExecute();
}
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
}
}
I thought It's disabled because nothing was written on the TExtboxes at first but apparently that's not the case. I'm basically using https://www.codeproject.com/Articles/694908/Connecting-to-SQL-Server-using-MVVM-Pattern with some changes.
EDIT:
If I do this with the DataContext:
<Button Command="{Binding Path= SaveCommand}" Margin="10,0,1,9" Height="42" Grid.Column="1" Grid.Row="3" VerticalAlignment="Bottom">
<Button.DataContext>
<local:ConnexionViewModel Password="something" Username="sdfsdf" />
</Button.DataContext>
The button will get enabled and the something
and sdfsdf
will be added to the database just fine but again, that's not the behavior I want, I want the user to be able to type both the login and password through the textboxes.
Upvotes: 2
Views: 841
Reputation: 31
The Text property of TextBox is updated when focus on the TextBox is lost. Your Save button will be enabled if the focus is lost from the textboxes after you have typed the content in them. If you want the Text property to be updated as soon as you type into them, then you need to set the Binding.UpdateSourceTrigger property to PropertyChanged.
<TextBox x:Name="User" Text="{Binding Username, UpdateSourceTrigger=PropertyChanged}" Margin="0,0,62,0"/>
<TextBox x:Name="Pass" Text="{Binding Password, UpdateSourceTrigger=PropertyChanged}" Margin="0,0,62,0"/>
<Button Command="{Binding Path= SaveCommand}" Content="Save" IsDefault="True" Margin="10,0,1,9" Height="42" VerticalAlignment="Bottom"/>
Upvotes: 1
Reputation: 247551
Include an accessible means to raise the CanExecuteChanged
event within the DelegateCommand
for example
public class DelegateCommand : ICommand {
//...code removed for brevity
public bool CanExecute(object parameter) {
if(_canExecute == null)
return true;
return _canExecute();
}
public void RaiseCanExecuteChanged() {
if( CanExecuteChanged != null ) {
CanExecuteChanged(this, EventArgs.Empty);
}
}
}
so that the UI is aware that something changed in the view model's command so it would know to check/invoke the CanExecute
and react accordingly.
public string Username {
get { return _username; }
set {
_username = value;
NotifyOfPropertyChange("Username");
SaveCommand.RaiseCanExecuteChanged();
}
}
public string Password {
get { return _password; }
set {
_password = value;
NotifyOfPropertyChange("Password");
SaveCommand.RaiseCanExecuteChanged();
}
}
To avoid repeated code you could move that code to with the NotifyOfPropertyChange
method instead
protected void NotifyOfPropertyChange(string name) {
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) {
handler(this, new PropertyChangedEventArgs(name));
SaveCommand.RaiseCanExecuteChanged();
}
}
so that the command also raises its event when a property changes. That suggestion is specific to this scenario as you have few properties.
Upvotes: 0