Home

Awesome

Overview

Sharp.UI is a library for the .NET Multi-platform App User Interface (MAUI) framework that enables you to build user interfaces declaratively in C# code using fluent methods. With Sharp.UI, you can create interfaces without needing to use XAML. Additionally, the library includes hot reload support to make the development process faster and more efficient. The hot reload feature is supported in Visual Studio Code and Visual Studio 2022 using the HotReloadKit library.

<a href="https://youtu.be/wxQr0p3lEg0" target="_blank"> <img src="https://github.com/idexus/Sharp.UI/raw/main/doc/assets/ytscreen2.jpg" alt="Hot Reload Support" width="640" border="0" /> </a>

Hello, World! Example

Here is an example of how you could create a simple "Hello, World!" page in Sharp.UI:

namespace ExampleApp;
using Sharp.UI;

public partial class HelloWorldPage : ContentPage 
{
    int count = 0; 

    public HelloWorldPage()
    {
        Content =

        new VStack(e => e
            .Spacing(25)
            .Padding(30, 0)
            .CenterVertically())
        {
            new Image("dotnet_bot.png", out var image)        
                .HeightRequest(280) 
                .CenterHorizontally(),

            new Label("Welcome to .NET Multi-platform App UI")
                .FontSize(e => e.OnPhone(16).Default(30))
                .CenterHorizontally(),

            new Button("Click me")
                .FontSize(20)
                .CenterHorizontally()
                .OnClicked(button =>
                {
                    count++;
                    button.Text = $"Clicked {count} ";
                    button.Text += count == 1 ? "time" : "times";
                })
        }; 
    }
}

Using Sharp.UI

Nuget Package

To add Sharp.UI to your project, along with all its functionality, you can use:

Repository

This project uses submodules, which means that it depends on other external projects to function properly. To ensure that these dependencies are properly included, you'll need to initialize the submodules when you first clone the repository.

To do this, use the following command:

git submodule update --init --recursive

If you ever update your clone of the repository, you may need to update the submodules as well to ensure that you have the latest version of all dependencies. To do this, you can use the following command:

git submodule update --recursive

Project Reference

You can also add the library to your project by adding a project reference to the Sharp.UI library. For more information, see the Adding the Library by VS Project Reference document.

In Your Project

To use Sharp.UI in your projects, you need to include the using Sharp.UI statement inside your app namespace.

namespace ExampleApp;
using Sharp.UI;

Or:

namespace ExampleApp
{
    using Sharp.UI;
    ...
}

Sharp.UI Template Project

A vanilla sample project using nuget package

https://github.com/idexus/Sharp.UI-Template

Hot Reload

The hot reload feature allows you to see changes to your UI in real-time without having to rebuild the entire application. To use hot reload in Sharp.UI, you will need to use the HotReloadKit library and add SharpUIApp<App>(HotReloadSupport.IdeIPs) extension method in your MauiApp builder.

public static MauiApp CreateMauiApp()
{
    var builder = MauiApp.CreateBuilder();
    builder
        .SharpUIApp<App>(HotReloadSupport.IdeIPs)   // to enable Hot Reload
        .UseMauiApp<App>()
        ...

    return builder.Build();
}

Visual Studio Code and Visual Studio 2022 extensions for both Windows and Mac are available for download from the HotReloadKit releases page. Please note that this is a proof of concept and there is no official support. Use it at your own risk.

Examples

Here are some examples showing how to use the Sharp.UI library

Properties and Fluent Methods

Sharp.UI provides a convenient way to set properties for UI elements by matching properties with fluent helper methods. This makes it easier and more readable to define the interface of your application.

Here is an example of using fluent methods to set properties on a Label:

new Label()
    .Text("This is a test")
    .Padding(20)
    .FontSize(30)

Additionally

new Label("This is a test")
new Label().TextCenter()
new Entry().TextBottomStart()
new VStack
{
    new Label("Hello, World!").CenterHorizontally()
}

Inline bindable property configuration

In C# user interfaces, it's often useful to configure the properties of UI elements inline, instead of setting them directly in XAML or code-behind.

Property binding

One way to configure a bindable property inline is to use the Path method and additional extension methods to bind the property to a data source. For example:

new Label().FontSize(e => e.Path("MyFontSize"))
new Label().Text(e => e.Path("Value").Source(slider).StringFormat("Value : {0:F1}"))

Idiom, Platform, and Theme

Another way to configure bindable properties inline is to set different values for different device idiom (phone, tablet, etc.), platform (WinUI, iOS, etc.), or theme (light or dark). For example:

new Label().FontSize(e => e.OnPhone(30).OnTablet(50).Default(40))
new Label().FontSize(e => e.OnWinUI(30).OniOS(50).Default(40))
new Label().TextColor(e => e.OnLight(Colors.Black).OnDark(Colors.White))

Dynamic resources

Another way to configure bindable properties inline is to use dynamic resources. Dynamic resources are resources whose values can change at runtime. For example:

Resources = new ResourceDictionary
{
    { "myColor", Colors.Yellow },
    ...
}
Label().TextColor(e => e.DynamicResource("myColor"))

Mixing

Finally, it's also possible to mix these various configuration options to achieve more complex property configurations. For example:

new Label()
    .TextColor(e => e
        .OnLight(e => e.OnWinUI(Colors.Aqua).Default(Colors.LightCoral))
        .OnDark(Colors.Black)
    )

How to assign object references

There are two main ways to assign objects in Sharp.UI:

new Label(out label)

Or:

new Label().Assign(out label)

Using fluent methods for styling

Sharp.UI provides a way to define the styles of elements using the Style<T> class and extension methods. Here's an example of how you can define the styles for a Label and a Button:

Resources = new ResourceDictionary
{
    new Style<Label>(e => e
        .FontSize(35)
        .TextColor(AppColors.Gray200)
        .CenterInContainer()),                

    new Style<Button>(e => e
        .BackgroundColor(AppColors.Gray950)
        .Padding(20)
        .CornerRadius(10))
    {
        new VisualState<Button>(VisualStates.Button.Normal, e => e
            .FontSize(33)
            .TextColor(AppColors.Gray200)
            .SizeRequest(270,110)),

        new VisualState<Button>(VisualStates.Button.Disabled, e => e
            .FontSize(20)
            .TextColor(AppColors.Gray600)
            .SizeRequest(180,80))
    }
};

Animations

In Sharp.UI, you can use async methods with the naming convention Animate{PropertyName}To to animate any double or Color bindable property.

For example, to animate the BackgroundColor property, you can use the AnimateBackgroundColorTo async method.

await border.AnimateBackgroundColorTo(Colors.Red, 500);  // 500ms

Example Usage

You can use animations inside event handlers. For example, to animate a Button when it's clicked:

new Button()
    .Text("Click me")
    .OnClicked(async (Button button) =>
    {
        count++;
        button.Text = $"Clicked {count} ";
        button.Text += count == 1 ? "time" : "times";

        _ = button.AnimateBackgroundColorTo(count % 1 == 0 ? Colors.Red : Colors.Blue, 500);
        await button.AnimateFontSizeTo(count % 1 == 0 ? Colors.Red : Colors.Blue);
        await button.RotateTo(360 * (count % 2), 300);
    })

You can also use visual states inside Style<T> to define animations. See the documentation on Style<T> for more information.

Auto-generated code

Sharp.UI library has a feature of automatically generating bindable properties and their fluent helper methods. To use this feature, you need to define the view-model as follows:

[BindableProperties]
public interface IViewModelProperties
{
    string Title { get; set; }
    string Author { get; set; }
}

[SharpObject]
public partial class ViewModel : BindableObject, IViewModelProperties
{
    public void SetAuthor(Button button)
    {
        this.Title = "Tosca";
        this.Author = "Puccini";
    }
}

And, in the view, the code will be:

public class ViewPage : ContentPage
{
    ViewModel viewModel => BindingContext as ViewModel;

    public ViewPage(ViewModel viewModel)
    {
        BindingContext = viewModel;
        Content = new VStack
        {
            new Label().Text(e => e.Path("Author"))
            new Label().Text(e => e.Path("Title"))
            new Button("Click Me")
                .FontSize(100)
                .OnClicked(viewModel.SetAuthor)
        };
    }
}

Other Examples

Advanced

Disclaimer

Sharp.UI is a proof of concept. There is no official support. Use at your own risk.

License

The MIT License, Copyright (c) 2022 Pawel Krzywdzinski