VEFramework.VEBlazor.Editable 0.4.2

dotnet add package VEFramework.VEBlazor.Editable --version 0.4.2                
NuGet\Install-Package VEFramework.VEBlazor.Editable -Version 0.4.2                
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="VEFramework.VEBlazor.Editable" Version="0.4.2" />                
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add VEFramework.VEBlazor.Editable --version 0.4.2                
#r "nuget: VEFramework.VEBlazor.Editable, 0.4.2"                
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install VEFramework.VEBlazor.Editable as a Cake Addin
#addin nuget:?package=VEFramework.VEBlazor.Editable&version=0.4.2

// Install VEFramework.VEBlazor.Editable as a Cake Tool
#tool nuget:?package=VEFramework.VEBlazor.Editable&version=0.4.2                

VEBlazor.Editable

VEBlazor.Editable

Komponenta Editable je dodatečným (extension) balíčkem VEBlazor knihovny. Vznikla kvůli potřebě častého zobrazování parametrů tříd v UI a jejich editace.

Editable text property

Editable bool property

C# v kódu umožňuje pracovat s abstraktní vrstvou tříd. Příkladem využití v praxi je komponenta Editable resp. její vnitřní logika. Příklad demonstrace komponenty na projektu VEBlazor.Editable.Demo.

Demo vychází ze standardního dema pro Blazor WASM aplikaci. Navíc je přidána reference na projekt/balíček VEFramework.VEBlazor.Editable. Definice modelu třídy Piano, komponenta Piano a její přidání do Index.razor. Definice třídy obsahuje několik základních parametrů piána:

namespace VEBlazor.Editable.Demo.Models
{
    public class Piano
    {
        public string Name { get; set; } = string.Empty;
        public string Brand { get; set; } = string.Empty;
        public int NumberOfKeys { get; set; } = 88;
        public double Volume { get; set; } = 0.5;
        public bool IsOn { get; set; } = true;
    }
}

Parametry jsou různých typů. Pro jejich zobrazení a editaci, by byla potřeba samostatná logika. A tu řeší právě komponenta Editable. Pokud je potřeba zobrazit parametr a umožnit jeho editaci, lze to udělat tak jako v komponentě PianoComponent.razor

<Editable Item="@PianoModel" ParameterName="@(nameof(PianoModel.Name))" TItem="Piano" ItemChanged="@OnPianoChanged" />
<Editable Item="@PianoModel" ParameterName="@(nameof(PianoModel.Brand))" TItem="Piano" ItemChanged="@OnPianoChanged" />
<Editable Item="@PianoModel" ParameterName="@(nameof(PianoModel.NumberOfKeys))" TItem="Piano" ItemChanged="@OnPianoChanged" />
<Editable Item="@PianoModel" ParameterName="@(nameof(PianoModel.Volume))" TItem="Piano" ItemChanged="@OnPianoChanged" />
<Editable Item="@PianoModel" ParameterName="@(nameof(PianoModel.IsOn))" TItem="Piano" ItemChanged="@OnPianoChanged" />

Pro všechny parametry je společný handler pro detekci jejich změny - OnPianoChanged, který propaguje i aktualizovanou verzi objektu:

    [Parameter]
    public Piano PianoModel { get; set; } = new Piano() { Name = "S82", Brand = "Yamaha" };

    private void OnPianoChanged(Piano e)
    {
        PianoModel = e;
        StateHasChanged();
    }

Blazor umožňuje definovat, že komponenta bude přebírat generický typ objektu. To se provede tak, že se na začátek .razor souboru napíše:

@typeparam TItem

Tím se definuje TItem jako Parametr, ideálně s OnChanged EventCallbackem, aby se s objektem dalo v kódu pracovat.

    [Parameter]
    public TItem? Item { get; set; }
    [Parameter]
    public EventCallback<TItem> ItemChanged { get; set; }

Aby komponenta věděla, se kterým parametrem v objektu má pracovat (jestli s Name, Volume, apod.) je potřeba zadat název parametru:

    [Parameter]
    public string? ParameterName { get; set; }

Ten je zadaný jako string, nicméně se doporučuje volbu parametru nezadávat natvrdo. Spíš se doporučuje využít konstrukci s nameof, protože pokud se automaticky přes IDE mění název ve třídě, správně se zpropaguje/změní všude. Příklad:

   nameof(PianoModel.Name) // takto namísto "Name"

C# dokáže identifikovat názvy proměných a funkcí ve třídě. Ty pak vyhledat a přistupovat k nim jako k objektům. Díky tomu lze zjistit typ a přizpůsobit čtení/editaci hodnoty. To samé platí pro zobrazení v UI. Dohledání typu lze udělat automaticky, což je řešeno funkcí LoadParam.

Na začátku se ověří, jestli v objektu typu TItem existuje konkrétní jméno parametru. Pokud ano, vrátí první parametr jména, pokud ne, vrátí null.

var param = typeof(TItem).GetProperties().Where(p => p.Name == ParameterName).FirstOrDefault();

Pokud je možné parametr číst, získá se jeho hodnota a podle typu se převede do obecné proměné ParametrValue:

if (param != null && param.CanRead)
        {
            var value = param.GetValue(Item);
            if (value != null)
            {
                paramType = param.PropertyType;

                if (param.PropertyType == typeof(string) || param.PropertyType == typeof(String))
                    ParameterValue = (string)value;
                else if (param.PropertyType == typeof(int))
                    ParameterValue = (int)value;
                else if (param.PropertyType == typeof(double))
                    ParameterValue = (double)value;
                else if (param.PropertyType == typeof(bool))
                    ParameterValue = (bool)value;

                await InvokeAsync(StateHasChanged);
            }
        }

Za zmínku ještě stojí funkce, která zajistí uložení parametru:

    private async Task Save()
    {
        Editing = false;

        var param = typeof(TItem).GetProperties().Where(p => p.Name == ParameterName).FirstOrDefault();
        if (param != null && param.CanWrite)
        {
            param.SetValue(Item, ParameterValue);
            await ItemChanged.InvokeAsync(Item);
        }
        await InvokeAsync(StateHasChanged);
    }

Při ukládání se opět zavolá parametr jako obecný objekt a pomocí jeho funkce SetValue se mu přiřadí nová hodnota. Musí se ale zajistit správnost zadané hodnoty. To řeší funkce OnValueChanged, která parsuje vstup od uživatele podle identifikovaného typu parametru, který se dohledal automaticky:

paramType = param.PropertyType;

Komponentu by bylo vhodné rozšířit ještě minimálně o datum. Případné další návrhy a dokonce kontribuce jsou vítány 😃

Product Compatible and additional computed target framework versions.
.NET net6.0 is compatible.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 is compatible.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (1)

Showing the top 1 NuGet packages that depend on VEFramework.VEBlazor.Editable:

Package Downloads
VEFramework.VEBlazor.EntitiesBlocks

Blazor Component library for .NET drivers for calculation of the entities and its time based blocks with specfic amount.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
0.4.2 212 9/24/2023
0.3.3 196 2/12/2023