I'm creating an application(logviewer) which will display the logs from xml files.
Note: each xml file can have one or more records.my application has to show each record as one row in DatagridView
control.
basically it will perform the following tasks:
1.from the Do_Work
=> parse each xml file and add the records to the List.
2.if the List size reaches 100
then call the ProgressChanged
event to update the UI (DataGridView) with 100 records.
3.repeat this process untill all records from all xml files are appended to the UI (DataGridView)
requirements: even if the user is trying to read some thousands of files, UI should not freeze.
i have implemented the above scenario by waiting for 100 milliseconds in the DoWork
event before calling the ProgressChanged
for following reason:
1.Background thread waits (Thread.Sleep(100))for 100 milliseconds so that UI Thread can be updated meanwhile and visible to the User(records are appending).
do i need to have the Thread.Sleep()
to make the UI thread to render the records.
is there any best approach through which i can update the UI without freezing?
because if i test my application with 4 thousand records,then 100 milliseconds waiting time also not working , i mean application freezes if i do some operations on the form.
but if i increase the waiting time to 500 ms then it works but it takes more time to display all the records.
so please suggest me the better approach in updating the UI while working with BackgroundWorker component.
here is my code:
Note: this is sample code
private void bWorkerReadXmlLogs_DoWork(object sender, DoWorkEventArgs e)
{
try
{
//declare a xmlLogRecords list to hold the list of log records to be displayed on the UI
List<XmlLogRecord> lstXmlLogRecords = new List<XmlLogRecord>();
//loop through the records sent by the GetLogDetails() function and add it to the list
foreach (XmlLogRecord record in GetLogDetails(path))
{
//cancel the background thread if the cancel was requested from the user.
if (bWorkerReadXmlLogs.CancellationPending)
{
e.Cancel = true;
return;
}
//add log record to the list
lstXmlLogRecords.Add(record);
/*if the list contains 100 items then invoke the progresschanged event
where it appends the 100 items into the LogViewer UI (DataGridView)*/
if (lstXmlLogRecords.Count % 100 == 0)
{
//block/wait on background thread so that processor allocates some cycles to work on UI/Main thread to update the records on the DatagridView
Thread.Sleep(100); //if i wait more time like 500 ms then UI does not freeze but it takes more time
bWorkerReadXmlLogs.ReportProgress(0, new List<XmlLogRecord>(lstXmlLogRecords));
//clear the List to start/add items from the beginning.
lstXmlLogRecords.Clear();
}
}
//invoke the ProgressChanged Event for updating the DataGridView if the List contains less than 100 items greater than 0 items
if (lstXmlLogRecords.Count > 0)
{
//Invoke ProgressChanged Event to update the records on the DataGridView
bWorkerReadXmlLogs.ReportProgress(0, lstXmlLogRecords);
}
}
catch (Exception ex)
{
Write_Trace(ex.Message);
}
}
private void bWorkerReadXmlLogs_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
try
{
var rowIndex = 0;
if (e.UserState is List<XmlLogRecord>)
{
//Cast the UserState object into the List<XmlLogRecord>
var records = e.UserState as List<XmlLogRecord>;
//iterate over all the records sent from DoWork event and append the each record into the LogViewer control DataGridView UI
foreach (var record in records)
{
//get the next row Index where the new row has to be placed.
rowIndex = dgvLogViewer.Rows.Count;
//add an emtpy row to add the empty cells into it
dgvLogViewer.Rows.Add();
//set the LogViewer properties if not set already
if (!IsLogviewerPropertiesSet)
{
SetLogViewerProperties();
}
//Disable the Column selection for image columns
DisableImageColumnsSelection(rowIndex);
//Add Data for normal or text cells into the LogViewer Control (DatagridView)
AddLogviewerTextCells(rowIndex, record);
//Add Icons in Image Columns into the LogViewer control (DataGridView)
AddLogviewerImageCells(rowIndex, record);
}
//Sort the LogViewer control (DataGridView) by Datetime column(Index = 2) in Descending order.
dgvLogViewer.Sort(dgvLogViewer.Columns[MKeys.DTTIME], ListSortDirection.Descending);
dgvLogViewer.Columns[MKeys.DTTIME].HeaderCell.SortGlyphDirection = SortOrder.Descending;
if (!IsLogviewerSortingDone)
{
//call selectedindex changed event of the selected record in the datagridview
dgvLogViewer_SelectionChanged(null, null);
IsLogviewerSortingDone = true;
}
}
}
catch (Exception ex)
{
Write_Trace(ex.Message);
}
}
}