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));
}
}
}
FirstName
orSurname
when the text changes (or, in fact, at all!), soSetProperty
won't be called. You need to observe the property changes withinTextBoxModel
. – Charles MagerText
property, which is astring
. Trying to set that value will not magically new up aTextBoxModel
and setFirstName
as well. It will just silently fail becauseFirstName
isnull
. – Charles Mager