Click here to Skip to main content
15,867,308 members
Articles / Web Development

Introducing Layouts - Xaml for the Web

Rate me:
Please Sign up or sign in to vote.
2.73/5 (4 votes)
19 Oct 2015CPOL5 min read 19.7K   128   6   4
Layouts is a Javascript library that let you create web applications with complex UI using Xaml

Layouts Sample Application Screenshot

Introduction

With Layouts you can create a web application using Xaml markup language to define its UI. Actually Layouts does much more than this: you can create a fully SPA (single page application) using best MVVM practices. Layouts is suited to build complex user interfaces like dashboards or LOB applications but is easy enough to even just build a page of your exiting application.

In short Layouts replaces HTML with XAML and leave the same Javascript and CSS that web developers are used to work with.

A basic knowledge of TypeScript (http://www.typescriptlang.org/) is preferable before reading this article or look at Layouts source.

Getting Started

First create an empty TypeScript project in Visual Studio (or in Sublime or whatsoever).

Put in following files:

index.xml is an empty HTML page with links to layouts.js, linq.min.js and app.js:

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="utf-8" />
	<title>Layouts Sample</title>
	<link rel="stylesheet" href="app.css" type="text/css" />
	<script src="linq.min.js" type="text/javascript"></script>
	<script src="layouts.js" type="text/javascript"></script>
	<script src="app.js" type="text/javascript"></script>
	</head>
	<body>
	</body>
</html>

Also create a CSS file (app.css) that just remove any margins and set body to occupy the whole page:

CSS
* {
	margin: 0px;
}
	html { 
	height:100%; 
}
body {
	font-family: 'Segoe UI', sans-serif;
	height:100%; 
	margin:0px; 
}
#helloworld {
	color: red;
}

Finally copy latest layouts.js file from github.com repository, excellent linq.min.js from https://linqjs.codeplex.com/ and setup TypeScript compiler to generate everything in one single file called app.js.

Hello World

Add a typescript file app.ts like the following:

JavaScript
/// <reference path="layouts.d.ts"/>
window.onload = () => {
	var app = new layouts.Application();
	var lmlReader = new layouts.XamlReader();
	var lmlTest = `<?xml version="1.0" encoding="utf-8" ?>
		<Page>
			<TextBlock id="helloworld" Text="Hello World" VerticalAlignment="Center" HorizontalAlignment="Center"/>
		</Page>
	`;
	app.page = lmlReader.Parse(lmlTest);
};

If everything compile and run you should be able to see a white page with Hello World centered in red.

Looking at above code you will see that I've created an Application (variable app) and a xaml reader (lmlReader). Next I'll describe how my page should be composed in xaml-like markup that I than pass to XamlReader.Parse method to get a Page object. Application.Page is finally set with newly created page.In layouts there can be only one Application object. Application.Page returns current page: one could switch between pages just setting this property.

The interesting part is how Page is defined in Xaml. We define the Page itself using the Page header that contains a TextBlock element. Looking at TextBlock, it defines a paragraph object (p) vertically and horizontally center. TextBlock id attribute is directly passed to resulting HTML so we can just select it in CSS file (app.css) to give it a red color.

Let's experiment a bit with this xaml for example set HorizontalAlignment to Left or Right and VerticalAlignment to Top or Bottom.

XamlReader.Parse method is quite powerful because it doesn't only manage Page object. It can parse and create other layouts controls but also controls you define in your code.

Sample Login Page

Now let's complicate a bit our sample creating a login page:

JavaScript
window.onload = () => {
	var app = new layouts.Application();
	var lmlReader = new layouts.XamlReader();

	var lmlTest = `<?xml version= "1.0" encoding= "utf-8" ?>
	<Stack Orientation="Vertical" VerticalAlignment= "Center" HorizontalAlignment= "Center" >
		<TextBlock Text="Welcome to Login Page" Margin= "8" />
		<TextBox Placeholder= "User name" Margin= "8" />
		<TextBox Type= "password" Placeholder= "Password" Margin= "8" />
		<Button Text="Sign In" Margin= "8,16,8,8" />
	</Stack>
	`;
	app.page = lmlReader.Parse(lmlTest);
};

Stack element is fundamental element in Layouts (as long with Grid) that allows arranging children elements in a stack vertically or horizontally oriented. TextBox is rendered as an HTML input control and Button as a html button. Margin is an attribute that determines how elements are positioned relative to their borders. Margin="8" means "reserve 8 pixel space on top, right, bottom and left".

Note that button is disabled: we have not yet specified a command for the button so Layouts disables it (see below).

Take a moment to experiment with Layouts Margin and Orientation properties. You can also embed a Stack inside another Stack.

Make another small modification:

JavaScript
var lmlTest = `<?xml version= "1.0" encoding= "utf-8" ?>
<Stack Orientation="Vertical" VerticalAlignment= "Center" HorizontalAlignment= "Center">
	<TextBlock Text="Welcome to Login Page" Margin= "8" />
		<TextBox Placeholder= "User name" Margin= "8" />
	<TextBox Type= "password" Placeholder= "Password" Margin= "8" />
	<Grid Columns="* Auto" Margin= "8,16,8,8" MaxWidth="300">
		<Button Text="Sign In"/>
		<TextBlock Text="Not yet registered?" Grid.Column="1" Margin="10,0,0,0"/>
	</Grid>
</Stack>
`;

We've added a Grid panel inside the stack. Grid is the most powerful element present in Layouts. Grid arranges its children using grid layout composed of Rows and Columns. Above we've created a Grid with 2 columns and 1 row (by default). First column has star (*) width, second column is set to Auto. Grid also supports fixed size columns or rows where you'll be able to specify how large should be a column or row in pixels.

Again take a moment experimenting with Grid. Please note that if you change text "Not yet registered" with something else Grid will reserve enough space to completely show new text. Auto sizing is one important Layouts feature: it allows the creation of interfaces that follow content size.

MVVM

Layouts encourages use of MVVM pattern: it provides some important classes you are required to implement in order to plug UI elements with models. I can't dive here too much in MVVM description and I'm sure out there you can find guides and tutorials that describe it much better than I could do.

Let's create a view-model class that can handle login process:

JavaScript
class LoginViewModel extends layouts.DepObject {
	static typeName: string = "app.LoginViewModel";
	get typeName(): string {
		return LoginViewModel.typeName;
	}

	constructor() {
		super();
	}
	
	private _username: string;
	get username(): string {
		return this._username;
	}
	set username(value: string) {
		if (this._username != value) {
			var oldValue = this._username;
			this._username = value;
			this.onPropertyChanged("username", value, oldValue);
			this._loginCommand.canExecuteChanged();
		}
	}
	
	private _password: string;
	get password(): string {
		return this._password;
	}
	set password(value: string) {
		if (this._password != value) {
			var oldValue = this._password;
			this._password = value;
			this.onPropertyChanged("password", value, oldValue);
			this._loginCommand.canExecuteChanged();
		}
	}
	
	private _loginCommand: layouts.Command;
	get loginCommand(): layouts.Command {
		if (this._loginCommand == null)
			this._loginCommand = new layouts.Command((cmd, p) => this.onLogin(), (cmd, p) => this.canLogin());
		return this._loginCommand;
	}
	
	onLogin() {
		if (this._username == "test" &&
			this._password == "test") {
			alert("Logged in!");
		}
		else
			alert("Unable to login!");
	}
	
	canLogin(): boolean {
		return this._username != null && this._username.trim().length > 0 &&
		this._password != null && this._password.trim().length > 0;
	}

}

Layouts defines a type called DepObject that provides some basic features useful to create view models. For example above we've defined a LoginViewModel class that derives from DepObject. Our view model defines a couple of properties (Username and Password) and a command (loginCommand). The first part declaring the type name is required to making Layouts binding work (as there is no way in javascript to discover type name at runtime).

Now let's link the view (login page) to above view-model:

JavaScript
window.onload = () => {
	var app = new layouts.Application();
	var lmlReader = new layouts.XamlReader();

	var lmlTest = `<?xml version= "1.0" encoding= "utf-8" ?>
	<Stack Orientation="Vertical" VerticalAlignment="Center" HorizontalAlignment="Center">
		<TextBlock Text="Welcome to Login Page" Margin="8"/>
		<TextBox Text="{username,mode:twoway}" Placeholder="User name (test)" Margin="8"/>
		<TextBox Text="{password,mode:twoway}" Type="password" Placeholder="Password (test)" Margin="8"/>
		<Button Text="Sign In" Command="{loginCommand}" Margin="8,16,8,8"/>
	</Stack>
	`;
	app.page = lmlReader.Parse(lmlTest);
	app.page.dataContext = new LoginViewModel();
};

First thing to note is that I've set property dataContext of current page to a new instance of LoginViewModel. Than looking at xaml definition you can certainly notice that I've informed Layouts to bind first text box to Username property of the view-model, second textbox to Password and finally button to loginCommand. Now if you run the sample application you should be able to edit username and password and then sign-in.

What's next?

Layouts is a large framework and would be impossible to describe all details in an article. This is a summary of what you could get with it:

  • Controls like ItemsControl, ControlTemplate and ContentTemplate and many other
  • Ability to create custom controls deriving from FrameworkElement or UserContol. In github repository you'll find controls like TreeView and TabView.
  • Ability to embed external UI frameworks (I’ve successfully used Kendo UI, JQuery UI and datatables.net in projects)
  • Complex binding scenarios with custom converters and targets (self,dataContext,element)
  • Ability to directly embed HTML as native elements
  • Embedded navigation system for SPA implementation

Conclusion

Layouts is my attempt to port Xaml and WPF paradigms to web application development. I've used Layouts to build a complex dashboard application that is now getting in production and that will be used by tens of people. In the last 3 months I've deeply worked to get it stable and fully featured.

History

10-19-2015 First Article Release

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Systems Engineer
Italy Italy
I bought my first computer in Nov 1991, 21st and I started programming with QBasic under MSDOS.
Today my main interest is developping applications with .NET and HTML5 stack.

Comments and Discussions

 
QuestionYou are rock! Pin
Daniel Degtyarev11-May-16 1:52
Daniel Degtyarev11-May-16 1:52 
Good work. I am working on similar stuff, could you contact with me davinci (at) mail (dot) ru I think we can be helpful for each other.

modified 11-May-16 8:14am.

AnswerRe: You are rock! Pin
adospace.NET12-May-16 10:31
adospace.NET12-May-16 10:31 
QuestionCool stuff Pin
dazinator20-Oct-15 13:05
dazinator20-Oct-15 13:05 
AnswerRe: Cool stuff Pin
adospace.NET20-Oct-15 21:31
adospace.NET20-Oct-15 21:31 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.