Reputation: 93
namespace ScienceProgram
{
public abstract class BaseViewModel : INotifyPropertyChanged
{
#region Usual Boiler-plate stuff for BindableBase
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string name = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
#endregion
#region Properties (All scientific parameters and calculations )
public double ParamA { get; set; }
public double ParamB { get; set; }
// ...
// Lots of parameters //
// ...
public double ParamA23 { get; set; }
public double TotalLength()
{
return ParamA + ParamB + ParamA23;
}
// ...
// Lots of other methods
// ...
#endregion
}
}
namespace ScienceProgram
{
public abstract class BaseViewModel : INotifyPropertyChanged
{
// Global Parameter // Shared across ViewModels //
public static ScienceParameters scienceParameters = new ScienceParameters ();
#region Usual Boiler-plate stuff for BindableBase
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string name = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
#endregion
}
}
namespace ScienceProgram
{
public class UserInputView1ViewModel : BaseViewModel
{
#region User Input
private double _paramA;
public double ParamA
{
get { return _paramA; }
set
{
_paramA = value;
OnPropertyChanged("ParamA");
// Store Value //
scienceParameters.ParamA = value;
}
}
}
}
#endregion
Many thanks in advance.
Upvotes: 2
Views: 1738
Reputation: 3048
You're close. I see areas where you are duplicating storage of data that could cause maintenance problems. Based on what you've stated, I think your approach with having a BaseViewModel is unnecessary (but if you follow through my answer here, I show you how you could make a BaseViewModel more useful than what you're using it for).
If I understand correctly, you have multiple Views because you want the user to press 'NEXT' to get to the next navigated View. Each View has one associated ViewModel. But underneath the hood, you want to collect all of the properties into one class instance.
To me, the best practice here is to learn the MVVM architecture. The key learning that comes from MVVM is understanding "separation of concerns". Mainly, your data (i.e. all of the user's input values, aka the "Model") has nothing to do with the Views and ViewModels that you present to them in the UI. Read up on this and you will get a better handle on this good practice.
Here's how I would do it.
1) Create a Model class (ScienceParameters.cs), this will hold ALL of the properties that you expect the user to enter. Example:
public class ScienceParameters
{
public double ParamA { get; set; }
public double ParamB { get; set; }
// ...
// Lots of parameters //
// ...
public double ParamA23 { get; set; }
public double TotalLength()
{
return ParamA + ParamB + ParamA23;
}
}
Then on each UI that you present to the user, you will show them one View and one associated ViewModel that gives them access to "see/get" or "store/set" PORTIONS of this data. Example:
public class UserInput1ViewModel: INotifyPropertyChanged
{
public UserInput1ViewModel(ScienceParameters model)
{
this.Model = model;
}
public ScienceParameters Model { get; private set; }
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string name = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
public double ParamA
{
get { return this.Model.ParamA; }
set
{
// Store the user's data directly into the Model, not the ViewModel!
this.Model.ParamA = value;
OnPropertyChanged(nameof(this.ParamA)); // <-- avoid magic words like "ParamA" in quotes, this is bad coding and can cause maintenance issues.
}
}
}
public class UserInput2ViewModel: INotifyPropertyChanged
{
public UserInput2ViewModel(ScienceParameters model)
{
this.Model = model;
}
public ScienceParameters Model { get; private set; }
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string name = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
public double ParamB
{
get { return this.Model.ParamB; }
set
{
this.Model.ParamB = value;
OnPropertyChanged(nameof(this.ParamB));
}
}
}
Extra Credit:
If you want to remove the repetitiveness of writing the PropertyChanged junk in each ViewModel, then put it into a BaseViewModel.
public class BaseViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string name = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
}
Then remove all those PropertyChanged lines from your ViewModels and instead define each ViewModel with the base:
public class UserInput1ViewModel: BaseViewModel
{
// ...
}
Upvotes: 2