This post is entirely updated to put all code in one class and to try to make it as straight-forward as possible.
The project works perfectly EXCEPT for one thing: When a student record is updated, the database is updated, but the visible list does not update.
The only way I've been able to see the changes is when I refresh the entire page (see NavigationManager line at bottom of code).
Can you please help me understand what I'm not doing right here.
@page "/Students2"; @using ParentChild.Models; @inject IJSRuntime JS; // Used for Confirmation Dialog & Alert Box @inject NavigationManager NavigationManager // Used to Refresh Entire Page <h3>Students 2</h3> @if (byStudents == null) { <p><em>Loading...</em></p> } else if (!byStudents.Any()) { <p><em>No students in database. Please add some.</em></p> } else { <table class="table"> <thead> <tr> <th>First</th> <th>Last</th> <th>Street</th> <th>City</th> <th>State</th> <th>Zip</th> <th>Cell</th> <th>Home</th> <th>Email</th> <th>Note</th> <th></th> </tr> </thead> <tbody> @foreach (var byStudent in byStudents) { <tr> <td>@byStudent.SFirst</td> <td>@byStudent.SLast</td> <td>@byStudent.SStreet</td> <td>@byStudent.SCity</td> <td>@byStudent.SState</td> <td>@byStudent.SZip</td> <td>@byStudent.SCell</td> <td>@byStudent.SHome</td> <td>@byStudent.SEmail</td> <td>@byStudent.SNote</td> <td> <input type="button" class="btn btn-primary" @onclick="@(() => OpenEditStudent(@byStudent.SId))" value="Edit" /> <nbsp></nbsp> <input type="button" class="btn btn-danger" @onclick="@(async () => await DeleteStudentAction(@byStudent.SId))" value="Delete" /> </td> </tr> } </tbody> </table> } <button class="btn btn-primary" @onclick="() => OpenAddStudent()">Add New Student</button> @if (showBackdrop) { <div class="modal-backdrop fade show"></div> } <!-- Define Modal Pop-UP in this Page --> <div class="modal @modalClass" tabindex="-1" role="dialog" style="display:@modalDisplay; overflow-y: auto;"> <div class="modal-dialog modal-lg" role="document"> <div class="modal-content"> <div class="modal-header"> <h5 class="modal-title"> <!-- Pop-Up Title Section --> @{ var txt = ""; if ((SId == null) | (SId == "")) { txt = "Add Student"; @txt; } else { txt = "Edit Student"; @txt; } } </h5> <!-- Pop-Up Close Button at Top --> <button type="button" class="close" data-dismiss="modal" aria-label="Close" @onclick="Close"> <span aria-hidden="true">×</span> </button> </div> <div class="modal-body"> <!-- Pop-Up Body Section --> <div class="form-group row"> <input id="SId" @bind="SId" type="hidden" class="col-sm-4 form-control" /> </div> <div class="form-group row"> <label for="@SFirst" class="col-sm-8 col-form-label">First Name:</label> <input id="SFirst" @bind="SFirst" class="col-sm-4 form-control" /> </div> <div class="form-group row"> <label for="@SLast" class="col-sm-8 col-form-label">Last Name:</label> <input id="SLast" @bind="SLast" class="col-sm-4 form-control" /> </div> <div class="form-group row"> <label for="@SStreet" class="col-sm-8 col-form-label">Street:</label> <input id="@SStreet" @bind="SStreet" class="col-sm-4 form-control" /> </div> <div class="form-group row"> <label for="@SCity" class="col-sm-8 col-form-label">City:</label> <input id="@SCity" @bind="SCity" class="col-sm-4 form-control" /> </div> <div class="form-group row"> <label for="@SState" class="col-sm-8 col-form-label">State:</label> <input id="@SState" @bind="SState" class="col-sm-4 form-control" /> </div> <div class="form-group row"> <label for="@SZip" class="col-sm-8 col-form-label">Zip:</label> <input id="@SZip" @bind="SZip" class="col-sm-4 form-control" /> </div> <div class="form-group row"> <label for="@SCell" class="col-sm-8 col-form-label">Cell #:</label> <input id="@SCell" @bind="SCell" class="col-sm-4 form-control" /> </div> <div class="form-group row"> <label for="@SHome" class="col-sm-8 col-form-label">Home #:</label> <input id="@SHome" @bind="SHome" class="col-sm-4 form-control" /> </div> <div class="form-group row"> <label for="@SEmail" class="col-sm-8 col-form-label">Email:</label> <input id="@SEmail" @bind="SEmail" class="col-sm-4 form-control" /> </div> <div class="form-group row"> <label for="@SNote" class="col-sm-8 col-form-label">Note:</label> <input id="@SNote" @bind="SNote" class="col-sm-4 form-control" /> </div> </div> <div class="modal-footer"> <!-- Pop-Up Body Section --> @{ if ((SId == null) | (SId == "")) { <button type="button" class="btn btn-primary" @onclick="async () => await AddStudentAction()">Add</button> } else { <button type="button" class="btn btn-primary" @onclick="async () => await UpdateStudentAction(this.SId)">Update</button> } } <button type="button" class="btn btn-secondary" data-dismiss="modal" @onclick="() => this.Close()">Close</button> </div> </div> </div> </div> @code { //------------------------------------------------------------------------- // Modal Control Variables and Code //------------------------------------------------------------------------- private string modalDisplay = "none;"; private string modalClass = ""; private bool showBackdrop = false; //--- Open Modal... public void Open() { modalDisplay = "block;"; modalClass = "show"; showBackdrop = true; } //--- Close Modal... public void Close() { modalDisplay = "none"; modalClass = ""; showBackdrop = false; } //------------------------------------------------------------------------- // Student List from Database //------------------------------------------------------------------------- DB_136837_byogaContext db = new DB_136837_byogaContext(); private List<ByStudents> byStudents; //--- Build Student List on Page Initialization... protected override void OnInitialized() { byStudents = db.ByStudents.ToList(); } //------------------------------------------------------------------------- // Modal Parameters //------------------------------------------------------------------------- private Modal modal { get; set; } [Parameter] public string SId { get; set; } = ""; [Parameter] public string SFirst { get; set; } = ""; [Parameter] public string SLast { get; set; } = ""; [Parameter] public string SStreet { get; set; } = ""; [Parameter] public string SCity { get; set; } = ""; [Parameter] public string SState { get; set; } = ""; [Parameter] public string SZip { get; set; } = ""; [Parameter] public string SCell { get; set; } = ""; [Parameter] public string SHome { get; set; } = ""; [Parameter] public string SEmail { get; set; } = ""; [Parameter] public string SNote { get; set; } = ""; //------------------------------------------------------------------------- // Open Modal to Add Student //------------------------------------------------------------------------- protected void OpenAddStudent() { //-- Clear Any Info Set in Previous Edit Requests... SId = ""; SFirst = ""; SLast = ""; SStreet = ""; SCity = ""; SState = ""; SZip = ""; SCell = ""; SHome = ""; SEmail = ""; SNote = ""; //--- Open Modal Popup... this.Open(); } //------------------------------------------------------------------------- // Open Modal to Edit Student //------------------------------------------------------------------------- protected void OpenEditStudent(int myID) { //--- Build & Run SQL Select Statement... using (var myContext = new DB_136837_byogaContext()) { //--- Grab Info for Selected Student... var myQuery = (from s in myContext.ByStudents where s.SId == myID select s).Single(); //--- Set Fields on Popup Form... this.SId = myQuery.SId.ToString(); this.SFirst = myQuery.SFirst; this.SLast = myQuery.SLast; this.SStreet = myQuery.SStreet; this.SCity = myQuery.SCity; this.SState = myQuery.SState; this.SZip = myQuery.SZip; this.SCell = myQuery.SCell; this.SHome = myQuery.SHome; this.SEmail = myQuery.SEmail; this.SNote = myQuery.SNote; } //--- Open Modal Form... this.Open(); } //------------------------------------------------------------------------- // Delete Selected Student from Database with Confirmation Dialog //------------------------------------------------------------------------- protected async Task DeleteStudentAction(int myID) { bool isConfirmed = await JS.InvokeAsync<bool>("confirm", $"Do you sure you want to permanently delete whis record?"); if (isConfirmed) { //--- Build & Run SQL Delete Statement... using (var myContext = new DB_136837_byogaContext()) { var myQuery = (from d in myContext.ByStudents where d.SId == myID select d).Single(); myContext.ByStudents.Remove(myQuery); myContext.SaveChanges(); } //--- Delete Complete Dialog... await JS.InvokeVoidAsync("alert", "Record Deleted"); //--- Refresh Page... await InvokeAsync(() => { StateHasChanged(); this.OnInitialized(); }); } } //------------------------------------------------------------------------- // Add Student to Database //------------------------------------------------------------------------- protected async Task AddStudentAction() { //--- Define the New Student... var newStudent = new ByStudents(); newStudent.SFirst = SFirst; newStudent.SLast = SLast; newStudent.SStreet = SStreet; newStudent.SCity = SCity; newStudent.SState = SState; newStudent.SZip = SZip; newStudent.SCell = SCell; newStudent.SHome = SHome; newStudent.SEmail = SEmail; newStudent.SNote = SNote; //--- Add New Student to Database... using (var myContext = new DB_136837_byogaContext()) { myContext.ByStudents.Add(newStudent); myContext.SaveChanges(); } //--- Close the Popup... this.Close(); //--- Refresh Page... await InvokeAsync(() => { StateHasChanged(); this.OnInitialized(); }); } //------------------------------------------------------------------------- // Update Student in Database //------------------------------------------------------------------------- protected async Task UpdateStudentAction(string myID) { //--- Build & Run SQL Select Statement... using (var myContext = new DB_136837_byogaContext()) { //--- Update Info for Selected Student... var myQuery = (from d in myContext.ByStudents where d.SId == Convert.ToInt32(myID) select d).Single(); myQuery.SFirst = this.SFirst; myQuery.SLast = this.SLast; myQuery.SStreet = this.SStreet; myQuery.SCity = this.SCity; myQuery.SState = this.SState; myQuery.SZip = this.SZip; myQuery.SCell = this.SCell; myQuery.SHome = this.SHome; myQuery.SEmail = this.SEmail; myQuery.SNote = this.SNote; myContext.ByStudents.Update(myQuery); myContext.SaveChanges(); } //--- Close the Popup... this.Close(); //--- Refresh Page... await InvokeAsync(() => { StateHasChanged(); this.OnInitialized(); }); //--- Refresh Page by Reloading...SHOULD NOT HAVE TO DO THIS! //NavigationManager.NavigateTo("Refresh/Students2"); } } Any and all help is appreciated. Thanks!
StateHasChangedas "redraw this component and anything inside it, but leave anything upstream unchanged"private List<ByStudents> byStudents => db.ByStudents.ToList();and then you can callStateHasChanged();I don't think you need it in an InvokeAsync either as it's happening in the UI thread.