/Paia

Paia is a CLI framework that enables you to easily render and change between different views in a Console application.

Primary LanguageC#MIT LicenseMIT

Pie

Paia 🐵🥧

Paia is a CLI framework that enables you to easily render and change between different views in a Console application.


Give a Star! ⭐

If you like the project, please consider giving it a star to raise awareness!


Table of Contents


Usage

See the sample projects for a basic usage of the framework.

The full project from the tutorial below can be found here.

Quick Installation Guide

Install Package

dotnet add package Paia

Clone the repository

# if you are using ssh
$ git clone git@github.com:Abooow/Paia.git

# if you are using https
$ git clone https://github.com/Abooow/Paia.git

Getting Started

Start by creating a new Console Application.

dotnet new console -o "APP_NAME"

Initialize the App

Add the following lines of code in Program.cs

using Paia;

var builder = new AppBuilder()
builder.Build().Run<MyFirstView>();

MyFirstView will become the starting View for the application, we'll create that View in the next section.


Create, Render and Change View

Creating a View

To create a View, start by creating a new class and inherit the ViewBase class.

using Paia.Views;

class MyFirstView : ViewBase
{
  public override ViewResult Render()
  {
    Console.Clear();
    
    Console.WriteLine("Hello World!");
    Console.WriteLine();
    Console.WriteLine("Press 1 to exit");
    char input = Console.ReadKey().KeyChar;
    
    return input switch
    {
      '1' => Exit(),
       _  => ReRenderView()
    };
  }
}

The Render() method is where you place your main/rendering logic. The method returns a ViewResult, which tells the program what to do next after finishing the rendering process.

Exit() will return a ViewResult telling the framework to exit the application with exitcode 0. (Read more about Exit() and exitcode here)
ReRenderView() instructs the framework to remain in the current view but refresh its display. The state of the View will NOT change, the ViewManager will keep the same instance of the View and only call the Render method again. If you want to refresh the view without retaining its current state, use the RefreshView() method instead.

Change between Views

To change view, simply use the ChangeView<TView>() method provided by the ViewBase class.

using Paia.Views;

class MyFirstView : ViewBase
{
  public override ViewResult Render()
  {
    Console.Clear();
    
    Console.WriteLine("Hello World!");
    Console.WriteLine();
    Console.WriteLine("Press 1 to change View, 2 to exit");
    char input = Console.ReadKey().KeyChar;
    
    return input switch
    {
      '1' => ChangeView<MySecondView>(),
      '2' => Exit(),
       _  => ReRenderView()
    };
  }
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~

class MySecondView : ViewBase
{
  public override ViewResult Render()
  {
    Console.Clear();
    Console.WriteLine("Hello World from my Second View!");
    Console.WriteLine();
    Console.WriteLine("Press a key to go back...");
    Console.ReadKey();
    
    return GoBack();
  }
}

When changing to a new View, the old View (MyFirstView) will be pushed to a stack called BackStack by the ViewManager, making it possible to return to it later if needed.
The GoBack() method pops the stack and renders the previous View (MyFirstView), simultaneously, the current view (MySecondView) is added to another stack called FrontStack. This enables you to move forward in the application flow. You can do this by calling the GoForward() method.


Passing data between Views

Let's add a public Name property to MySecondView. Now MyFirstView will be able to assign a value to it before changing view.

class MySecondView : ViewBase
{
  public string Name { get; set; }

  public override ViewResult Render()
  {
    Console.Clear();
    Console.WriteLine("Hello World from my Second View!");
    Console.WriteLine($"And hello to you, {Name}!");
    
    Console.WriteLine();
    Console.WriteLine("Press a key to go back...");
    Console.ReadKey();
    
    return GoBack();
  }
}

class MyFirstView : ViewBase
{
  public override ViewResult Render()
  {
    Console.Clear();
  
    Console.WriteLine("Hello World!");
    Console.WriteLine();
    Console.WriteLine("Press 1 to change View, 2 to exit");
    char input = Console.ReadKey().KeyChar;
  
    return input switch
    {
      '1' => ChangeView<MySecondView>(view => view.Name = "Monkey Paia"),
      '2' => Exit(),
       _  => ReRenderView()
    };
  }
}

Returning to MyFirstView, the ChangeView<MySecondView>() method accepts an Action<MySecondView> to be passed as a argument.
In the provided example, a lambda expression is used where view serves as a reference to a MySecondView instance. This is how we can access the Name property in order to assign a value to it.

Passing data to the starting View

Let's say we want to be able to change the welcome message in the starting view from Main().
Start by adding a public property called Message in MyFirstView.

class MyFirstView : ViewBase
{
  public string Message { get; set; }

  public override void OnInitialized()
  {
    Message = "Hello World!";
  }

  public override ViewResult Render()
  {
    Console.Clear();
  
    Console.WriteLine(Message);
    Console.WriteLine();
    Console.WriteLine("Press 1 to change View, 2 to exit");
    char input = Console.ReadKey().KeyChar;
  
    return input switch
    {
      '1' => ChangeView<MySecondView>(view => view.Name = "Monkey Paia"),
      '2' => Exit(),
       _  => ReRenderView()
    };
  }
}

The OnInitialized() method will be called only once per View instance, immediately after the constructor and right before the Render() method. Place your initialization code in the OnInitialized() method.

Passing data to the starting View is done in a similar manner as the previous section, by passing a Action<MyFirstView> as an argument, but to the .Run<MyFirstView>() method instead.

var builder = new AppBuilder()
builder.Build().Run<MyFirstView>(view => view.Message = "Yo World!");

Dependency Injection

Adding Dependency Injection

Add services to the app by using the builder.Services property in AppBuilder.

var builder = new AppBuilder()
builder.Services.AddSingleton<IMyService, MyServiceImplementation>()

builder.Build().Run<MyFirstView>(view => view.Message = "Yo World!");

Injecting a service

To inject a service to a view, use the [Inject] attribute on a public property with a setter.

using Paia.Attributes;

class MyFirstView : ViewBase
{
  [Inject]
  public IMyService MyService { get; set; }

  public override ViewResult Render()
  {
    ...
  }
}

More

Exit() and exitcode

To exit the application with a exitcode other than 0, you need a return statement on the .Run<>() method.

var builder = new AppBuilder()
return builder.Build().Run<MyFirstView>();

The .Run<>() method returns an int, which is the exit code for the application.
Exit() (called from Views) will return 0 by default, but has a overload allowing you to pass an integer as a argument for a custom exitcode.

class MyFirstView : ViewBase
{
  public override ViewResult Render()
  {
    Console.WriteLine("Press a key for a nice exit...");
    Console.ReadKey();
    
    return 69;
  }
}

It's possible to also return an integer directly from a View, there is an implicit conversion from int to ViewResult. This is telling the View to exit with exitcode 69.


Maintainers

This repository is currently maintained by @Abooow.

License

This project has been released under the MIT license. More information can be found by viewing the license here.