功能已执行,我不知道为什么

Function is executed and i dont know why

我是 blazor 的新手,有一个我不明白的问题。

我写了一个简单的测试应用程序,我可以在其中创建联系人、文章和发票。这行得通。在发票中,我可以通过打开模式和 select 一些文章来创建发票行项目,然后获得新的发票行项目。

现在我有两个 problems/questions:

  1. 当我删除最后一个发票行项目时它有效,但是当我删除另一个而不是最后一个项目时,函数 SaveInvoice 被执行。
  2. 如果我将模式代码放在 <Editform> 标签内,函数 SaveInvoice 也会被执行。如果我将模式放在 <Editform> 标签之外,它会按预期工作,但我想将它放在表单内。

为什么没有显式调用就执行了这段代码?我想有某种隐式调用,但我不明白它来自哪里。

你能帮我或给我提示吗?或者您需要更多信息?

发票表单调用代码:

@page "/invoice/edit/{rechnungID:int}"
@inject NavigationManager navMan
@inject IJSRuntime js
@inject IInvoiceRepository invoiceRepository
@inject IArticleRepository articleRepository

<h3>Rechnung bearbeiten</h3>

<FormInvoice ButtonText="Aktualisieren" Artikel="@Artikel" Rechnung="@Rechnung" Positionen="@Positionen" OnValidSubmit="@SaveInvoice" EditMode="true" OnCancel="@Cancel" OnRemoveItem="@RemoveItem" />


@code {
    [Parameter] public int rechnungID { get; set; }
    Rechnung Rechnung = new Rechnung();
    List<Rechnungsposition> Positionen { get; set; } = new List<Rechnungsposition>();
    List<Artikel> Artikel { get; set; } = new List<Artikel>();

    protected async override Task OnInitializedAsync()
    {
        Rechnung = await invoiceRepository.GetInvoiceByID(rechnungID);
        Positionen = Rechnung.Positionen;
        Artikel = await articleRepository.GetArticles();
    }

    async Task SaveInvoice() // This gets executed and i dont know why
    {
        await invoiceRepository.UpdateInvoice(Rechnung);
        await js.InvokeVoidAsync("alert", $"Erfolgreich aktualisiert!");
        navMan.NavigateTo("invoice");
    }

    void Cancel() => navMan.NavigateTo("invoice");

    private void RemoveItem(Rechnungsposition pos)
    {
        Positionen.Remove(pos);
    }
}

发票表格代码:

@inject IModalService Modal
@inject IArticleRepository articleRepository
@inject IInvoiceRepository invoiceRepository
@inject IInvoiceLineItemRepository itemsRepository


<EditForm Model="@Rechnung" OnValidSubmit="@OnValidSubmit">
    <DataAnnotationsValidator />
    <div class="form-group row">
        <label class="col-sm-1 col-form-label" for="inputReNr">Rechnungsnr:</label>
        <div class="col-sm-2">
            @if (EditMode)
            {
                <InputText id="inputReNr" class="form-control-plaintext" @bind-Value="@Rechnung.RechnungsNr" readonly />
            }
            else
            {
                <InputText id="inputReNr" class="form-control" @bind-Value="@Rechnung.RechnungsNr" />
                @*<ValidationMessage For="@(() => Rechnung.RechnungsNr)" />*@
            }
        </div>
        <label class="col-sm-1 col-form-label" for="inputReDatum">Datum:</label>
        <div class="col-sm-2">
            <InputDate id="inputReDatum" class="form-control" @bind-Value="@Rechnung.RechnungsDatum" />
            <ValidationMessage For="@(() => Rechnung.RechnungsDatum)" />
        </div>
    </div>

    <div class="form-group row">
        <label class="col-sm-1 col-form-label" for="inputAdresse">Adresse:</label>
        <div class="col-sm-5">
            <InputTextArea id="inputAdresse" class="form-control" @bind-Value="@Rechnung.Adresse" />
            <ValidationMessage For="@(() => Rechnung.Adresse)" />
        </div>
    </div>


    <SelectedInvoiceLineItems Positionen="@Positionen" OnRemoveItem=@RemoveItem />

    <div class="form-group row">
        <label>Nettosumme</label>
        <label>@Rechnung.NettoSumme</label>
    </div>
    <div class="form-group row">
        <label>zzgl USt</label>
        <label>@Rechnung.UStSumme</label>
    </div>
    <div class="form-group row">
        <label>Bruttosumme</label>
        <label>@Rechnung.BruttoSumme</label>
    </div>
</EditForm>

@*When the modal is here the SaveInvoice-function is not exceuted, but when i place it inside <EditForm> it gets executed*@
@if (EditMode)
{
    <button @onclick="ShowModal" class="bg-gray-100 hover:bg-blue-200 text-gray-800 font-semibold py-2 px-4 border border-gray-400 rounded shadow">Neue Position</button>
}

<div class="form-group row">
    <button class="btn btn-success mr-2" @onclick="@OnValidSubmit">
        @ButtonText
    </button>
    <button class="btn btn-secondary" @onclick="@OnCancel">Abbrechen</button>
</div>


@code {
    int RechnungID { get; set; }
    [Parameter] public Kontakt Kontakt { get; set; }
    [Parameter] public Rechnung Rechnung { get; set; }
    [Parameter] public List<Artikel> Artikel { get; set; } = new List<Artikel>();
    [Parameter] public List<Rechnungsposition> Positionen { get; set; } = new List<Rechnungsposition>();
    [Parameter] public string ButtonText { get; set; } = "Speichern";
    [Parameter] public EventCallback OnValidSubmit { get; set; }
    [Parameter] public EventCallback OnCancel { get; set; }
    [Parameter] public EventCallback<Rechnungsposition> OnRemoveItem { get; set; }
    [Parameter] public bool EditMode { get; set; }

    protected override void OnInitialized()
    {
        if (!EditMode)
        {
            Rechnung = new Rechnung();
        }
        else
        {
            RechnungID = Rechnung.ID;
        }
    }

    protected override void OnParametersSet()
    {
        if (!EditMode)
        {
            Rechnung.Adresse = Kontakt.Name;
            Rechnung.KontaktID = Kontakt.ID;
            Rechnung.IstBezahlt = false;
        }
    }

    async Task ShowModal()
    {
        var parameters = new ModalParameters();
        parameters.Add(nameof(SelectArticle.Artikel), Artikel);
        parameters.Add(nameof(SelectArticle.RechnungID), Rechnung.ID);
        parameters.Add(nameof(SelectArticle.Positionen), Positionen);
        var options = new ModalOptions()
        {
            DisableBackgroundCancel = true,
            HideCloseButton = true
        };
        var messageForm = Modal.Show<SelectArticle>("Artikel auswählen", parameters, options);
        var result = await messageForm.Result;

        if (result.Cancelled)
        {
            //Console.WriteLine("Modal was cancelled");
        }
        else
        {
            //Console.WriteLine($"Anzahl Positionen nach Modal: {Positionen.Count}");
        }

    }

    private async Task RemoveItem(Rechnungsposition pos)
    {
        await OnRemoveItem.InvokeAsync(pos);
    }
}

显示发票行项目和删除可能性的代码:

<div>
    <table class="table table-striped">
        <thead>
            <tr>
                <th>ID</th>
                <th>Bezeichnung</th>
                <th>Anzahl</th>
                <th>Stückpreis</th>
                <th>Gesamtpreis</th>
                <th></th>
            </tr>
        </thead>
        <tbody>
            @foreach (var pos in Positionen)
            {
                <tr>
                    <td>@pos.ID</td>
                    <td>@pos.Bezeichnung</td>
                    <td>@pos.Anzahl</td>
                    <td>@pos.Stueckpreis</td>
                    <td>@pos.Gesamtpreis</td>
                    <td>
                        <a class="btn btn-success" href="/invoicelineitem/edit/@pos.ID">Bearbeiten</a>
                        <button class="btn btn-danger" @onclick="@(() => RemoveItem(pos))">Löschen</button>
                    </td>
                </tr>
            }

        </tbody>
    </table>
</div>

@code {
    [Parameter] public List<Rechnungsposition> Positionen { get; set; } = new List<Rechnungsposition>();
    [Parameter] public EventCallback<Rechnungsposition> OnRemoveItem { get; set; }

    private async Task RemoveItem(Rechnungsposition pos)
    {
        await OnRemoveItem.InvokeAsync(pos);
    }
}

模态代码:

@if (Artikel == null)
{
    <text>Lade Daten...</text>
}
else if (Artikel.Count == 0)
{
    <text>Keine Daten gefunden.</text>
}
else
{
    <table class="table table-sm table-hover table-bordered">
        <thead>
            <tr>
                <th scope="col"></th>
                <th scope="col">Bezeichnung</th>
                <th scope="col">Einheit</th>
                <th scope="col">Stückkosten</th>
                <th scope="col"></th>
            </tr>
        </thead>
        <tbody>
            @foreach (Artikel art in Artikel)
            {
                <tr>
                    <td scope="row"><Input type="checkbox" @onchange="eventArgs => { ArtikelClicked(art, eventArgs.Value); }" /></td>
                    <td scope="row">@art.Bezeichnung</td>
                    <td scope="row">@art.Einheit</td>
                    <td scope="row">@art.Stueckkosten</td>
                </tr>
            }

        </tbody>
    </table>

    <button @onclick="@Anlegen" class="btn btn-primary">Anlegen</button>
    <button @onclick="@Cancel" class="btn btn-secondary">Abbrechen</button>
}

@code 
{
    [CascadingParameter] BlazoredModalInstance BlazoredModal { get; set; }
    [Parameter] public List<Artikel> Artikel { get; set; }
    [Parameter] public int RechnungID { get; set; }
    private List<Artikel> ArtikelAuswahl = new List<Artikel>();
    [Parameter] public List<Rechnungsposition> Positionen { get; set; }


    void ArtikelClicked(Artikel artikel, object checkedValue)
    {
        if ((bool)checkedValue)
        {
            if (!ArtikelAuswahl.Contains(artikel))
            {
                ArtikelAuswahl.Add(artikel);

            }
        }
        else
        {
            if (ArtikelAuswahl.Contains(artikel))
            {
                ArtikelAuswahl.Remove(artikel);
            }
        }

    }

    void Anlegen()
    {
        Rechnungsposition position;
        for (int i = 0; i < ArtikelAuswahl.Count; i++)
        {
            position = new Rechnungsposition();
            position.ID = 0;
            position.RechnungID = RechnungID;
            position.ArtikelID = ArtikelAuswahl[i].ID;
            position.Anzahl = 1;
            position.Beschreibung = ArtikelAuswahl[i].Beschreibung;
            position.Bezeichnung = ArtikelAuswahl[i].Bezeichnung;
            position.Einheit = ArtikelAuswahl[i].Einheit;
            position.Stueckpreis = ArtikelAuswahl[i].Stueckkosten;
            position.Gesamtpreis = ArtikelAuswahl[i].Stueckkosten;
            Positionen.Add(position);
        }

        BlazoredModal.Close(ModalResult.Ok(true));
    }

    void Cancel()
    {
        Console.WriteLine("Cancel");
        BlazoredModal.Cancel();
    }
}

将按钮类型设置为简单的“按钮”,默认通常是“提交”。

<button type="button" @onclick="ShowModal" ...>Neue Position</button>

来自w3schools

Tip: Always specify the type attribute for the element. Different browsers may use different default types for the element.