背景
有一个我无法控制的外部程序每 8 秒将制表符分隔的行写入“PRN”文件 (Test_1234.prn)。我的程序的工作是读取该文件并将第 n 行(写入文件的最后一行)写入一个简单的示例 ListView。我还在视图中运行了一个秒表,我计划使用时钟通过检查秒表的秒数来驱动 PRN 的读数。每 4 秒我会出去读取文件并返回一个 DataTable,然后每 8 秒我会将该 DataTable 的第 n 行写入我的视图。PRN 确实有很多行,但大小永远不会超过 1mb - 5mb。
问题
我的问题源于这是一个同步操作,虽然它工作,但它只工作几分钟,并且 StopWatch 行为不规律,并调用向我的 SamplesView 写入多行。这最终导致我的 _nextLine 计数器领先于实际 PRN 所在的位置,并且我得到一个越界异常。
鉴于缺乏线程经验,我不知道从哪里开始使用线程来修复此代码,以便它在它应该做的时间间隔内做它应该做的事情。
由于 Samples 集合需要定期更新,我怀疑我需要实现一些东西,例如尊重视图权利的后台线程,以便根据我在此处和此处阅读的内容在主线程上更新自身。但是,再一次,我不知道从哪里开始。
有人可以帮助实施线程解决方案来解决我的特定问题吗?
//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++;
}
}