I created a visual studio t4 template to do just that. It will grab a file like this:
using MicroMvvm;
namespace MyApplication
{
[Bindable]
public partial class MyApplication
{
[Bindable]
private string _ipAdress;
[Bindable]
private MyChild _child;
public MyApplication()
{
IpAdress = "ip adress test";
Child = new MyChild(this, "");
}
[Bindable]
void AddDot()
{
IpAdress += ".";
}
[Can]
bool CanChangeChild()
{
return IpAdress.Trim().Length != 0;
}
[Bindable]
void ChangeChild()
{
Child = new MyChild2(this);
}
}
}
And generate this file:
using System;
using System.ComponentModel;
using System.Windows.Input;
using MicroMvvm;
namespace MyApplication
{
public partial class MyApplication : INotifyPropertyChanged
{
[field: NonSerialized]
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged(String propertyName)
{
var handler = PropertyChanged;
if (handler == null) return;
var e = new PropertyChangedEventArgs(propertyName);
handler(this, e);
}
public String IpAdress
{
get { return _ipAdress; }
set
{
_ipAdress = value;
RaisePropertyChanged("IpAdress");
}
}
public MyChild Child
{
get { return _child; }
set
{
_child = value;
RaisePropertyChanged("Child");
}
}
public ICommand AddDotCommand { get { return new RelayCommand(AddDot, null); } }
public ICommand ChangeChildCommand { get { return new RelayCommand(ChangeChild, CanChangeChild); } }
}
}
This is the template, you need to change "MyApplication" to the project name which contains the objects you want to morph into viewmodels.
<#@ template debug="false" hostspecific="false" language="C#" #>
<#@ assembly name="System.Core" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Reflection" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ output extension=".cs" #>
<#@ assembly name="$(SolutionDir)MicroMvvm\bin\Debug\MicroMvvm.dll" #>
<#@ assembly name="$(SolutionDir)MyApplication\bin\Debug\MyApplication.dll" #>
<#@ import namespace="MyApplication" #>
using System;
using System.ComponentModel;
using System.Windows.Input;
using MicroMvvm;
namespace MyApplication
{
<#
var assembly = typeof(MyApplication).Assembly;
var types = new HashSet<Type>(assembly.GetTypes().Where(type => Attribute.GetCustomAttribute(type, typeof(MicroMvvm.Bindable)) != null));
var skip = new HashSet<Type>(types.Where(type => types.Contains(type.BaseType)));
foreach (Type type in types)
{
if (Attribute.GetCustomAttribute(type, typeof(MicroMvvm.Bindable)) == null)
continue;
#>
public partial class <#=type.Name#> <#=skip.Contains(type) ? "" : ": INotifyPropertyChanged"#>
{
<#
if (!skip.Contains(type))
{
#>
[field: NonSerialized]
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged(String propertyName)
{
var handler = PropertyChanged;
if (handler == null) return;
var e = new PropertyChangedEventArgs(propertyName);
handler(this, e);
}
<#
}
foreach(FieldInfo fieldInfo in type.GetFields(BindingFlags.DeclaredOnly | BindingFlags.NonPublic | BindingFlags.Instance)) {
if (!Attribute.IsDefined(fieldInfo, typeof(MicroMvvm.Bindable)))
continue;
if (!fieldInfo.Name.StartsWith("_"))
continue;
string fieldName = fieldInfo.Name.Substring(1);
fieldName = char.ToUpper(fieldName[0]) + fieldName.Substring(1);
#> public <#=fieldInfo.FieldType.Name#> <#=fieldName#>
{
get { return <#=fieldInfo.Name#>; }
set
{
<#=fieldInfo.Name#> = value;
RaisePropertyChanged("<#=fieldName#>");
}
}
<#
}
foreach(MethodInfo method in type.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.NonPublic | BindingFlags.Instance)) {
if (!Attribute.IsDefined(method, typeof(MicroMvvm.Bindable)))
continue;
MethodInfo canMethod = null;
foreach(MethodInfo searchMethod in type.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.NonPublic | BindingFlags.Instance)) {
if (Attribute.IsDefined(searchMethod, typeof(MicroMvvm.Can)) && ("Can" + method.Name).Equals(searchMethod.Name))
canMethod = searchMethod;
}
#> public ICommand <#=method.Name#>Command { get { return new RelayCommand(<#=method.Name#>, <#= canMethod == null ? "null" : canMethod.Name #>); } }
<#
}
#>
}
<#
}
#>
}
It also needs the MicroMvvm framework, and two System.Attribute's Bindable and Can. It significantly cuts down on the boiler plate code you need to write. But its a little bit rough around the edges.