Voorbeeld van een MercatorPenguin customizer : verkopen en aankopen

0000003450     -      03-06-2026

Deze pagina toont een voorbeeld van een customizer voor het ingavescherm van een verkoop of een aankoop (Billing) in MercatorPenguin. Het is van toepassing op de verkopen. De broncode is beschikbaar in het onderstaande zip-bestand.

Deze customizer voegt een knop toe (PortButton) waarvan de code in het project opgenomen is. Het erft dus over van Microsoft.Maui.Controls.Button. Het laat toe om de vraag "Verzendkosten toevoegen" te stellen en een lijn toe te voegen aan de lopende verkoop met het artikel "verzendkosten" en het ingevoerde bedrag. Deze knop wordt geplaatst via een override van de methode OnInit.

Hieronder de code voor het toevoegen van een lijn aan de lopende verkoop:

Zoom
private async void PortButton_Clicked(object sender, EventArgs e)
{
    try
    {
        IsEnabled = false;
        DataRow drPort = customizer.Lignes.Rows.FirstOrDefault(dr => dr["id_article"].ToString() == ID_PORT);
        decimal currentPort = drPort != null ? Convert.ToDecimal(drPort["pu"]) : 0;
        decimal? pu = await Dialogs.AskDecimal(customizer.Page, "Welk bedrag voor de verzendkosten?", 2, currentPort);
        if (pu == null)
            return;

        if (drPort != null)
            customizer.Lignes.RemoveRow(drPort);

        drPort = customizer.Lignes.NewRow();
        drPort["id_article"] = ID_PORT;
        drPort["designatio"] = DESIGN_PORT;
        drPort["q"] = 1;
        drPort["pu"] = pu.Value;
        customizer.Lignes.AddRow(drPort);
    }
    finally
    {
        IsEnabled = true;
    }
}

 

De customizer laat ook toe om code uit te voeren na de selectie van de klant. Dit via de methode OnInsertingCustomerSupplier. In dit voorbeeld worden de volledige contactgegevens van de klant opgehaald, via een SQL-query doorgegeven via MercatorPenguinServer, om ze weer te geven in een dialoogvenster. De focus wordt ook geplaatst in het veld "Referentie".

Zoom
public override async Task OnInsertingCustomerSupplierAsync(InsertingCustomerSupplierEventArgs e)
{
    string id_cli = e.Tiers["id_cli"].ToString();
    ActivityIndicator.SetActive(true);
    var r = await GetRunSqlData<(string c_nom, string c_adresse, string c_codep, string c_ville)>("select c_nom, c_adresse, c_codep, c_ville from CLI where c_id = @id_cli", [new RunSqlDescriptor.Parameter("@id_cli", id_cli)]);
    ActivityIndicator.SetActive(false);
    if (r.Result == null)
    {
        await Dialogs.Stop(Page, "Fout bij het ophalen van de klantgegevens : " + r.Error);
        e.CancelInsertingCustomerSupplier = true;
        return;
    }
    if (r.Result.Count > 0)
    {
        IEntry editEntryReference = Controls.OfType<IEditEntry>().FirstOrDefault(c => c.Source?.Equals("reference", StringComparison.InvariantCultureIgnoreCase) ?? false);
        editEntryReference?.Focus();
        await Dialogs.Stop(Page, r.Result[0].c_nom + Environment.NewLine + r.Result[0].c_adresse + Environment.NewLine + r.Result[0].c_codep + " " + r.Result[0].c_ville);
    }
}

 

De methoden OnBeforeInsertItem en OnAfterInsertItem laten toe om code uit te voeren, respectievelijk vóór en na het invoegen van een artikel.

Zoom
public override async Task OnBeforeInsertItemAsync(BeforeInsertItemEventArgs e)
{
    await Dialogs.Stop(Page, $"U gaat een artikel zoeken op basis van \"{e.EntryArt.Text}\"!");
}

public override async Task OnAfterInsertItemAsync(AfterInsertItemEventArgs e)
{
    decimal? pu = await Dialogs.AskDecimal(Page, $"Welke prijs voor het artikel \"{e.Item["designatio"]}\"?", 2);
    if (pu == null)
    {
        e.CancelInsertItem = true;
        return;
    }
    e.Item["pu"] = pu.Value;
}

 

De volgende methoden worden uitgevoerd op deze momenten:

  • OnBeforeAddLine : vóór het toevoegen van een lijn,
  • OnAfterAddLine : na het toevoegen van een lijn,
  • OnAfterDeleteLine : na het verwijderen van een lijn,
  • OnBeforeChangeLine : vóór het wijzigen van een lijn.

 

Zoom
public override async Task OnBeforeAddLineAsync(BeforeAddLineEventArgs e)
{
    IEditEntry editEntryQ = Controls.OfType<IEditEntry>().FirstOrDefault(c => c.Source?.Equals("line|q", StringComparison.InvariantCultureIgnoreCase) ?? false);
    if (!await Dialogs.AnswerYesNo(Page, $"Wilt u echt een lijn toevoegen met het artikel \"{e.EntryArt.TargetSigLabel.Text}\" en Q = {editEntryQ.Text}?"))
    {
        e.CancelAddLine = true;
    }
}

public override async Task OnAfterAddLineAsync(AfterAddLineEventArgs e)
{
    await Dialogs.Stop(Page, $"Lijn nr. {e.Ligne.Table.Rows.Count} werd succesvol toegevoegd! Het bevat het artikel \"{e.Ligne["designatio"]}\".");
}
public override async Task OnBeforeDeleteLineAsync(BeforeDeleteLineEventArgs e)
{
	if (!await Dialogs.AnswerYesNo(Page, $"Wilt u deze lijn {e.Ligne["id_article"]} op deze picking echt verwijderen?"))
	{
		e.CancelDeleteLine = true;
	}
}

public override async void OnAfterDeleteLine(AfterDeleteLineEventArgs e)
{
	await Dialogs.Stop(Page, $"De lijn werd succesvol verwijderd!");
}

public override async Task OnBeforeChangeLineAsync(BeforeChangeLineEventArgs e)
{
	if (!await Dialogs.AnswerYesNo(Page, $"Wilt u de kolom {e.ColumnToChange} van deze lijn {e.Line["id_article"]} echt wijzigen met deze nieuwe waarde {e.NewValue}?"))
	{
		e.CancelChangeLine = true;
	}
}

 

De methode OnBeforeSave laat toe om de opslagaanvraag te onderscheppen.

Zoom
public override async Task OnBeforeSaveAsync(BeforeSaveEventArgs e)
{
    if (!await Dialogs.AnswerYesNo(Page, $"Wilt u de wijzigingen op {(BillingTypeVA == MercatorPenguin.Enums.TypeVAEnum.V ? "deze verkoop" : "deze aankoop")} echt opslaan?"))
    {
        e.CancelSave = true;
    }
}

 

Deze customizer toont ook hoe een via code aangemaakt besturingselement (RecentSales) toegevoegd kan worden. Dit toont een raster met de 10 laatste verkochte artikelen bij de klant van de lopende verkoop. Dit raster wordt gevuld bij de initialisatie van de verkoop en bij de wijziging van klant, via editEntryIdCli.AfterTargetSigSearchAsync. Dit raster wordt toegevoegd door de code van de methode OnInitAsync.

Zoom
public override async Task OnInitAsync(InitEventArgs e)
{
    VerticalStackLayout verticalStackLayout = ScrollView.Content as VerticalStackLayout;
    if (verticalStackLayout == null)
    {
        MercatorTunnel.PlatformMaui.Api.ShowToastLongBottom("Kan de VerticalStackLayout op de pagina niet vinden!");
    }
    else
    {
        PortButton portButton = new PortButton(this);
        verticalStackLayout.Children.Add(portButton);

        IEditEntry editEntryIdCli = Controls.OfType<IEditEntry>().FirstOrDefault(c => c.Source?.Equals("id_cli", StringComparison.InvariantCultureIgnoreCase) ?? false);
        if (editEntryIdCli == null)
        {
            MercatorTunnel.PlatformMaui.Api.ShowToastLongBottom("Kan het EditEntry van de klant niet vinden!");
        }
        else
        {
            RecentSales recentSales = new RecentSales(this, editEntryIdCli);
            verticalStackLayout.Children.Add(recentSales);
            await recentSales.Populate(true);
        }
    }
}


Te laden : 0000003450.zip (5 Kb - 13-05-2026)


Functionele cookies: Cookies die nodig zijn voor het gebruik van de website en voorkeurscookies. Ze bevatten geen persoonsgegevens. (Meer informatie)

Analytische cookies: Verzamelen van statistieken met betrekking tot het gedrag van internetgebruikers. (Meer informatie)

Marketingcookies: Om bezoekers op verschillende websites te volgen voor advertentiedoeleinden. (Meer informatie)