vendredi 27 février 2015

Make my MVC less verbose

Here my habits in my C#/WinForm applications


First a model.



public class MyModel : NotifyPropertyChangedAdapter
{
private string _propertyA;
private string _propertyB;

public string PropertyA
{
get { return _propertyA; }
set
{
// If nothing new just leave.
if (Equals(_propertyA, value)) return;
_propertyA = value;
OnPropertyChanged("PropertyA");
}
}

public string PropertyB
{
get { return _propertyB; }
set
{
// If nothing new just leave.
if (Equals(_propertyB, value)) return;
_propertyB = value;
OnPropertyChanged("PropertyB");
}
}

[...]

}


Lets use it in a UserControl



public partial class MyUserControl : UserControl
{
private MyModel _myModel;

public MyUserControl()
{
InitializeComponent();
}

[CanBeNull]
[Browsable(false)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public MyModel MyModel
{
get { return _myModel; }
set
{
// If nothing new just leave.
if (Equals(_myModel, value)) return;

// Unregister previous model.
if (_myModel != null)
{
_myModel.PropertyChanged -= MyModelOnPropertyChanged;
}

_myModel = value;

// Yep I have child user control who show stuffs depending of 'MyModel'.
childUserControl.MyModel = value;

// Register new model.
if (_myModel != null)
{
_myModel.PropertyChanged += MyModelOnPropertyChanged;
}

// Update UI stuffs which depends on MyModel
UpdateLabelA();
UpdateLabelB();
}
}

private void MyModelOnPropertyChanged(object sender, PropertyChangedEventArgs eventArgs)
{
switch (eventArgs.PropertyName)
{
case null: // I forget those two often
case "":
UpdateLabelA();
UpdateLabelB();
break;
case "PropertyA":
UpdateLabelA();
break;
case "PropertyB":
UpdateLabelB();
break;
}
}

private void UpdateLabelA()
{
// Yes, the model can be accessed by non-UI threads.
if (InvokeRequired)
{
Invoke((MethodInvoker) UpdateLabelA);
return;
}

// Take a local copy.
// Yes, the 'MyModel' properties can be changed by non-UI threads.
var myModel = MyModel;
if (myModel == null) return;

// Lets apply the so special formating.
labelA.Text = String.Format("A is: {0}", myModel.PropertyA);
}

private void UpdateLabelB()
{
if (InvokeRequired)
{
Invoke((MethodInvoker) UpdateLabelB);
return;
}

var myModel = MyModel;
if (myModel == null) return;

labelB.Text = String.Format("B is: {0}", myModel.PropertyB);
}
}


My point is : it is really too much verbose. In the ChildUserControl there is exactly the same code for the MyModel property.


And that is the simplest stuff I use. In general the MyModelclass are stored in a MetaModel. For example I want to be able to switch from a model to an other.


The meta-model



public class MyMetaModel
{
private readonly MyModel _myModel1;
private readonly MyModel _myModel2;
private readonly MyModel _myModel3;

private int _currentMode;
private MyModel _currentModel;

public MyMetaModel()
{
// Initialize the models.
_myModel1 = new MyModel();
_myModel2 = new MyModel();
_myModel3 = new MyModel();

// Initialize current mode.
_currentMode = 1;
_currentModel = _myModel1;
}

public int CurrentMode
{
get { return _currentMode; }
set
{
if(Equals(_currentMode, value)) return;
if ((value < 1) || (value > 3)) throw new ArgumentException();

_currentMode = value;
switch (value)
{
case 1:
CurrentModel = _myModel1;
break;
case 2:
CurrentModel = _myModel2;
break;
case 3:
CurrentModel = _myModel3;
break;
}
}
}

/// <summary>
/// Gets the CurrentModel.
/// To change it, use <see cref="CurrentMode"/>.
/// </summary>
public MyModel CurrentModel
{
get { return _currentModel; }
private set
{
if (Equals(_currentModel, value)) return;
_currentModel = value;
OnCurrentModelChanged(EventArgs.Empty);
}
}

public event EventHandler CurrentModelChanged;

protected virtual void OnCurrentModelChanged(EventArgs eventArgs)
{
var handler = CurrentModelChanged;
if (handler == null) return;

handler(this, eventArgs);
}
}


Lets use it in the UserControl



public partial class MyUserControl : UserControl
{
private MyMetaModel _myMetaModel;
private MyModel _myModel;

public MyUserControl()
{
InitializeComponent();
}

[CanBeNull]
[Browsable(false)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public MyMetaModel MyMetaModel
{
get { return _myMetaModel; }
set
{
if(Equals(_myMetaModel, value)) return;

// Unregister previous meta-model.
if (_myMetaModel != null)
{
_myMetaModel.CurrentModelChanged -= MyMetaModelOnCurrentModelChanged;
}

_myMetaModel = value;

// Register new meta-model.
if (_myMetaModel != null)
{
_myMetaModel.CurrentModelChanged += MyMetaModelOnCurrentModelChanged;
}

// Update stuffs which depends on MyMetaModel
UpdateMyModel();
}
}

private void MyMetaModelOnCurrentModelChanged(object sender, EventArgs eventArgs)
{
UpdateMyModel();
}

private void UpdateMyModel()
{
// Yes, the 'MyMetaModel' properties can be changed at any moment by non-UI threads.
var myMetaModel = MyMetaModel;
MyModel = (myMetaModel == null) ? null : myMetaModel.CurrentModel;
}

[CanBeNull]
private MyModel MyModel
{
get { return _myModel; }
set
{
// If nothing new just leave.
if (Equals(_myModel, value)) return;

// Unregister previous model.
if (_myModel != null)
{
_myModel.PropertyChanged -= MyModelOnPropertyChanged;
}

_myModel = value;

// Yep I have child user control who show stuffs depending of 'MyModel'.
childUserControl.MyModel = value;

// Register new model.
if (_myModel != null)
{
_myModel.PropertyChanged += MyModelOnPropertyChanged;
}

// Update UI stuffs which depends on MyModel
UpdateLabelA();
UpdateLabelB();
}
}

private void MyModelOnPropertyChanged(object sender, PropertyChangedEventArgs eventArgs)
{
switch (eventArgs.PropertyName)
{
case null: // I forget those two often
case "":
UpdateLabelA();
UpdateLabelB();
break;
case "PropertyA":
UpdateLabelA();
break;
case "PropertyB":
UpdateLabelB();
break;
}
}

private void UpdateLabelA()
{
// Yes, the model can be accessed by non-UI threads.
if (InvokeRequired)
{
Invoke((MethodInvoker) UpdateLabelA);
return;
}

// Take a local copy.
// Yes, the 'MyModel' properties can be changed by non-UI threads.
var myModel = MyModel;
if (myModel == null) return;

// Lets apply the so special formating.
labelA.Text = String.Format("A is: {0}", myModel.PropertyA);
}

private void UpdateLabelB()
{
if (InvokeRequired)
{
Invoke((MethodInvoker) UpdateLabelB);
return;
}

var myModel = MyModel;
if (myModel == null) return;

labelB.Text = String.Format("B is: {0}", myModel.PropertyB);
}
}


And that is a lot of code !!


I will take any advices to enhance this.


Aucun commentaire:

Enregistrer un commentaire