Data Validation - Code

Data Models

Tax.cs

using System;
using System.ComponentModel.DataAnnotations;

namespace BlazorPurchaseOrders.Data
{
    public class Tax
    {
        [Required]
        public int TaxID { get; set; }

        [Required(ErrorMessage = "'Description' is required.")]
        [StringLength(50, ErrorMessage = "'Description' has a maximum length of 50 characters.")]
        public string TaxDescription { get; set; }

        [Required(ErrorMessage = "'Rate' is required.")]
        [Range(0, 1, ErrorMessage = "'Rate' must be in the range 0 to 1 (0-100%)")]
        public decimal TaxRate { get; set; }

        [Required]
        public bool TaxIsArchived { get; set; }
    }
}

Supplier.cs

using System;
using System.ComponentModel.DataAnnotations;

namespace BlazorPurchaseOrders.Data
{
    public class Supplier
    {
        [Required]
        public int SupplierID { get; set; }

        [Required(ErrorMessage = "'Supplier Name' is required.")]
        [StringLength(50, MinimumLength = 4, ErrorMessage = "'Supplier Name' has a minimum length of 4 and maximum of 50 characters.")]
        public string SupplierName { get; set; }

        [StringLength(50, ErrorMessage = "'Address' has a maximum length of 50 characters.")]
        public string SupplierAddress1 { get; set; }

        [StringLength(50, ErrorMessage = "'Address' has a maximum length of 50 characters.")]
        public string SupplierAddress2 { get; set; }

        [StringLength(50, ErrorMessage = "'Address' has a maximum length of 50 characters.")]
        public string SupplierAddress3 { get; set; }

        [StringLength(10, ErrorMessage = "'Post Code' has a maximum length of 50 characters.")]
        public string SupplierPostCode { get; set; }

        [EmailAddress]
        [StringLength(256, ErrorMessage = "'Email' has a maximum length of 256 characters.")]
        public string SupplierEmail { get; set; }

        [Required]
        public bool SupplierIsArchived { get; set; }

        public string CombinedAddress { get; }
    }
}

Product.cs

using System;
using System.ComponentModel.DataAnnotations;
// This is the model for one row in the database table. You may need to make some adjustments.
namespace BlazorPurchaseOrders.Data
{
    public class Product
    {
        [Required]
        public int ProductID { get; set; }

        [Required (ErrorMessage = "'Product Code' is required.")]
        [StringLength(25, ErrorMessage = "'Product Code' has a maximum length of 25 characters.")]
        public string ProductCode { get; set; }

        [Required (ErrorMessage = "'Description' is required.")]
        [StringLength(50, MinimumLength = 5, ErrorMessage = "'Description' has a minimum length of 5 and a maximum of 25 characters.")]
        public string ProductDescription { get; set; }

        [Required]
        public decimal ProductUnitPrice { get; set; }

        public int ProductSupplierID { get; set; }

        [Required]
        public bool ProductIsArchived { get; set; }

        public string SupplierName { get; }
    }
}

Pages

TaxPage.cs

@page "/tax"
@using BlazorPurchaseOrders.Data
@inject ITaxService TaxService
@using Syncfusion.Blazor.Navigations

<h3>Tax Rates</h3>
<br />

<SfGrid DataSource="@tax"
        Toolbar="@Toolbaritems">
    <GridColumns>
        <GridColumn Field="@nameof(Tax.TaxDescription)"
                    HeaderText="Description"
                    TextAlign="TextAlign.Left"
                    Width="60">
        </GridColumn>
        <GridColumn Field="@nameof(Tax.TaxRate)"
                    HeaderText="Rate %"
                    TextAlign="TextAlign.Right"                    
                   Format="p2"
                    Width="40">
        </GridColumn>
    </GridColumns>
    <GridEvents RowSelected="RowSelectHandler" OnToolbarClick="ToolbarClickHandler" TValue="Tax"></GridEvents>
</SfGrid>

<SfDialog @ref="DialogAddEditTax" IsModal="true" Width="500px" ShowCloseIcon="true" Visible="false">
    <DialogTemplates>
        <Header> @HeaderText </Header>
    </DialogTemplates>
    <EditForm Model="@addeditTax" OnValidSubmit="@TaxSave">
        <DataAnnotationsValidator />
        <div>
            <SfTextBox Enabled="true" Placeholder="Description"
                       FloatLabelType="@FloatLabelType.Always"
                       @bind-Value="addeditTax.TaxDescription"></SfTextBox>
            <ValidationMessage For="@(() => addeditTax.TaxDescription)" />
            <SfNumericTextBox Enabled="true" Placeholder="Tax Rate" Width="50"
                              Format="p2"                              
                              FloatLabelType="@FloatLabelType.Always"
                              @bind-Value="addeditTax.TaxRate"></SfNumericTextBox>
            
            <ValidationMessage For="@(() => addeditTax.TaxRate)" />
        </div>
        <br /><br />
        <div class="e-footer-content">
            <div class="button-container">
                <button type="button" class="e-btn e-normal" @onclick="@CloseDialog">Cancel</button>
                <button type="submit" class="e-btn e-normal e-primary">Save</button>
            </div>
        </div>
    </EditForm>
</SfDialog>

<SfDialog @ref="DialogDeleteTax" IsModal="true" Width="500px" ShowCloseIcon="true" Visible="false">
    <DialogTemplates>
        <Header> Confirm Delete </Header>
        <Content>
            <SfTextBox Enabled="false" Placeholder="Description"
                       FloatLabelType="@FloatLabelType.Always"
                       @bind-Value="addeditTax.TaxDescription"></SfTextBox>
            <SfNumericTextBox Enabled="false" Placeholder="Tax Rate" Width="50"
                              Format="p2"
                              FloatLabelType="@FloatLabelType.Always"
                              @bind-Value="addeditTax.TaxRate"></SfNumericTextBox>
            <br />
            <br />
            <span class="text-danger">Please confirm that you want to delete this record</span>
        </Content>
    </DialogTemplates>
    <DialogButtons>
        <DialogButton Content="Delete" IsPrimary="true" OnClick="@ConfirmDeleteYes" />
        <DialogButton Content="Cancel" IsPrimary="false" OnClick="@ConfirmDeleteNo" />
    </DialogButtons>
</SfDialog>

<WarningPage @ref="Warning" WarningHeaderMessage="@WarningHeaderMessage" WarningContentMessage="@WarningContentMessage" />

@code {

    IEnumerable<Tax> tax;
    private List<ItemModel> Toolbaritems = new List<ItemModel>();

    SfDialog DialogAddEditTax;
    Tax addeditTax = new Tax();
    string HeaderText = "";

    WarningPage Warning;
    string WarningHeaderMessage = "";
    string WarningContentMessage = "";

    public int SelectedTaxId { get; set; } = 0;

    SfDialog DialogDeleteTax;


    protected override async Task OnInitializedAsync()
    {
        //Populate the list of Tax objects from the Tax table.
        tax = await TaxService.TaxList();

        Toolbaritems.Add(new ItemModel() { Text = "Add", TooltipText = "Add a new Tax Rate", PrefixIcon = "e-add" });
        Toolbaritems.Add(new ItemModel() { Text = "Edit", TooltipText = "Edit selected Tax Rate", PrefixIcon = "e-edit" });
        Toolbaritems.Add(new ItemModel() { Text = "Delete", TooltipText = "Delete selected Tax Rate", PrefixIcon = "e-delete" });
    }

    public async Task ToolbarClickHandler(Syncfusion.Blazor.Navigations.ClickEventArgs args)
    {
        if (args.Item.Text == "Add")
        {
            //Code for adding goes here
            addeditTax = new Tax();             // Ensures a blank form when adding
            HeaderText = "Add Tax Rate";
            await this.DialogAddEditTax.Show();
        }
        if (args.Item.Text == "Edit")
        {
            //Code for editing goes here
            //Check that a Tax Rate has been selected
            if (SelectedTaxId == 0)
            {
                WarningHeaderMessage = "Warning!";
                WarningContentMessage = "Please select a Tax Rate from the grid.";
                Warning.OpenDialog();
            }
            else
            {
                //populate addeditTax (temporary data set used for the editing process)
                HeaderText = "Edit Tax Rate";
                addeditTax = await TaxService.Tax_GetOne(SelectedTaxId);
                await this.DialogAddEditTax.Show();
            }

        }
        if (args.Item.Text == "Delete")
        {
            //code for deleting goes here
            if (SelectedTaxId == 0)
            {
                WarningHeaderMessage = "Warning!";
                WarningContentMessage = "Please select a Tax Rate from the grid.";
                Warning.OpenDialog();
            }
            else
            {
                //populate addeditTax (temporary data set used for the editing process)
                HeaderText = "Delete Tax Rate";
                addeditTax = await TaxService.Tax_GetOne(SelectedTaxId);
                await this.DialogDeleteTax.Show();
            }
        }
    }

    protected async Task TaxSave()
    {
        if (addeditTax.TaxID == 0)
        {
            int Success = await TaxService.TaxInsert(addeditTax.TaxDescription, addeditTax.TaxRate);
            if (Success != 0)
            {
                //Tax Rate already exists
                WarningHeaderMessage = "Warning!";
                WarningContentMessage = "This Tax Description already exists; it cannot be added again.";
                Warning.OpenDialog();
                // Data is left in the dialog so the user can see the problem.
            }
            else
            {
                // Clears the dialog and is ready for another entry
                // User must specifically close or cancel the dialog
                addeditTax = new Tax();
            }
        }
        else
        {
            // Item is being edited
            int Success = await TaxService.TaxUpdate(addeditTax.TaxDescription, addeditTax.TaxRate, SelectedTaxId, addeditTax.TaxIsArchived);
            if (Success != 0)
            {
                //Tax Rate already exists
                WarningHeaderMessage = "Warning!";
                WarningContentMessage = "This Tax Description already exists; it cannot be added again.";
                Warning.OpenDialog();
            }
            else
            {
                await this.DialogAddEditTax.Hide();
                this.StateHasChanged();
                addeditTax = new Tax();
                SelectedTaxId = 0;
            }
        }

        //Always refresh datagrid
        tax = await TaxService.TaxList();
        StateHasChanged();
    }

    private async Task CloseDialog()
    {
        await this.DialogAddEditTax.Hide();
    }

    public void RowSelectHandler(RowSelectEventArgs<Tax> args)
    {
        //{args.Data} returns the current selected records.
        SelectedTaxId = args.Data.TaxID;
    }

    public async void ConfirmDeleteNo()
    {
        await DialogDeleteTax.Hide();
        SelectedTaxId = 0;
    }

    public async void ConfirmDeleteYes()
    {
        int Success = await TaxService.TaxUpdate(addeditTax.TaxDescription, addeditTax.TaxRate, SelectedTaxId, addeditTax.TaxIsArchived = true);
        if (Success != 0)
        {
            //Tax Rate already exists - THis should never happen when marking a record 'IsArchived'.
            WarningHeaderMessage = "Warning!";
            WarningContentMessage = "Unknown error has occurred - the record has not been deleted!";
            Warning.OpenDialog();
        }
        else
        {
            await this.DialogDeleteTax.Hide();
            tax = await TaxService.TaxList();
            this.StateHasChanged();
            addeditTax = new Tax();
            SelectedTaxId = 0;
        }
    }
}

SupplierPage.cs

@page "/supplier"
@using BlazorPurchaseOrders.Data
@inject ISupplierService SupplierService
@using Syncfusion.Blazor.Navigations

<h3>Suppliers</h3>
<br />

<SfGrid DataSource="@supplier"
        Toolbar="@Toolbaritems"
        AllowResizing="true">
    <GridColumns>
        <GridColumn Field="@nameof(Supplier.SupplierName)"
                    HeaderText="Name"
                    TextAlign="TextAlign.Left"
                    Width="40">
        </GridColumn>
        <GridColumn Field="@nameof(Supplier.CombinedAddress)"
                    HeaderText="Address"
                    TextAlign="TextAlign.Left"
                    Width="60">
        </GridColumn>
        <GridColumn Field="@nameof(Supplier.SupplierEmail)"
                    HeaderText="Email"
                    TextAlign="TextAlign.Left"
                    Width="40">
        </GridColumn>
    </GridColumns>
    <GridEvents RowSelected="RowSelectHandler" OnToolbarClick="ToolbarClickHandler" TValue="Supplier"></GridEvents>
</SfGrid>

<SfDialog @ref="DialogAddEditSupplier" IsModal="true" Width="500px" ShowCloseIcon="true" Visible="false">
    <DialogTemplates>
        <Header> @HeaderText </Header>
    </DialogTemplates>
    <EditForm Model="@addeditSupplier" OnValidSubmit="@SupplierSave">
        <DataAnnotationsValidator />
        <div>
            <SfTextBox Enabled="true" Placeholder="Supplier Name"
                       FloatLabelType="@FloatLabelType.Auto"
                       @bind-Value="addeditSupplier.SupplierName"></SfTextBox>
            <ValidationMessage For="@(() => addeditSupplier.SupplierName)" />
            <SfTextBox Enabled="true" Placeholder="Address"
                       FloatLabelType="@FloatLabelType.Auto"
                       @bind-Value="addeditSupplier.SupplierAddress1"></SfTextBox>
            <ValidationMessage For="@(() => addeditSupplier.SupplierAddress1)" />
            <SfTextBox Enabled="true" Placeholder=""
                       FloatLabelType="@FloatLabelType.Never"
                       @bind-Value="addeditSupplier.SupplierAddress2"></SfTextBox>
            <ValidationMessage For="@(() => addeditSupplier.SupplierAddress2)" />
            <SfTextBox Enabled="true" Placeholder=""
                       FloatLabelType="@FloatLabelType.Never"
                       @bind-Value="addeditSupplier.SupplierAddress3"></SfTextBox>
            <ValidationMessage For="@(() => addeditSupplier.SupplierAddress3)" />
            <SfTextBox Enabled="true" Placeholder="Post Code"
                       FloatLabelType="@FloatLabelType.Auto"
                       CssClass="ToUpperCase"
                       @bind-Value="addeditSupplier.SupplierPostCode"></SfTextBox>
            <ValidationMessage For="@(() => addeditSupplier.SupplierPostCode)" />
            <SfTextBox Enabled="true" Placeholder="Email"
                       FloatLabelType="@FloatLabelType.Auto"
                       @bind-Value="addeditSupplier.SupplierEmail"></SfTextBox>
            <ValidationMessage For="@(() => addeditSupplier.SupplierEmail)" />
        </div>
        <br /><br />
        <div class="e-footer-content">
            <div class="button-container">
                <button type="button" class="e-btn e-normal" @onclick="@CloseDialog">Cancel</button>
                <button type="submit" class="e-btn e-normal e-primary">Save</button>
            </div>
        </div>
    </EditForm>
</SfDialog>

<SfDialog @ref="DialogDeleteSupplier" IsModal="true" Width="500px" ShowCloseIcon="true" Visible="false">
    <DialogTemplates>
        <Header> Confirm Delete </Header>
        <Content>
            <SfTextBox Enabled="false" Placeholder="Supplier Name"
                       FloatLabelType="@FloatLabelType.Auto"
                       @bind-Value="addeditSupplier.SupplierName"></SfTextBox>
            <SfTextBox Enabled="false" Placeholder="Address"
                       FloatLabelType="@FloatLabelType.Auto"
                       @bind-Value="addeditSupplier.SupplierAddress1"></SfTextBox>
            <SfTextBox Enabled="false" Placeholder="Address"
                       FloatLabelType="@FloatLabelType.Never"
                       @bind-Value="addeditSupplier.SupplierAddress2"></SfTextBox>
            <SfTextBox Enabled="false" Placeholder="Address"
                       FloatLabelType="@FloatLabelType.Never"
                       @bind-Value="addeditSupplier.SupplierAddress3"></SfTextBox>
            <SfTextBox Enabled="false" Placeholder="Post Code"
                       FloatLabelType="@FloatLabelType.Auto"
                       @bind-Value="addeditSupplier.SupplierAddress3"></SfTextBox>
            <SfTextBox Enabled="false" Placeholder="Email"
                       FloatLabelType="@FloatLabelType.Auto"
                       @bind-Value="addeditSupplier.SupplierEmail"></SfTextBox>
            <br />
            <br />
            <span class="text-danger">Please confirm that you want to delete this record</span>
        </Content>
    </DialogTemplates>
    <DialogButtons>
        <DialogButton Content="Delete" IsPrimary="true" OnClick="@ConfirmDeleteYes" />
        <DialogButton Content="Cancel" IsPrimary="false" OnClick="@ConfirmDeleteNo" />
    </DialogButtons>
</SfDialog>

<WarningPage @ref="Warning" WarningHeaderMessage="@WarningHeaderMessage" WarningContentMessage="@WarningContentMessage" />

<style>
    .e-control-wrapper.ToUpperCase .e-textbox {
        text-transform: uppercase;
    }
</style>

@code {

    IEnumerable<Supplier> supplier;
    private List<ItemModel> Toolbaritems = new List<ItemModel>();

    SfDialog DialogAddEditSupplier;
    Supplier addeditSupplier = new Supplier();
    string HeaderText = "";

    WarningPage Warning;
    string WarningHeaderMessage = "";
    string WarningContentMessage = "";

    public int SelectedSupplierId { get; set; } = 0;

    SfDialog DialogDeleteSupplier;


    protected override async Task OnInitializedAsync()
    {
        //Populate the list of Supplier objects from the Supplier table.
        supplier = await SupplierService.SupplierList();

        Toolbaritems.Add(new ItemModel() { Text = "Add", TooltipText = "Add a new Supplier", PrefixIcon = "e-add" });
        Toolbaritems.Add(new ItemModel() { Text = "Edit", TooltipText = "Edit selected Supplier", PrefixIcon = "e-edit" });
        Toolbaritems.Add(new ItemModel() { Text = "Delete", TooltipText = "Delete selected Supplier", PrefixIcon = "e-delete" });
    }

    public async Task ToolbarClickHandler(Syncfusion.Blazor.Navigations.ClickEventArgs args)
    {
        if (args.Item.Text == "Add")
        {
            //Code for adding goes here
            addeditSupplier = new Supplier();             // Ensures a blank form when adding
            HeaderText = "Add Supplier";
            await this.DialogAddEditSupplier.Show();
        }
        if (args.Item.Text == "Edit")
        {
            //Code for editing goes here
            //Check that a Supplier Rate has been selected
            if (SelectedSupplierId == 0)
            {
                WarningHeaderMessage = "Warning!";
                WarningContentMessage = "Please select a Supplier from the grid.";
                Warning.OpenDialog();
            }
            else
            {
                //populate addeditSupplier (temporary data set used for the editing process)
                HeaderText = "Edit Supplier";
                addeditSupplier = await SupplierService.Supplier_GetOne(SelectedSupplierId);
                await this.DialogAddEditSupplier.Show();
            }

        }
        if (args.Item.Text == "Delete")
        {
            //code for deleting goes here
            if (SelectedSupplierId == 0)
            {
                WarningHeaderMessage = "Warning!";
                WarningContentMessage = "Please select a Supplier from the grid.";
                Warning.OpenDialog();
            }
            else
            {
                //populate addeditSupplier (temporary data set used for the editing process)
                HeaderText = "Delete Supplier";
                addeditSupplier = await SupplierService.Supplier_GetOne(SelectedSupplierId);
                await this.DialogDeleteSupplier.Show();
            }
        }
    }

    protected async Task SupplierSave()
    {
        if (addeditSupplier.SupplierID == 0)
        {
            int Success = await SupplierService.SupplierInsert(addeditSupplier.SupplierName,
                addeditSupplier.SupplierAddress1,
                addeditSupplier.SupplierAddress2,
                addeditSupplier.SupplierAddress3,
                addeditSupplier.SupplierPostCode,
                addeditSupplier.SupplierEmail
                );
            if (Success != 0)
            {
                //Supplier Rate already exists
                WarningHeaderMessage = "Warning!";
                WarningContentMessage = "This Supplier Description already exists; it cannot be added again.";
                Warning.OpenDialog();
                // Data is left in the dialog so the user can see the problem.
            }
            else
            {
                // Clears the dialog and is ready for another entry
                // User must specifically close or cancel the dialog
                addeditSupplier = new Supplier();
            }
        }
        else
        {
            // Item is being edited
            int Success = await SupplierService.SupplierUpdate(
                SelectedSupplierId,
                addeditSupplier.SupplierName,
                addeditSupplier.SupplierAddress1,
                addeditSupplier.SupplierAddress2,
                addeditSupplier.SupplierAddress3,
                addeditSupplier.SupplierPostCode,
                addeditSupplier.SupplierEmail,
                addeditSupplier.SupplierIsArchived);
            if (Success != 0)
            {
                //Supplier Rate already exists
                WarningHeaderMessage = "Warning!";
                WarningContentMessage = "This Supplier already exists; it cannot be added again.";
                Warning.OpenDialog();
            }
            else
            {
                await this.DialogAddEditSupplier.Hide();
                this.StateHasChanged();
                addeditSupplier = new Supplier();
                SelectedSupplierId = 0;
            }
        }

        //Always refresh datagrid
        supplier = await SupplierService.SupplierList();
        StateHasChanged();
    }

    private async Task CloseDialog()
    {
        await this.DialogAddEditSupplier.Hide();
    }

    public void RowSelectHandler(RowSelectEventArgs<Supplier> args)
    {
        //{args.Data} returns the current selected records.
        SelectedSupplierId = args.Data.SupplierID;
    }

    public async void ConfirmDeleteNo()
    {
        await DialogDeleteSupplier.Hide();
        SelectedSupplierId = 0;
    }

    public async void ConfirmDeleteYes()
    {
        int Success = await SupplierService.SupplierUpdate(

            SelectedSupplierId,
                addeditSupplier.SupplierName,
                addeditSupplier.SupplierAddress1,
                addeditSupplier.SupplierAddress2,
                addeditSupplier.SupplierAddress3,
                addeditSupplier.SupplierPostCode,
                addeditSupplier.SupplierEmail,
                addeditSupplier.SupplierIsArchived = true);
        if (Success != 0)
        {
            //Supplier Rate already exists - THis should never happen when marking a record 'IsArchived'.
            WarningHeaderMessage = "Warning!";
            WarningContentMessage = "Unknown error has occurred - the record has not been deleted!";
            Warning.OpenDialog();
        }
        else
        {
            await this.DialogDeleteSupplier.Hide();
            supplier = await SupplierService.SupplierList();
            this.StateHasChanged();
            addeditSupplier = new Supplier();
            SelectedSupplierId = 0;
        }
    }
}

ProductPage.cs

@page "/product"
@using BlazorPurchaseOrders.Data
@inject IProductService ProductService
@inject ISupplierService SupplierService


<h3>Products</h3>
<br />

<SfGrid DataSource="@product"
        Toolbar="@Toolbaritems"
        AllowResizing="true">
    <GridColumns>
        <GridColumn Field="@nameof(Product.ProductCode)"
                    HeaderText="Code"
                    TextAlign="TextAlign.Left"
                    Width="40">
        </GridColumn>
        <GridColumn Field="@nameof(Product.ProductDescription)"
                    HeaderText="Description"
                    TextAlign="TextAlign.Left"
                    Width="60">
        </GridColumn>
        <GridColumn Field="@nameof(Product.ProductUnitPrice)"
                    HeaderText="Unit Price"
                    TextAlign="TextAlign.Right"
                    Format="C2"
                    Width="40">
        </GridColumn>
        <GridColumn Field="@nameof(Product.SupplierName)"
                    HeaderText="Supplier"
                    TextAlign="TextAlign.Left"
                    Width="60">
        </GridColumn>
    </GridColumns>
    <GridEvents RowSelected="RowSelectHandler" OnToolbarClick="ToolbarClickHandler" TValue="Product"></GridEvents>
</SfGrid>

<SfDialog @ref="DialogAddEditProduct" IsModal="true" Width="500px" ShowCloseIcon="true" Visible="false">
    <DialogTemplates>
        <Header> @HeaderText </Header>
    </DialogTemplates>
    <EditForm Model="@addeditProduct" OnValidSubmit="@ProductSave">
        <DataAnnotationsValidator />
        <div>
            <SfTextBox Enabled="true" Placeholder="Product Code"
                       FloatLabelType="@FloatLabelType.Auto"
                       @bind-Value="addeditProduct.ProductCode"></SfTextBox>
            <ValidationMessage For="@(() => addeditProduct.ProductCode)" />

            <SfTextBox Enabled="true" Placeholder="Description"
                       FloatLabelType="@FloatLabelType.Auto"
                       @bind-Value="addeditProduct.ProductDescription"></SfTextBox>
            <ValidationMessage For="@(() => addeditProduct.ProductDescription)" />

            <SfNumericTextBox Enabled="true" Placeholder="Unit Price"
                              FloatLabelType="@FloatLabelType.Auto"
                              ShowSpinButton=false
                              @bind-Value="addeditProduct.ProductUnitPrice"></SfNumericTextBox>

            <SfDropDownList DataSource="@supplier"
                            TItem="Supplier"
                            TValue="int"
                            Text="SupplierID"
                            @bind-Value="addeditProduct.ProductSupplierID"
                            FloatLabelType="@FloatLabelType.Auto"
                            Placeholder="Select a Supplier"
                            Enabled="true">
                <DropDownListFieldSettings Text="SupplierName" Value="SupplierID"></DropDownListFieldSettings>
            </SfDropDownList>
        </div>        
        <br /><br />
        <div class="e-footer-content">
            <div class="button-container">
                <button type="button" class="e-btn e-normal" @onclick="@CloseDialog">Cancel</button>
                <button type="submit" class="e-btn e-normal e-primary">Save</button>
            </div>
        </div>
    </EditForm>
</SfDialog>



<SfDialog @ref="DialogDeleteProduct" IsModal="true" Width="500px" ShowCloseIcon="true" Visible="false">
    <DialogTemplates>
        <Header> Confirm Delete </Header>
        <Content>
            <SfTextBox Enabled="false" Placeholder="Product Code"
                       FloatLabelType="@FloatLabelType.Auto"
                       @bind-Value="addeditProduct.ProductCode"></SfTextBox>
            <SfTextBox Enabled="false" Placeholder="Description"
                       FloatLabelType="@FloatLabelType.Auto"
                       @bind-Value="addeditProduct.ProductDescription"></SfTextBox>
            <SfNumericTextBox Enabled="false" Placeholder="Unit Price"
                              FloatLabelType="@FloatLabelType.Auto"
                              @bind-Value="addeditProduct.ProductUnitPrice"></SfNumericTextBox>
            <SfDropDownList DataSource="@supplier"
                            TItem="Supplier"
                            TValue="int"
                            Text="SupplierID"
                            @bind-Value="addeditProduct.ProductSupplierID"
                            FloatLabelType="@FloatLabelType.Auto"
                            Placeholder="Select a Supplier"
                            Enabled="false">
                <DropDownListFieldSettings Text="SupplierName" Value="SupplierID"></DropDownListFieldSettings>
            </SfDropDownList>
            <br />
            <br />
            <span class="text-danger">Please confirm that you want to delete this record</span>
        </Content>
    </DialogTemplates>
    <DialogButtons>
        <DialogButton Content="Delete" IsPrimary="true" OnClick="@ConfirmDeleteYes" />
        <DialogButton Content="Cancel" IsPrimary="false" OnClick="@ConfirmDeleteNo" />
    </DialogButtons>
</SfDialog>

<WarningPage @ref="Warning" WarningHeaderMessage="@WarningHeaderMessage" WarningContentMessage="@WarningContentMessage" />

<style>
    .e-control-wrapper.ToUpperCase .e-textbox {
        text-transform: uppercase;
    }
</style>

@code {

    IEnumerable<Product> product;
    IEnumerable<Supplier> supplier;
    private List<ItemModel> Toolbaritems = new List<ItemModel>();

    SfDialog DialogAddEditProduct;
    Product addeditProduct = new Product();
    string HeaderText = "";

    WarningPage Warning;
    string WarningHeaderMessage = "";
    string WarningContentMessage = "";

    public int SelectedProductId { get; set; } = 0;

    SfDialog DialogDeleteProduct;


    protected override async Task OnInitializedAsync()
    {
        //Populate the list of Product objects from the Product table.
        product = await ProductService.ProductList();
        supplier = await SupplierService.SupplierList();

        Toolbaritems.Add(new ItemModel() { Text = "Add", TooltipText = "Add a new Product", PrefixIcon = "e-add" });
        Toolbaritems.Add(new ItemModel() { Text = "Edit", TooltipText = "Edit selected Product", PrefixIcon = "e-edit" });
        Toolbaritems.Add(new ItemModel() { Text = "Delete", TooltipText = "Delete selected Product", PrefixIcon = "e-delete" });
    }

    public async Task ToolbarClickHandler(Syncfusion.Blazor.Navigations.ClickEventArgs args)
    {
        if (args.Item.Text == "Add")
        {
            //Code for adding goes here
            addeditProduct = new Product();             // Ensures a blank form when adding
            HeaderText = "Add Product";
            await this.DialogAddEditProduct.Show();
        }
        if (args.Item.Text == "Edit")
        {
            //Code for editing goes here
            //Check that a Product Rate has been selected
            if (SelectedProductId == 0)
            {
                WarningHeaderMessage = "Warning!";
                WarningContentMessage = "Please select a Product from the grid.";
                Warning.OpenDialog();
            }
            else
            {
                //populate addeditProduct (temporary data set used for the editing process)
                HeaderText = "Edit Product";
                addeditProduct = await ProductService.Product_GetOne(SelectedProductId);
                await this.DialogAddEditProduct.Show();
            }

        }
        if (args.Item.Text == "Delete")
        {
            //code for deleting goes here
            if (SelectedProductId == 0)
            {
                WarningHeaderMessage = "Warning!";
                WarningContentMessage = "Please select a Product from the grid.";
                Warning.OpenDialog();
            }
            else
            {
                //populate addeditProduct (temporary data set used for the editing process)
                HeaderText = "Delete Product";
                addeditProduct = await ProductService.Product_GetOne(SelectedProductId);
                await this.DialogDeleteProduct.Show();
            }
        }
    }

    protected async Task ProductSave()
    {
        if (addeditProduct.ProductID == 0)
        {
            int Success = await ProductService.ProductInsert(
                addeditProduct.ProductCode,
                addeditProduct.ProductDescription,
                addeditProduct.ProductUnitPrice,
                addeditProduct.ProductSupplierID
                );
            if (Success != 0)
            {
                //Product Rate already exists
                WarningHeaderMessage = "Warning!";
                WarningContentMessage = "This Product Description already exists; it cannot be added again.";
                Warning.OpenDialog();
                // Data is left in the dialog so the user can see the problem.
            }
            else
            {
                // Clears the dialog and is ready for another entry
                // User must specifically close or cancel the dialog
                addeditProduct = new Product();
            }
        }
        else
        {
            // Item is being edited
            int Success = await ProductService.ProductUpdate(
                SelectedProductId,
                addeditProduct.ProductCode,
                addeditProduct.ProductDescription,
                addeditProduct.ProductUnitPrice,
                addeditProduct.ProductSupplierID,
                addeditProduct.ProductIsArchived);
            if (Success != 0)
            {
                //Product Rate already exists
                WarningHeaderMessage = "Warning!";
                WarningContentMessage = "This Product already exists; it cannot be added again.";
                Warning.OpenDialog();
            }
            else
            {
                await this.DialogAddEditProduct.Hide();
                this.StateHasChanged();
                addeditProduct = new Product();
                SelectedProductId = 0;
            }
        }

        //Always refresh datagrid
        product = await ProductService.ProductList();
        StateHasChanged();
    }

    private async Task CloseDialog()
    {
        await this.DialogAddEditProduct.Hide();
    }

    public void RowSelectHandler(RowSelectEventArgs<Product> args)
    {
        //{args.Data} returns the current selected records.
        SelectedProductId = args.Data.ProductID;
    }

    public async void ConfirmDeleteNo()
    {
        await DialogDeleteProduct.Hide();
        SelectedProductId = 0;
    }

    public async void ConfirmDeleteYes()
    {
        int Success = await ProductService.ProductUpdate(
            SelectedProductId,
            addeditProduct.ProductCode,
            addeditProduct.ProductDescription,
            addeditProduct.ProductUnitPrice,
            addeditProduct.ProductSupplierID,
            addeditProduct.ProductIsArchived = true);
        if (Success != 0)
        {
            //Product Rate already exists - THis should never happen when marking a record 'IsArchived'.
            WarningHeaderMessage = "Warning!";
            WarningContentMessage = "Unknown error has occurred - the record has not been deleted!";
            Warning.OpenDialog();
        }
        else
        {
            await this.DialogDeleteProduct.Hide();
            product = await ProductService.ProductList();
            this.StateHasChanged();
            addeditProduct = new Product();
            SelectedProductId = 0;
        }
    }
}