Added dirty checking to GenerateStateClass to allow model Sync and Comet property change notifications.
I've tested with below scenario and it works well.
Usage Sample: Update underlying model with comet.OriginalModel.Rides++; and call the state classes comet.SyncModels() method to notify Comet of changes. In reality this would be done outside of a Comet click handler and invoked when the developer knows the underlying model has changed outside of a Comet state/binding.
Usage:
[GenerateStateClass] //OR [assembly: GenerateStateClass(typeof(NS.POCOPlain))]
public class POCOPlain
{
public int Rides { get; set; }
public string CometTrain => "☄️".Repeat(Rides);
}
public class MainPage : View
{
static readonly POCOPlain POCOPlain = new();
readonly POCOPlainState comet = new(POCOPlain);
[Body]
View body()
=> new VStack {
new Text(()=> $"({comet.Rides}) rides taken:{comet.CometTrain}")
.Frame(width:300)
.LineBreakMode(LineBreakMode.CharacterWrap)
.FillHorizontal(),
new Button("Ride the Comet Sync! ☄️", ()=>{
//comet.Rides++;
comet.OriginalModel.Rides++;
comet.NotifyChanged();
})
.Frame(height:44)
.Margin(8)
.Background(Colors.Green)
.Color(Colors.White)
.TextAlignment(TextAlignment.Center)
.FillHorizontal()
};
}
Sample generated state class:
public partial class POCOPlainState :INotifyPropertyRead, IAutoImplemented
{
public event PropertyChangedEventHandler PropertyRead;
public event PropertyChangedEventHandler PropertyChanged;
public readonly GTApp.POCOPlain OriginalModel;
bool shouldNotifyChanged = true;
public POCOPlainState (GTApp.POCOPlain model)
{
OriginalModel = model;
if (model is INotifyPropertyChanged inpc)
{
inpc.PropertyChanged += Inpc_PropertyChanged;
shouldNotifyChanged = false;
}
}
void Inpc_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
StateManager.OnPropertyChanged(sender, e.PropertyName, null);
PropertyChanged?.Invoke(sender, e);
}
void NotifyPropertyChanged(object value, [CallerMemberName] string memberName = null){
if (shouldNotifyChanged) {
StateManager.OnPropertyChanged(this, memberName, value);
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(memberName));
}
}
void NotifyPropertyRead([CallerMemberName] string memberName = null){
InitDirtyProperty(memberName);
StateManager.OnPropertyRead(this, memberName);
PropertyRead?.Invoke(this, new PropertyChangedEventArgs(memberName));
}
/// <summary>
/// Notifies Comet of all changes in the underlying model (OriginalModel) observed properties
/// </summary>
public void NotifyChanged(){
if (shouldNotifyChanged){
if (ridesIsObserved){
UpdateDirtyProperty("Rides");
}
if (cometTrainIsObserved){
UpdateDirtyProperty("CometTrain");
}
}
}
void InitDirtyProperty([CallerMemberName] string memberName = null){
switch (memberName){
case "Rides":
if (!ridesIsObserved){
ridesLastValue = OriginalModel.Rides;
ridesIsObserved = true;
}
break;
case "CometTrain":
if (!cometTrainIsObserved){
cometTrainLastValue = OriginalModel.CometTrain;
cometTrainIsObserved = true;
}
break;
}
}
void UpdateDirtyProperty([CallerMemberName] string memberName = null){
switch (memberName){
case "Rides":
if (ridesIsDirty){
ridesLastValue = OriginalModel.Rides;
NotifyPropertyChanged(ridesLastValue, memberName);
}
break;
case "CometTrain":
if (cometTrainIsDirty){
cometTrainLastValue = OriginalModel.CometTrain;
NotifyPropertyChanged(cometTrainLastValue, memberName);
}
break;
}
}
bool ridesIsObserved = false;
bool ridesIsDirty => ridesIsObserved && !OriginalModel.Rides.Equals(ridesLastValue);
System.Int32 ridesLastValue;
public System.Int32 Rides {
get {
NotifyPropertyRead();
return OriginalModel.Rides;
}
set {
OriginalModel.Rides = value;
ridesLastValue = value;
NotifyPropertyChanged(value);
}
}
bool cometTrainIsObserved = false;
bool cometTrainIsDirty => cometTrainIsObserved && !OriginalModel.CometTrain.Equals(cometTrainLastValue);
System.String cometTrainLastValue;
public System.String CometTrain {
get {
return OriginalModel.CometTrain;
}
}
}
Added dirty checking to GenerateStateClass to allow model Sync and Comet property change notifications.
I've tested with below scenario and it works well.
Usage Sample: Update underlying model with
comet.OriginalModel.Rides++;
and call the state classescomet.SyncModels()
method to notify Comet of changes. In reality this would be done outside of a Comet click handler and invoked when the developer knows the underlying model has changed outside of a Comet state/binding.Usage:
Sample generated state class: