API

Templating via PBars happens in two steps. You first create an instance of the PBarsCompiler class. Then you use this instance to translate templates into renderers. The renderer is is called with an object that represents the viewmodel to render. Here is a simple example:

// 01_SimpleExample
var compiler = new PBarsCompiler();
var renderer = compiler.Compile("{{Greet}}");
Trace.WriteLine(renderer.Render(new { Greet="Hello World!" }));

You can optionally pass in an object to the PBarsCompiler, which allows to configure various aspects about it's behavior.

var compiler = new PBarsCompiler(new CompilerOptions() { ConvertTabsToSpaces = false });

I would suggest to have just one compiler instance for your whole application and spawn all renderers from this instance if possible.

Templating directives

To make templating possible, the original template document is augmented with so called templating directive. A templating directive allows PBars to link the template to the viewmodel (e.g. by embedding items from the viewmodel in the output. Here is a simple example of a viewmodel and a template that displays a property of it.

Viewmodel:

class ViewModel
{
    public string Name
    {
        get
        {
            return "Bob";
        }
    }
}

Template:

Hello {{Name}}!

When running the template, the renderer will replace the {{Name}} placeholder with the value Bob. This is the simplest way to do templating. In the following sections you will see some more complex things you can do.

#each

The each directive lets the renderer iterate over a collection in the viewmode. Inside the each directive, all references to the viewmodel will be rebased to the current item that the iteration loops over. Here is an example:

Viewmodel:

// 02_Each
class ViewModel
{
    private readonly Person[] m_People = new[]
    {
        new Person { FirstName = "Bob", LastName = "Smith" },
        new Person { FirstName = "Alice", LastName = "Cooper" }

    };

    public Person[] People
    {
        get
        {
            return m_People;
        }
    }
}

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

    public string LastName
    {
        get;
        set;
    }
}

Template:

{{#each People}}
    Hello {{FirstName}} {{LastName}}!
{{/each}}

#with

The with directive lets the renderer enter a deeper context in the view model. Though not strictly necessary to, it saves you from having to type a lot of navigation paths when working with deep object graphs. Here is an example:

Viewmodel:

// 03_With
class ViewModel
{
    private readonly Person m_Person = new Person { FirstName = "Alice", LastName = "Cooper" };

    public Person Person
    {
        get
        {
            return m_Person;
        }
    }
}

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

    public string LastName
    {
        get;
        set;
    }
}

Template:

{{#with Person}}
    Hello {{FirstName}} {{LastName}}!
{{/with}}

#if / #else

The if/else directive lets the renderer selective render blocks based on whether an expression is true or false. The else part of the expression is optional.

Viewmodel:

// 04_IfElse
class ViewModel
{
    public bool IsFemale
    {
        get
        {
            return true;
        }
    }

    public string LastName
    {
        get
        {
            return "Cooper";
        }
    }
}

Template:

Hello {{#if IsFemale}}Mrs.{{#else}}Mr.{{/if}} {{LastName}}!

#template

The template directive allows the renderer to embed an external template in-place. This is especially useful with big templates and with templates that contain the same parts in multiple places.

Viewmodel:

// 05_Template
class ViewModel
{
    private readonly Person[] m_People = new[]
    {
        new Person { FirstName = "Bob", LastName = "Smith" },
        new Person { FirstName = "Alice", LastName = "Cooper" }
    };

    public Person[] People
    {
        get
        {
            return m_People;
        }
    }
}

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

    public string LastName
    {
        get;
        set;
    }
}

Template:

{{#each People}}
    {{#template SubTemplate.txt}}
{{/each}}

Sub Template:

Hello {{FirstName}} {{LastName}}!

Just trying to render this example without a special setup will throw an exception:

Specify a template registry in the compiler options to have child template support.

The reason is, that PBars cannot determine, how to get to the sub-template. Read the chapter about template registries for more information. A template directive may additionally define a new context (like the with directive). Here is an example:

Viewmodel:

// 05_Template
class ViewModelWithOnePerson
{
    private readonly Person m_Person = new Person { FirstName = "Bob", LastName = "Smith" };

    public Person Person
    {
        get
        {
            return m_Person;
        }
    }
}

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

    public string LastName
    {
        get;
        set;
    }
}

Template:

{{#template SubTemplate.txt Person}}

Sub Template:

Hello {{FirstName}} {{LastName}}!

You may also use a template selector (a property on the viewmodel determines, which template to use). Here is an example:

Template:

{{#each People}}
    {{#template [(parent).TemplateName]}}
{{/each}}

Viewmodel:

// 05_Template
class ViewModel
{
    private readonly Person[] m_People = new[]
    {
        new Person { FirstName = "Bob", LastName = "Smith" },
        new Person { FirstName = "Alice", LastName = "Cooper" }
    };

    public Person[] People
    {
        get
        {
            return m_People;
        }
    }

    public string TemplateName
    {
        get
        {
            return "SubTemplate.txt";
        }
    }
}

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

    public string LastName
    {
        get;
        set;
    }
}

\

Using a \ at the end of the line will join the line with the next one. This makes it possible to distribute complex template expressions to multiple lines making them more readable. Here is an example:

Template:

This will go \
into one line.

Data expressions

Data expressions display data from the view model in the rendered output. You've seen them already in all examples before. Data expressions are just navigation paths relative to the corrent data context inside the view model. You may navigate downwards the object graph using the . notation:

Viewmodel:

// 06_DataExpression
class ViewModel
{
    private Person m_Person = new Person { FirstName = "Alice", LastName = "Cooper" };

    public Person Person
    {
        get
        {
            return m_Person;
        }
    }

    public string City
    {
        get
        {
            return "Cologne";
        }
    }
}

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

    public string LastName
    {
        get;
        set;
    }
}

Template:

Hello {{Person.FirstName}} {{Person.LastName}}!

(this) / (parent)

In addition, there are two reserved keywords, (this) and (parent). This returns the value directly at the data context, while parent navigates one path upwards. Here is an example.

Viewmodel:

// 06_DataExpression
class ViewModel
{
    private Person m_Person = new Person { FirstName = "Alice", LastName = "Cooper" };

    public Person Person
    {
        get
        {
            return m_Person;
        }
    }

    public string City
    {
        get
        {
            return "Cologne";
        }
    }
}

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

    public string LastName
    {
        get;
        set;
    }
}

Template:

{{#with Person.FirstName}}
{{(this)}}
{{/with}}
{{#with Person}}
{{(parent).City}}
{{/with}}

Automatic property inheritence

Properties automatically flow down the data context. This means that you can just use a property as if it existed on the same level, even though it comes from somewhere above in the object graph. Here is an example:

Viewmodel:

// 06_DataExpression
class ViewModel
{
    private Person m_Person = new Person { FirstName = "Alice", LastName = "Cooper" };

    public Person Person
    {
        get
        {
            return m_Person;
        }
    }

    public string City
    {
        get
        {
            return "Cologne";
        }
    }
}

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

    public string LastName
    {
        get;
        set;
    }
}

Template:

{{#with Person.FirstName}}
{{City}}
{{/with}}

Full line expressions

When you are not templating for HTML but raw text, it sometimes get's quite annoying, that directives are not totally invisible to the output, but at least create a line feed or spaces when indented. Here is an example:

Template:

{{#with Person.FirstName}}
{{City}}
{{/with}}

Without special handling, the with statement lines would render line feeds. PBars has a concept of full line expressions. This means that a line contains nothing but a {{#with}}, {{/with}}, {{#each}}, {{/each}}, {{#template}} and optionally spaces, this stuff will all be removed from the output.

#index

The #index expression returns the zero-based index of an item in a collection. Here is an example:

Viewmodel:

// 06_DataExpression 
class ViewModelWithCollection
{
    private Person[] m_People = new[]
    {
        new Person { FirstName = "Alice", LastName = "Cooper" },
        new Person{FirstName = "Bob", LastName="Smith"}
    };

    public Person[] People
    {
        get
        {
            return m_People;
        }
    }
}

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

    public string LastName
    {
        get;
        set;
    }
}

Template:

{{#each People}}
{{#index}} - {{FirstName}} {{LastName}}
{{/each}}