【问题标题】:Blazor, cancelling a two way bindBlazor,取消双向绑定
【发布时间】:2022-11-07 16:14:12
【问题描述】:

刚刚开始了解 Blazor 并试图找出两种方式绑定。

我正在尝试创建一个内联可编辑网格。我有一组项目,并使用 foreach 来显示行。大多数行都有编辑/删除按钮,正在编辑的行有更新/取消按钮。

我在编辑行中的输入上使用@bind 属性,但是当输入失去焦点并且我希望能够取消并恢复该更改时,它们会更新项目实例。是否有内置方法可以做到这一点,或者我是否需要在编辑时显式存储旧值,然后在取消时手动恢复它们?

@page "/inlineeditingsample"

<PageTitle>Inline Editing Sample</PageTitle>

<h1>Inline Editing Sample</h1>

@if (_items == null)
{
    <p><em>Loading...</em></p>
}
else
{
    <table class="table">
        <thead>
            <tr>
                <th>ID</th>
                <th>Title</th>
                <th>Description</th>
                <th></th>
            </tr>
        </thead>
        <tbody>
            @foreach (var item in _items)
            {
                var link = $"TableSampleDetails/{@item.ID}";
                <tr>
                    @if (item == _editItem)
                    {
                        <td>
                        @item.ID
                        </td>
                        <td><input type="text" class="form-control" @bind="@item.Title"/></td>
                        <td><input type="text" class="form-control" @bind="@item.Description" /></td>
                        <td>
                            <button type="button" class="btn btn-link" @onclick="() => Cancel(item)">Cancel</button>
                            <button type="button" class="btn btn-link" @onclick="() => Save(item)">Save</button>
                        </td>
                    }
                    else
                    {
                        <td>
                            <NavLink href="@link">@item.ID</NavLink>
                        </td>
                        <td>@item.Title</td>
                        <td>@item.Description</td>
                        <td>
                            <button type="button" class="btn btn-link" @onclick="() => Edit(item)">Edit</button>
                            <button type="button" class="btn btn-link" @onclick="() => Delete(item)">Delete</button>
                        </td>
                    }
                </tr>
            }
        </tbody>
    </table>
}

@code {
    private DAL.SampleObject? _editItem;
    private List<DAL.SampleObject> _items;

    private DAL.SampleDal _dal = new DAL.SampleDal();


    private void Edit(DAL.SampleObject item)
    {
        _editItem = item;
    }

    private void Save(DAL.SampleObject item)
    {
        _editItem = null;

        //call the repository to update the instance here.
        //show toast after done.
    }

    private void Delete(DAL.SampleObject item)
    {
        _editItem = null;

        //call the repository to delete the instance here.
        //show toast after done.
        _items.Remove(item);
    }

    private void Cancel(DAL.SampleObject item)
    {
        _editItem = null;   
    }

    protected override async Task OnInitializedAsync()
    {
        var items = await _dal.ListObjectsAsync(0, int.MaxValue);
        _items = items.ToList();
    }
}

【问题讨论】:

  • Mudblazor TableGrid 有一个简单的解决方案,提供单独的对象上下文模型和事件来管理这个场景
  • 使用组件来管理这意味着您不必为非常常见的需求滚动自己的逻辑和 html

标签: blazor blazor-server-side


【解决方案1】:

保持相同的方法

如果不注入数据库上下文(工厂),您可能会成功单程数据绑定和使用“改变" 仅当您保存更改时。这样不会将任何内容写回父组件。

您可能会发现使用像 MudBlazor 这样的 UI 框架更容易(如果您像我一样懒惰的话),或者创建一个自定义“行”组件,如果您不想处理一个单元格,您可以在其中传递要编辑的整个项目一次。

要在新的自定义行上启用具有可调用返回的 2 路和 1 路,只需添加:

[Parameter] public Item Value { get; set; }
[Parameter] public EventCallback<Item> ValueChanged { get; set; }

这里有一点魔力(如果你调用参数“价值", EventCallback 必须命名为 "价值改变“;”物品“与”一起项目已更改" 等等..) 现在无论您在哪里使用这个新的自定义行组件,您都可以使用:

<CustomRow @bind-Value="item" />

或(“e”的类型是“Item”而不是“ChangeEventArgs”,这对我来说感觉更干净),只有当用户实际点击自定义行内的按钮时,您才能调用保存更改:

<CustomRow Value="item" ValueChanged="(e) => SaveChanges(e)" />

不同的方法

如果你正在开发服务器端,并且正在使用数据库上下文在您的 UI 中,您可以使用:

dbContext.Entry(item).State = EntityState.Unchanged;

这实际上将 2-way 绑定项目恢复为原始值,在取消表单等时非常方便。

【讨论】:

    【解决方案2】:

    没有本地人布雷泽基于此的解决方案,布雷泽在这方面与其他框架没有什么不同。无论您使用 Blazor、UWP、WPF、React、Angular、Vue...,问题和解决方案都是相同的。

    绑定只是写入绑定的属性查看模型,由你来设计你的模型来处理这个问题。支持背后有两个基本范式撤消数据应用中的逻辑。

    1. 您存储原来的或者以前的对象的状态,通常是克隆从提供数据的时间开始。然后,当您需要回滚时,使用来自或原始对象本身的值来替换当前的目的。
    2. 编辑操作在编辑期间在单独的对象实例中执行,然后当数据被持久化时,这些值被复制到原始对象中。

      对于这样一个常见的需求,我建议您使用组件库而不是尝试重新发明轮子你自己。我发现 MudBlazor 包实现起来非常简单,但有很多可供选择。

      你所描述的听起来像MudTable that has inline row level editing。您无需对模型进行任何更改即可使此简单行为起作用,它使用上面的第二个选项:

      在这里玩一下:https://try.mudblazor.com/snippet/waQQYtuDYpotsVyL


      您也可以直接在数据模型中进行管理。还有其他 3rd 方库可以在不同程度上提供此功能,您的数据访问层可能已经为此提供了通用支持。以实体框架为例,它能够在您将结果提交到底层数据库之前跟踪、检查和操作更改。

      您甚至可以自己滚动,我仍然在某些模型中使用拦截器模式,其中模型上每个属性的设置器写入复杂对象而不是简单的值类型支持字段,但在用户界面中管理此特定行为作为组件非常实用。

    【讨论】:

      猜你喜欢
      • 2020-03-26
      • 1970-01-01
      • 2023-02-24
      • 2019-10-01
      • 2021-07-29
      • 1970-01-01
      • 2020-01-15
      • 2021-02-25
      • 2019-01-15
      相关资源
      最近更新 更多