.NET, C#, MVVM, TextTemplate, XAML

Using TextTemplate to Generate Wrapper classes

Wrapping classes is sometimes necessary in development. The MVVM pattern usually wraps the model inside a viewmodel class for it tobe bindable. In brokered component we can’t expose a class from a referenced library unless we wrap it in a sealed class. The problem with wrapping is that we repeat the same code over and we expose properties and function with the same name and we have to retype it and it takes some amount of time.

The good news is that there’s an item in visual studio called TextTemplate. Text template is a scriptable file that can generate code for you and those generated files are usable within the assembly.

Now going back to the problem of wrapping classes. We as developers doesn’t want to spend time typing repetitive codes. Using reflection I managed to create a reusable script that can generate a wrapper class. This script will generate wrapped properties, methods, constructors and nested class. You can download the TextTemplate source code from my Github repo.

Basic Class Wrapping

Classes that will be wrapped within a wrapper:

public class User
{
public string FirstName { get; set; }

public string LastName { get; set; }

public string UserName { get; set; }

public int Role { get; set; }

public int InvalidLoginAttempt { get; set; }

}

public class Driver
{
public Driver(string name) { }

public Driver() { Nested = new SomeNestedClass(); }

public string DriverId { get; private set; }

public string DriverName { get; set; }

public string TruckNo { get; set; }

public SomeNestedClass Nested { get; set; }

public User UserInfo { get; set; }

public void StartShift(string p1, string p2, ref int odometer, params object[] args) { Console.WriteLine("StartShift"); }

public int EndShift(string p1, string p2, out int odometer) { Console.WriteLine("EndShift"); odometer = 1; return 0; }

public class SomeNestedClass
{
public string NestedValue { get; set; }

public string NestedName { get; set; }

public void Hello()
{
Console.WriteLine("Hello Nested World");
}
}
}

Wrapped Classes:

public sealed class Driver
{
#region Constructors

public DataModels.Driver driverDataModel;
public Driver(DataModels.Driver driver) { this.driverDataModel = driver; }
public Driver(System.String name)
{
driverDataModel = new DataModels.Driver(name);
}
public Driver()
{
driverDataModel = new DataModels.Driver();
}

#endregion Constructors

#region Properties

public System.String DriverId { get { return driverDataModel.DriverId; }  }
public System.String DriverName { get { return driverDataModel.DriverName; } set { driverDataModel.DriverName = value; } }
public System.String TruckNo { get { return driverDataModel.TruckNo; } set { driverDataModel.TruckNo = value; } }
private BasicClassWrapperSample.SomeNestedClass _Nested = null;
public BasicClassWrapperSample.SomeNestedClass Nested { get { if(_Nested == null) _Nested = new BasicClassWrapperSample.SomeNestedClass(driverDataModel.Nested); return _Nested; } set { _Nested = value; } }
private BasicClassWrapperSample.User _UserInfo = null;
public BasicClassWrapperSample.User UserInfo { get { if(_UserInfo == null) _UserInfo = new BasicClassWrapperSample.User(driverDataModel.UserInfo); return _UserInfo; } set { _UserInfo = value; } }

#endregion Properties

#region Methods

public void StartShift (System.String p1, System.String p2, ref System.Int32 odometer, params System.Object[] args) => driverDataModel.StartShift(p1, p2, ref odometer, args);
public System.Int32 EndShift (System.String p1, System.String p2, out System.Int32 odometer) => driverDataModel.EndShift(p1, p2, out odometer);

#endregion Methods
}
public sealed class SomeNestedClass
{
#region Constructors

public DataModels.Driver.SomeNestedClass somenestedclassDataModel;
public SomeNestedClass(DataModels.Driver.SomeNestedClass somenestedclass) { this.somenestedclassDataModel = somenestedclass; }
public SomeNestedClass()
{
somenestedclassDataModel = new DataModels.Driver.SomeNestedClass();
}

#endregion Constructors

#region Properties

public System.String NestedValue { get { return somenestedclassDataModel.NestedValue; } set { somenestedclassDataModel.NestedValue = value; } }
public System.String NestedName { get { return somenestedclassDataModel.NestedName; } set { somenestedclassDataModel.NestedName = value; } }

#endregion Properties

#region Methods

public void Hello () => somenestedclassDataModel.Hello();

#endregion Methods
}

public sealed class User
{
#region Constructors

public DataModels.User userDataModel;
public User(DataModels.User user) { this.userDataModel = user; }
public User()
{
userDataModel = new DataModels.User();
}

#endregion Constructors

#region Properties

public System.String FirstName { get { return userDataModel.FirstName; } set { userDataModel.FirstName = value; } }
public System.String LastName { get { return userDataModel.LastName; } set { userDataModel.LastName = value; } }
public System.String UserName { get { return userDataModel.UserName; } set { userDataModel.UserName = value; } }
public System.Int32 Role { get { return userDataModel.Role; } set { userDataModel.Role = value; } }
public System.Int32 InvalidLoginAttempt { get { return userDataModel.InvalidLoginAttempt; } set { userDataModel.InvalidLoginAttempt = value; } }

#endregion Properties

#region Methods

#endregion Methods
}

Wrapping Model within ViewModel

//Model
public class User
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string UserName { get; set; }
public int Role { get; set; }
public int InvalidLoginAttempt { get; set; }
}

//Wrapped ViewModel
public sealed class UserViewModel : ViewModelBase
{
#region Constructors

public DataModels.User userDataModel;
public UserViewModel(DataModels.User user) { this.userDataModel = user; }
public UserViewModel()
{
userDataModel = new DataModels.User();
}

#endregion Constructors

#region Properties

public System.String FirstName { get { return userDataModel.FirstName; } set { userDataModel.FirstName = value; OnPropertyChanged(); } }
public System.String LastName { get { return userDataModel.LastName; } set { userDataModel.LastName = value; OnPropertyChanged(); } }
public System.String UserName { get { return userDataModel.UserName; } set { userDataModel.UserName = value; OnPropertyChanged(); } }
public System.Int32 Role { get { return userDataModel.Role; } set { userDataModel.Role = value; OnPropertyChanged(); } }
public System.Int32 InvalidLoginAttempt { get { return userDataModel.InvalidLoginAttempt; } set { userDataModel.InvalidLoginAttempt = value; OnPropertyChanged(); } }

#endregion Properties
}

 

.NET, BrokeredComponent, UWP, XAML

Part 2: Brokered Component for UWP App Starter Kit

My previous blog about brokered components demonstrate a procedure on how to consume a brokered component in a windows store app (Universal windows). It described some details and a lot of steps to get started with brokered components. I’m assuming that you have already read the previous blog post about brokered component or you have enough knowledge about it. Now to make it easier, I created a brokered component starter kit inside the VSIX installer together with the previous brokered component project templates. You can download the templates in visual studio gallery. There will be a new project template called Brokered Component Solution. This will create a solution that has three projects, the client, the server and the proxy.

Here are the steps on how to use the brokered component starter kit:
1. Download the Brokered Component Templates from visual studio gallery or update the extension if you have already downloaded it.
2. Run Visual Studio 2015 as an Administrator and create a new project.
3. In the new project dialog, try to search for “Brokered Component Solution”

bcsolution
4. Type in the Solution name and click ok.
5. A Setup dialog box will appear. Type in the desired names for the client, proxy and the server project then click OK.

Setup Dialog
6. It will generate a new solution with the three projects in it.

Projects
7. Build the server project (right click on the project then build).
8. Right click on the proxy project and add existing item.
9. Add the files generated by the server (dlldata.c, server_i.c, server_p.c, server.h)

Addexistingcfiles

Add existing
10. Build the Proxy project.
11. Right click on the Client project then add a new reference.
12. Click browse and then locate the reference folder of the server, then select server.winmd (i.e. Server\Bin\Debug\Reference\Server.winmd).

addref

ref

refwinmd.PNG
13. Set the Client project as the Start up project.
14. Hit F5 to run the client project.

app.PNG

The new template takes care of a bunch of things such as the registration of proxy.dll, the setup of app manifest, the copying of dlls to the debug folder. If you want to know more details about the brokered component, you can check my previous post or read about the brokered component white paper.

One last tweak, this is optional by the way. We don’t want to build each project one by one everytime there’s a change in the server. To do that, we need to configure the project dependencies. In the solution explorer, right click on the solution then click Project Dependencies. We want to make sure that the Client is dependent on both Proxy and Server and the Proxy is dependent on the Server. This will give us a build order of Server->Proxy->Client.

You can download the sourcecode from GitHub