private void DgvLog_CellValueNeeded(object sender, DataGridViewCellValueEventArgs e) { var logIndex = e.RowIndex; if (LogEntries.TryGetValue(logIndex, out var logEntry)) { if (logEntry.Status == LogEntryStatus.Present) { e.Value = logEntry.Message; } return; } e.Value = ""; if (!logToken.HasValue) { return; } // Find first displayed row that has no log present or requested var start = logIndex; for (; start > DgvLog.FirstDisplayedScrollingRowIndex; start--) { if (LogEntries.TryGetValue(start - 1, out var _)) { break; } } // Find last displayed row that has no log present or requested var end = logIndex; for (; end < DgvLog.GetLastDisplayedScrollingRowIndex(true); end++) { if (LogEntries.TryGetValue(end + 1, out var _)) { break; } } var count = end - start + 1; RequestLogEntries(logToken.Value, start, count); }
private async void RequestLogEntries(Guid logToken, int start, int count) { foreach (var index in Enumerable.Range(start, count)) { _ = LogEntries.TryAdd(index, new LogEntry { Status = LogEntryStatus.Requested, Message = "", }); } try { var logData = await Task.Factory.StartNew(() => WcfProxy.GetLogEntries(logToken, start, count)); if (start + count > DgvLog.RowCount) { return; } var logIndex = start; foreach (var logEntry in logData.LogEntries) { _ = LogEntries[logIndex++] = new LogEntry { Status = LogEntryStatus.Present, Message = logEntry, }; } foreach (var index in Enumerable.Range(start, count)) { DgvLog.UpdateCellValue(0, index); } } catch (Exception ex) when( ex is EndpointNotFoundException || ex is CommunicationException) { foreach (var index in Enumerable.Range(start, count)) { _ = LogEntries.TryRemove(index, out _); } } }
private void StatusTimerCallback(object param) { try { var status = WcfProxy.GetCurrentStatus(); this.InvokeIfRequired(() => { if (logToken != status.LogToken) { // Has to be in this order // Otherwise clearing the DGV causes cell value requests // in this thread before continuing here. // Which has a high chance of adding items in the // LogEntries list, which are subsequently cleared, // leaving empty cells in the DGV that won't be filled. DgvLog.RowCount = 0; LogEntries.Clear(); } logToken = status.LogToken; // If we are scrolled down, we auto scroll var prevRowCount = DgvLog.RowCount; DgvLog.RowCount = status.LogCount; if (DgvLog.GetLastDisplayedScrollingRowIndex(false) + 1 >= prevRowCount) { DgvLog.FirstDisplayedScrollingRowIndex = DgvLog.RowCount - 1; } UpdateOperation(status.Operation); DuplicateCount = status.DuplicateCount; LblDuplicateCount.Text = string.Format( StatusInfoDuplicateCount, DuplicateCount); BtnResolveDuplicates.Enabled = DuplicateCount > 0; BtnDiscardDuplicates.Enabled = DuplicateCount > 0; }); } catch (Exception ex) when( ex is EndpointNotFoundException || ex is CommunicationException || ex is TimeoutException) { Debug.Print("Status request failed with: " + ex.Message); this.InvokeIfRequired(() => { BtnResolveDuplicates.Enabled = false; UpdateOperation(new OperationInfo { Message = "Connecting...", ProgressStyle = ProgressStyle.Marquee, }); }); } finally { _ = StatusTimer.StartSingle(Settings.StatusRequestInterval); } }