MVVM Basic Concept Understanding - c#

I've started working on an application that allows the user to enter some data in different textboxes and then these data are serialized in an XML format, but it seems that I've understood the MVVM concept completely wrong because I've tried to serialize the ViewModel and one of my work colleagues said that is an incorrect way to do things and I should serialize the MODEL.
The "incorrect" implementation:
public class ExampleViewModel : ViewModelBase
{
private double lowerRange;
public double LowerRange
{
get { return lowerRange; }
set
{
lowerRange = value;
RaisePropertyChanged();
}
}
private double upperRange;
public double UpperRange
{
get { return upperRange; }
set
{
upperRange = value;
RaisePropertyChanged();
}
}
}
According to my colleague, serializing this is wrong, but then how should look my MODEL (actually this is the question)
This is correct?
public class ExampleModel
{
public double LowerRange { get; set; }
public double UpperRange { get; set; }
}
public class ExampleViewModel : ViewModelBase
{
private ExampleModel model;
public ExampleViewModel()
{
model = new ExampleModel();
}
private double lowerRange;
public double LowerRange
{
get { return model.LowerRange; }
set
{
model.LowerRange = value;
RaisePropertyChanged();
}
}
private double upperRange;
public double UpperRange
{
get { return model.UpperRange; }
set
{
model.UpperRange = value;
RaisePropertyChanged();
}
}
}
Or this is complety overhead? If you can provide me a meaningful example, I'll be grateful.
Also, I've seen some people that use "RaisePropertyChanged()" inside a MODEL, is this correct? that this model because a ViewModel, right?

Following my comment above, here is how I tend to do this:
public class ExampleModel : ViewModelBase
{
private double _lowerRange;
private double _upperRange;
public double LowerRange
{
get { return _lowerRange; }
set
{
_lowerRange = value;
RaisePropertyChanged();
}
}
public double UpperRange
{
get { return _upperRange; }
set
{
_upperRange= value;
RaisePropertyChanged();
}
}
}
public class ExampleViewModel : ViewModelBase
{
private ExampleModel model;
public ExampleViewModel()
{
Model = new ExampleModel();
}
// this is only needed if you change your complete model
// and need to update the change on the UI
public ExampleModel Model
{
get { return model; }
set
{
model = value;
RaisePropertyChanged();
}
}
}
Also, if you change your ViewModelBase class to something like the one shown here, you can simplify the property getters/setters a bit to the following for example:
public ExampleModel Model
{
get { return model; }
set { SetProperty<ExampleModel >(ref model, value); }
}

Related

Raise event from Inner class to outer class in c#

I'm using MVVM pattern in my project.
My class design is like this:
Class Model : AbstractModel
{
InnerClass Iclass = new InnerClass();
Public String ModelProp1
{
get
{
return Iclass.prop1;
}
set
{
Iclass.prop1 = value;
}
}
public override void SetLabel(UInt16 value, int Index)
{
byte[] arr = BitConverter.GetBytes(value);
this.Iclass.IclassConfig[Index].Label = arr[0];
}
public override string DateFormat
{
get { return Iclass.intlDate.ToString(); }
set { Iclass.intlDate = Convert.ToByte(value); }
}
}
Class InnerClass
{
public byte intlDate
{
get { return this.intl_date; }
set { this.intl_date = value;
RaiseModelPropertiesChangedEvent(new ValueChangedEventArgs { Parameter_dateformat = this.intlDate });
}
private JClassa []channel_config = new JClass[2];
public JClass[] IclassConfig
{
get { return this.channel_config; }
set { this.channel_config = value; }
}
}
Public JClass
{
private byte channel_label;
public byte Label
{
get { return this.channel_label; }
set { this.channel_label = value;}
}
I'm getting data from other application. updated data is coming in InnerClass property from there I want to push this updated data to Model class.
Problem is coming for JClass property how can I fire event such that It will push updated data to model class.
For this I have created Event in InnerClass like this:
public event EventHandler<ValueChangedEventArgs> ModelPropertiesChanged;
public void RaiseModelPropertiesChangedEvent(ValueChangedEventArgs e)
{
if (ModelPropertiesChanged != null)
ModelPropertiesChanged(this, e);
}
public class ValueChangedEventArgs : EventArgs
{
public int Parameter_dateformat { get; set; }
public int Parameter_channelLabel { get; set; }
}
Tell me how Can I achieve this. Becuase I have 4 property in Jclass and 6 Property is InnerClass.
I would add event triggers in the setter of your inner class properties. Then in the Constructor of your parent class, move the IClass = new InnerClass() into your constructor and attach your event listeners.
Since you're MVVM you could leverage INotifyPropertyChanged, but heat will get messy in the long run.
Better to have a 'PropertyName'Changed event for each property you want to notify to the parent class.

Connect ViewModel to Model

I'm working on an application and spent quite some time finding a solution for the following problem. I've tried several things but I'm not sure what's the best approach to solve it.
I've got a setup of a View, ViewModel and a Model. The ViewModel contains a collection of models of which the user can select a specific model (the collection can be empty which makes the selected model null).
The View consists of a Combobox which allows the user to select a model out of a collection of models. The selected model will then be displayed in the view (with various controls such as treeviews, labels, ...).
This is the Model (I will keep it simple for the sake of explanation):
public Model {
private int id;
private String name;
public Model(_id, _name) {
id = _id;
name = _name;
}
public int ID {
get { return id; }
set { id = value; }
}
public String Name {
get { return name; }
set { name = value; }
}
}
And the ViewModel:
public ViewModel : INotifyPropertyChanged {
private ObservableCollection<Model> models = new ObservableCollection<Model>();
private Model selectedModel;
public ViewModel() { }
public Model SelectedModel {
get { return selectedModel; }
set {
selectedModel = value;
NotifyChanged("SelectedModel");
}
}
public Model ModelCellection {
get { return models; }
set {
models = value;
NotifyChanged("ModelCellection");
}
}
public void addModel(Model newModel) {
models.Add(newModel);
}
//variant A
public int ID {
get { return (selectedModel == null) ? 0 : selectedModel.ID; }
set {
if(selectedModel == null)
return;
selectedModel.ID = value;
NotifyChanged("ID");
}
}
public String Name {
get { return (selectedModel == null) ? 0 : selectedModel.Name; }
set {
if(selectedModel == null)
return;
selectedModel.Name = value;
NotifyChanged("Name");
}
}
//variant B (the attributes of the model will be copied when the selected model changes)
public void changeSelectedModel(Model newSelectedModel) {
Name = newSelectedModel.Name;
Id = newSelectedModel.Id;
}
private int id = 0;
private String name = String.Empty;
public int ID {
get { return id; }
set {
id = value;
NotifyChanged("ID");
}
}
public String Name {
get { return name; }
set {
name = value;
NotifyChanged("Name");
}
}
}
My Question is pretty simple: How do I access the relevant public properties of the Model via the ViewModel?
The solutions I've tried so far are:
Variant A: Just change the selected model and use proxy properties to access the properties of the model (problem: The view doesn't get updated when the selected model changes because the Name and Id properties of the ViewModel don't raise a PropertyChanged event)
Variant B: Copy the relevant properties of the model when the selected model is changed (problem: I have to copy the properties of the model)
After talking to some guys in the wpf chat I switched from variant B to variant A but I don't know how to solve the problem of updating the view when the selected model changes? Or would you rather suggest to use a completely different approach to solve this?
I don't know how to solve the problem of updating the view when the selected model changes?
Just raise PropertyChanged event in your SelectedModel definition
public Model SelectedModel {
get { return selectedModel; }
set {
selectedModel = value;
NotifyChanged("SelectedModel");
NotifyChanged("ID");
NotifyChanged("Name");
}
}
You have to implement INotifyPropertyChanged in your Model.
Your code look like.
Your Model.cs
public Model:INotifyPropertyChanged
{
private int id;
private String name;
public Model(_id, _name)
{
id = _id;
name = _name;
}
public int ID {
get { return id; }
set { id = value; NotifyChanged("ID");}
}
public String Name
{
get { return name; }
set { name = value; NotifyChanged("Name");}
}
}
Your ViewModel.cs
public ViewModel
{
private ObservableCollection<Model> models = new ObservableCollection<Model>();
private Model selectedModel;
public ViewModel() { }
private Model _SelectedModel ;
public Model SelectedModel
{
get { return _SelectedModel??(_SelectedModel=new SelectedModel());}
set { _SelectedModel = value;}
}
}
If property has been Changed it will aromatically Notify because in the ViewModel Model object is present.
You have to set your property like
public void changeSelectedModel(Model newSelectedModel)
{
SelectedModel.Name = newSelectedModel.Name;
SelectedModel.Id = newSelectedModel.Id;
}
and it will Notify.

DataForm and 2nd Level Object Binding in WPF

I am using Telerik's WPF controls with Caliburn.Micro. In particular the DataForm control. I am trying to bind it to an object that has the following make up.
public class FrequencyMap : BindableBase
{
private Guid id;
public Guid ID
{
get { return id; }
set
{
id = value;
OnPropertyChanged();
}
}
private string procedureCodeId;
public string ProcedureCodeId
{
get { return procedureCodeId; }
set
{
procedureCodeId = value;
OnPropertyChanged();
}
}
private FrequencyChoice frequency;
public FrequencyChoice Frequency
{
get { return frequency; }
set
{
frequency = value;
OnPropertyChanged();
}
}
private DateTime effectiveDate;
public DateTime EffectiveDate
{
get { return effectiveDate; }
set
{
effectiveDate = value;
OnPropertyChanged();
}
}
private DateTime? terminateDate;
public DateTime? TerminateDate
{
get { return terminateDate; }
set
{
terminateDate = value;
OnPropertyChanged();
}
}
}
and then the FrequencyChoice object looks like this:
public class FrequencyChoice : BindableBase
{
private int id;
private string modifiedUser;
public int ID
{
get { return id; }
set
{
id = value; OnPropertyChanged();
}
}
private string code;
public string Code
{
get { return code; }
set
{
code = value; OnPropertyChanged();
}
}
private string name;
public string Name
{
get { return name; }
set
{
name = value; OnPropertyChanged();
}
}
private string description;
public string Description
{
get { return description; }
set
{
description = value; OnPropertyChanged();
}
}
private string calculationDescription;
public string CalculationDescription
{
get { return calculationDescription; }
set
{
calculationDescription = value; OnPropertyChanged();
}
}
private DateTime inactiveDate;
public DateTime InactiveDate
{
get { return inactiveDate; }
set
{
inactiveDate = value; OnPropertyChanged();
}
}
public string ModifiedUser
{
get
{
return this.modifiedUser;
}
set
{
this.modifiedUser = value;
OnPropertyChanged();
}
}
}
This works quite well except for the Frequency property. How do I get that to work properly. Do I have to use an Enum like this article? Data Forms in your XAML
If so how would I link the two?
I guess what you want is 1 Frequency Map with Many FrequencyChoices relationship
1st I would change the property to inherit from PropertyChangedBase
public class FrequencyChoice : PropertyChangedBase
{
}
then change your properties as below
private BindableCollection<FrequencyChoice> frequencyChoices;
public BindableCollection<FrequencyChoice> FrequencyChoices
{
get
{
return this.frequencyChoices;
}
set
{
if (Equals(value, this.frequencyChoices))
{
return;
}
this.frequencyChoices = value;
this.NotifyOfPropertyChange(() => this.FrequencyChoices);
}
}
I am not really sure what is BindableBase (from google is Prism but hey ur using Caliburn so use PropertyChangedBase) but if want to still use it go ahead but just make sure it handle change notification for you
as each map has many choices you will need collection to store the choices

JsonConvert.SerializeObject() fails in serializing class with DateTime fields

I'm having a class with only private fields and their public getter-setters. I need to convert class object into JSON String hence I'm using JSON.Net.
Following is a simple snippet to convert class object into a JSON string.
MyClass obj = new MyClass();
string json = JsonConvert.SerializeObject(obj);
Console.WriteLine(json);
But the method SerializeObject throws StackOverflowException at field in MyClass of type DateTime. What's happening here?
Update
Following is how MyClass looks like (as it is, I don't mind sharing the actual class)
class MyClass
{
private int _Model;
public int Model
{
get
{
return _Model;
}
set
{
_Model = value;
}
}
private long _ProductionControlNumber;
public long ProductionControlNumber
{
get
{
return _ProductionControlNumber;
}
set
{
_ProductionControlNumber = value;
}
}
private DateTime _ProductionDate;
public DateTime ProductionDate
{
get
{
return _ProductionDate;
}
set
{
_ProductionDate = value;
}
}
private DateTime _TestDate;
public DateTime TestDate
{
get
{
return _TestDate;
}
set
{
_TestDate = value;
}
}
private DateTime _TestStartTime;
public DateTime TestStartTime
{
get
{
return _TestStartTime;
}
set
{
_TestStartTime = value;
}
}
private TimeSpan _TestDuration;
public TimeSpan TestDuration
{
get
{
return _TestDuration;
}
set
{
_TestDuration = value;
}
}
public DateTime TestEndTime
{
get
{
//TODO Perform start end time computing logic.
return TestEndTime;
}
}
private int _TestBed;
public int TestBed
{
get
{
return _TestBed;
}
set
{
_TestBed = value;
}
}
private long _EngineSerial;
public long EngineSerial
{
get
{
return _EngineSerial;
}
set
{
_EngineSerial = value;
}
}
private Single _FuelSpecificGravity;
public Single FuelSpecificGravity
{
get
{
return _FuelSpecificGravity;
}
set
{
_FuelSpecificGravity = value;
}
}
private long _FuelConsume100;
public long FuelConsume100
{
get
{
return _FuelConsume100;
}
set
{
_FuelConsume100 = value;
}
}
private long _FuelConsume110;
public long FuelConsume110
{
get
{
return _FuelConsume100;
}
set
{
_FuelConsume100 = value;
}
}
private int _TemporaryRPM;
public int TemporaryRPM
{
get
{
return _TemporaryRPM;
}
set
{
_TemporaryRPM = value;
}
}
private int _PermanentRPM;
public int PermanentRPM
{
get
{
return _PermanentRPM;
}
set
{
_PermanentRPM = value;
}
}
private Single _RatedPower;
public Single RatedPower
{
get
{
return _RatedPower;
}
set
{
_RatedPower = value;
}
}
private int _RatedSpeed;
public int RatedSpeed
{
get
{
return _RatedSpeed;
}
set
{
_RatedSpeed = value;
}
}
private double _PulleyDiameter;
public double PulleyDiameter
{
get
{
return _PulleyDiameter;
}
set
{
_PulleyDiameter = value;
}
}
private double _RopeDiameter;
public double RopeDiameter
{
get
{
return _RopeDiameter;
}
set
{
_RopeDiameter = value;
}
}
private Single _FullLoad;
public Single FullLoad
{
get
{
return _FullLoad;
}
set
{
_FullLoad = value;
}
}
}
Also, I'll have another class which will have MyClass type field (along with its own similar set of fields), which is going to be converted into JSON string too, and that shouldn't be a problem since JSON.Net is said to support that situation too.
Note: I'm new to C# but I've previously worked with JSON in Java, where I get to play with JSONObject and JSONArray, and they were pretty straight forward.
It looks like your TestEndTime property's getter references itself. Therefore when Json.NET tries to serialize it, it recursively accesses itself and causes the StackOverflowException.
Hope that helps!

Derived Class to use property of Base class?

I have a class, with a public property "appController", as follows:
public class FAST
{
#region Props
public AppController.AppControllerClass appController = new AppController.AppControllerClass();
#endregion
#region Contructors
public FAST(AppController.AppControllerClass appcontroller)
{
this.appController = appcontroller;
}
#endregion
}
I have another few class, in which I would like to use the appController of FAST, the above class.They look like:
public class Forecast
{
#region Properties
private int _forecastnumber;
public int ForecastNumber
{
get { return _forecastnumber; }
set { _forecastnumber = value; }
}
private DateTime _startdate;
public DateTime StartDate
{
get { return _startdate; }
set { _startdate = value; }
}
private DateTime _enddate;
public DateTime EndDate
{
get { return _enddate; }
set { _enddate = value; }
}
private DateTime _deadline;
public DateTime Deadline
{
get { return _deadline; }
set { _deadline = value; }
}
private string _name;
public string Name
{
get { return _name; }
set { _name = value; }
}
private string _type;
public string Type
{
get { return _type; }
set { _type = value; }
}
private string _description;
public string Description
{
get { return _description; }
set { _description = value; }
}
private string _status;
public string Status
{
get { return _status; }
set { _status = value; }
}
#endregion
#region Constructors
public Forecast()
{
}
#endregion
#region Methods
public static void InsertForecast(Forecast forecast)
{
try
{
this.appController.Execute(appController.nDC.FASTData.InsertForecast(forecast.StartDate, forecast.EndDate, forecast.Deadline, forecast.Type, forecast.Name, forecast.Description, forecast.Status));
}
catch (Exception ex)
{
this.appController.LogError(ex);
}
}
#endregion
}
I want to be able to declare the FAST class once, passing in the AppController, then use my other classes freely, and they will use the appcontroller of the FAST class.
Can this be done at all? (inheritance?)
Thanks for any help.
It sounds like you simply want a static class for your FAST class. If you define the AppController variable as static, it will be accessible from anywhere.
I would say no to inheritance. Inheritance suggests an "is" relationship, e.g. "Forecast is a specialized version of the app controller." Aggregation, a specialized form of object composition, suggests a "has" relationship, e.g. "Forecast has an app controller."
http://en.wikipedia.org/wiki/Object_composition#Aggregation
You could add a setter method to set your FAST object as a property of Forecast:
public FAST appController { get; set; }
And then
var f = new FAST(new AppController.AppControllerClass());
var forecast = new Forecast();
var forecast2 = new Forecast();
forecast.appController = f;
forecast2.appController = f;

Categories

Resources