I use the following NEW BindableViewModel class(Old one I also post at the bottom of this topic) to make a object observable(from MS sample):
public abstract class BindableBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged = delegate { };
protected bool SetProperty<T>(ref T storage, T value, [CallerMemberName] string propertyName = null)
{
if (object.Equals(storage, value)) return false;
storage = value;
this.OnPropertyChanged(propertyName);
return true;
}
protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
I want use this to create a ViewModel in order to bind those TextBox Controls, such as this:
public class TextBoxModel : BindableBase
{
private string _text = string.Empty;
// I'm going to bind this field to TextBox.Text property
public string Text { get { return _text; } set { SetProperty(ref _text, value); } }
private bool _isEnabled = true;
// I'm going to bind this field to TextBox.IsEnabled property
public bool IsEnabled { get { return _isEnabled; } set { SetProperty(ref _isEnabled, value); } }
}
Then, in my Page ViewModel, I use TextBoxModel to define fields:
public class Page1ViewModel : BindableBase
{
private TextBoxModel _firstName = null;
public TextBoxModel FirstName { get { return _firstName; } set {
if (SetProperty(ref _firstName, value))
{
SubmitCommand.RaiseCanExecuteChanged();
} } }
private TextBoxModel _surname = null;
public TextBoxModel Surname { get { return _surname; } set {
if (SetProperty(ref _surname, value))
{
SubmitCommand.RaiseCanExecuteChanged();
} } }
private DelegateCommand _submitCommand = null;
public DelegateCommand SubmitCommand { get { return _submitCommand??(_submitCommand=new DelegateCommand(SubmitExecute, SubmitCanExecute)); } }
private void SubmitExecute()
{
MessageBox.Show($"{FirstName.Text} {Surname.Text}");
}
private bool SubmitCanExecute()
{
if(string.IsNullOrEmpty(FirstName.Text))
return false;
else if(string.IsNullOrEmpty(Surname.Text))
return false;
else
return true;
}
}
In my XAML View, I set textbox binding as usual:
<TextBox Text="{Binding FirstName.Text, UpdateSourceTrigger=PropertyChanged}" IsEnabled="{Binding FirstName.IsEnabled}"/>
<TextBox Text="{Binding Surname.Text, UpdateSourceTrigger=PropertyChanged}" IsEnabled="{Binding Surname.IsEnabled}"/>
<Button Content="Submit" Command{Binding SubmitCommand} />
When I run this, I've found text changing is not work. It didn't trigger if(SetProperty(ref _firstName, value)) or if(SetProperty(ref _surname, value)) in the setter. If I don't combine the properties in a TextBoxModel, everything works fine. If I use OLD ViewModelBase, TextBoxModel worked fine, too.
So I think I must missed something when using the NEW BindableBase class? Looking for your help, thanks!
OLD ViewModelBase:
[Obsolete("Please use BindableBase。")]
public abstract class ObservableModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public static string GetPropertyName<T>(System.Linq.Expressions.Expression<Func<T>> e)
{
var member = (System.Linq.Expressions.MemberExpression)e.Body;
return member.Member.Name;
}
protected virtual void RaisePropertyChanged<T>
(System.Linq.Expressions.Expression<Func<T>> propertyExpression)
{
RaisePropertyChanged(GetPropertyName(propertyExpression));
}
protected void RaisePropertyChanged(String propertyName)
{
System.ComponentModel.PropertyChangedEventHandler temp = PropertyChanged;
if (temp != null)
{
temp(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName));
}
}
}
FirstNameorSurnamewhen the text changes (or, in fact, at all!), soSetPropertywon't be called. You need to observe the property changes withinTextBoxModel.Textproperty, which is astring. Trying to set that value will not magically new up aTextBoxModeland setFirstNameas well. It will just silently fail becauseFirstNameisnull.