Background
There is an external program which I do not control that writes tab-delimited lines to a "PRN" file (Test_1234.prn) every 8 seconds. My program's job is read that file and write the nth line (the last line written to the file) to a simple ListView of Samples. I also run a StopWatch in the view and I had plans to use the clock to drive the reading of the PRN by checking the seconds of the StopWatch. Every 4 seconds I would go out and read the file and return a DataTable and then every 8 seconds I would write the nth line of that DataTable to my View. The PRN does get hold a lot of lines but the size never gets larger than a 1mb - 5mb.
The Problem
My problem stems from the fact that this is a synchronous operation, and while it works, it works only for a few minutes and the StopWatch behaves erratically and invokes the writing of multiple lines to my SamplesView. This ultimately causes my _nextLine counter to get ahead of where the actual PRN is and I get an out-of-bounds exception.
Given a lack of threading experience, I dont know where to start in using threads to fix this code so that it does what it is supposed to at the interval it is supposed to.
Since the Samples collection needs to be updated at an interval, I suspect I will need to implement something such as a background thread that respects the right of the View to update itself on the main thread given what I have read here and here. But, again, I don't know where to start.
Can someone help with implementing a threaded solution to fix my specific issue?
//Xaml belongs to my CalibrationView.xaml
<StackPanel Orientation="Vertical">
<Label Content="Run Time:" FontSize="16" FontWeight="Bold" Margin="10,0,0,0"/>
<TextBlock Name="ClockTextBlock" Text="{Binding CurrentTime, Mode=TwoWay}"/>
<ListView ItemsSource="{Binding Samples}" SelectedItem="{Binding SelectedSample}">
<ListView.View>
<GridView>
<GridViewColumn Header="Time" Width="70" DisplayMemberBinding="{Binding Time}"/>
</GridView>
</ListView.View>
</ListView>
</StackPanel>
public class CalibrationViewModel : ViewModelBase
{
DispatcherTimer dt = new DispatcherTimer();
Stopwatch stopWatch = new Stopwatch();
private bool _firstTime = true;
private int _nextLine = 1;
private int _sampleCount;
public CalibrationViewModel(Calibration calibration)
{
Samples = new ObservableCollection<StepRecord>();
dt.Tick += dt_Tick;
dt.Interval = new TimeSpan(0, 0, 0, 1);
}
public ObservableCollection<StepRecord> Samples { get; set; }
public DataTable Prn { get; set; }
public String CurrentTime
{
get { return _currentTime; }
set
{
if (_currentTime != value)
{
_currentTime = value;
OnPropertyChanged("CurrentTime");
}
}
}
void dt_Tick(object sender, EventArgs e)
{
if (stopWatch.IsRunning)
{
TimeSpan ts = stopWatch.Elapsed;
CurrentTime = String.Format("{0:00}:{1:00}:{2:00}", ts.Hours, ts.Minutes, ts.Seconds);
if (ts.Seconds % 4 == 0)
{
// Custom parser that reads a Tab Delimited file and returns a DataTable (PRN)
PrnParser parser = new PrnParser();
Prn = parser.PopulateDataTableFromTextFile(@"C:\Users\Path\To\File\Test_1234.prn");
if (_firstTime)
{
_nextLine = Prn.Rows.Count - 1;
_firstTime = false;
}
}
if (ts.Seconds % 8 == 0)
{
WriteLineToSamplesCollection();
}
}
}
private void WriteLineToSamplesCollection()
{
var record = new StepRecord
{
Time = (Prn.Rows[NextLine].Field<String>("Column-2")),
};
CurrentSample = record;
Samples.Insert(0, record);
_nextLine++;
_sampleCount++;
}
}