在上一篇 學習ASP.NET Core Blazor程式設計系列二十——檔案上傳(完) 文章中曾經談過檔案上傳功能遺留了二個問題。第一個問題我們已經在上一篇文章中解決了,第二個問題,就是資料重新整理問題,這不僅僅是上傳中會碰到,只要是用資料列表或表格呈現資料,都可能會碰到沒有及時重新整理,資料不是最新的這個問題。
十、重新整理資料
Blazor 繫結(繫結就是重新整理)機制有以下幾種
- 首次載入時的自動繫結
- 呼叫 StateHasChanged 強制重新繫結(重新繫結即重新整理)
- 註冊事件自動重新整理
Blazor元件在第一次渲染完成之後,ShouldRender 會返回為 false,然後後面呼叫都返回 false,對於任意一個元件,若出現沒重新整理的情況下,請考慮這個因素。
那麼,如何讓Blazor元件進行重新整理呢?方法很簡單,手動呼叫該元件的StateHasChanged 方法,然後繫結資料。
StateHasChanged 方法
這個方法至關重要,我們來看看這個方法裡面有什麼。如下圖。
資料重新整理的流程以上圖來講解,接下來,我們以具體的程式碼來實現此功能。
1. 在Visual Studio 2022中的解決方案資源管理器中使用滑鼠左鍵雙擊開啟UpFileInfoList.razor檔案。在@code程式碼塊中宣告一個事件。程式碼如下:
[Parameter]
public EventCallback RefterData { get; set; }
2.在Visual Studio 2022中的解決方案資源管理器中使用滑鼠左鍵雙擊開啟FileUpload1.razor檔案。在@code程式碼塊中用程式碼實現RefterData事件的一個方法 RefterDataHandler,並在UpFileInfoList元件中呼叫我們剛才寫的RefterDataHandler方法,在上傳方法中呼叫RefterDtaHandler方法 。程式碼如下:
@page "/FileUpload1"
@using BlazorAppDemo.Models
@using BlazorAppDemo.Utils
@using Microsoft.AspNetCore.Mvc.ModelBinding
@using Microsoft.EntityFrameworkCore
@inject IWebHostEnvironment Environ
@inject IDbContextFactory<BookContext> dbFactory
<h3>多檔案上傳示例</h3>
<p>
<label>
提示資訊:@Message
</label>
</p>
<p>
<label>
上傳檔案最大可以為:<input type="number" @bind="maxFileSize"/>位元組
</label>
</p>
<p>
<label>
一次可上傳:<input type="number" @bind="maxAllowedFiles" />個檔案
</label>
</p>
<p>
<label>
選擇上傳檔案:<InputFile OnChange="@LoadFiles" multiple />
</label>
<BlazorAppDemo.Pages.Descri.UpFileInfoList RefterData="RefterDataHandler" @ref="@upfileList"></BlazorAppDemo.Pages.Descri.UpFileInfoList>
</p>
@if (isLoading)
{
<p>檔案上傳中......</p>
}
else
{
<ul>
@foreach (var file in loadedFiles)
{
<li>
<ul>
<li>檔名:@file.Name</li>
<li>最後修改時間:@file.LastModified.ToString()</li>
<li>檔案大小(byte):@file.Size</li>
<li>檔案型別:@file.ContentType</li>
</ul>
</li>
}
</ul>
}
@code {
private List<IBrowserFile> loadedFiles = new();
private long maxFileSize = 1024 * 18;
private int maxAllowedFiles = 2;
private bool isLoading;
private string Message = string.Empty;
private BlazorAppDemo.Pages.Descri.UpFileInfoList upfileList;
private async Task LoadFiles(InputFileChangeEventArgs e)
{
isLoading = true;
loadedFiles.Clear();
foreach (var file in e.GetMultipleFiles(maxAllowedFiles))
{
try
{
ModelStateDictionary modelState = new ModelStateDictionary();
loadedFiles.Add(file);
FileHelpers.db = dbFactory.CreateDbContext();
string result= await FileHelpers.ProcessFormFile(file, modelState, Environ, maxFileSize);
if (string.IsNullOrEmpty(result))
{
Message = "上傳成功!";
RefterDataHandler();
}else
Message = "上傳失敗!";
}
catch (Exception ex)
{
Message = ex.Message;
}
}
isLoading = false;
}
public void RefterDataHandler()
{
StateHasChanged();
upfileList.BindData();
}
}
@page "/Descri/UpFileInfoList"
@using BlazorAppDemo.Models
@using BlazorAppDemo.Utils
@using Microsoft.EntityFrameworkCore
@inject IDbContextFactory<BookContext> dbFactory
@inject IJSRuntime JsRuntime
<h3>已上傳檔案列表</h3>
<table class="table" width="99%">
<thead>
<tr>
<th></th>
<th>
@HtmlHelper.GetDisplayName(fileDesc,m=>m.Name)
</th>
<th>
@HtmlHelper.GetDisplayName(fileDesc ,m=> m.NewName)
</th>
<th class="text-center">
@HtmlHelper.GetDisplayName(fileDesc ,m=>m.UploadDateTime)
</th>
<th class="text-center">
@HtmlHelper.GetDisplayName(fileDesc ,m=> m.FileSize)
</th>
</tr>
</thead>
<tbody>
@foreach (var item in fileDescs)
{
<tr>
<td>
<button id="delete" class="btn btn-primary" @onclick="@(async e => await ShowConfirmMsg(e, @item.ID))">刪除</button>
</td>
<td>
@item.Name
</td>
<td>
@item.NewName
</td>
<td class="text-center">
@item.UploadDateTime
</td>
<td class="text-center">
@item.FileSize
</td>
</tr>
}
</tbody>
</table>
@code {
private static BookContext _context;
private List<FileDescribe> fileDescs = new List<FileDescribe>();
private FileDescribe fileDesc = new FileDescribe();
[Parameter]
public EventCallback RefterData { get; set; }
protected override async Task OnInitializedAsync()
{
BindData();
await base.OnInitializedAsync();
}
public void BindData()
{
_context = dbFactory.CreateDbContext();
fileDescs = _context.FileDescribe.ToList();
}
public void DeleteFile(MouseEventArgs e, int Id)
{
List<int> listId = new();
listId.Add(Id);
int[] Ids= listId.ToArray();
var entity = _context.Find<FileDescribe>(Id);
_context.Remove<FileDescribe>(entity);
_context.SaveChangesAsync();
}
public async Task ShowConfirmMsg(MouseEventArgs e,int Id)
{
if (await JsRuntime.InvokeAsync<bool>("confirm",$"你是否確認要刪除當前檔案?"))
{
DeleteFile(e, Id);
await RefterData.InvokeAsync();
}
}
}
5. 在瀏覽器的“多檔案上傳示例”頁面中使用滑鼠左鍵點選“選擇檔案”按鈕,在彈出的對話方塊中,選擇“1K檔案”,檔案將被上傳,檔案資訊會在上傳成功之後,及時更新到“已上傳檔案列表”中。如下圖。
6. 在已上傳檔案列表中,點選要刪除的上傳檔案記錄前面的刪除按鈕。系統會彈出一個“你是否確認要刪除當前檔案”的提示資訊,如下圖。
7. 使用滑鼠左鍵點選“確定”按鈕,系統將把檔案資訊刪除,同時重新整理“已上傳檔案列表”資訊。如下圖。