我在Windows 7 64位上使用Visual Studio 2013,尝试制作一个简单的程序来管理某些文件的副本,例如TeraCopy。
我正面临这个问题: 我有一个进度条,显示主要进度(复制文件数/文件总数),显示与值不匹配...
以下是该行为的视频:https://vid.me/tDc1
以下是代码:
_totalProcessFileProgressBar.Minimum = 0;
_totalProcessFileProgressBar.Maximum = FileList.Length;
_totalProcessFileProgressBar.Value = 0;
int fileCounter = 1;
foreach (string File in FileList)
{
Program.move(File, _destinationFolder.SelectedPath + System.IO.Path.GetFileName(File), (fileCounter++).ToString() + " / " + FileList.Length.ToString());
Trace.write(File);
++_totalProcessFileProgressBar.Value;
//_totalProcessFileProgressBar.Update();
//_totalProcessFileProgressBar.Refresh();
_totalProcessFileProgressBar.Invalidate();
}
顺便说一句,我也尝试过使用它:
_totalProcessFileProgressBar.Step = 1;
(...)
_totalProcessFileProgressBar.PerformStep();
结果完全相同。
在调试模式下,我可以看到进度条的值为4,例如,最大值为8,条形图仅显示30%的进度。
好的,所以我使用了totalProcessFileProgressBar.Maximum = FileList.Length - 1
,并将我的Program.move()
方法更改为async
,行为非常相似。
以下是一些代码:
Program.move():
public async static Task<int> move(String inFileName, String outFileName, string text, bool copy = false)
{
FileAttributes attr = File.GetAttributes(inFileName);
if ((attr & FileAttributes.Directory) == FileAttributes.Directory)
{
return 0;
}
FileStream streamIn = null;
try
{
streamIn = new FileStream(inFileName, FileMode.Open);
}
catch (System.IO.IOException ex)
{
Trace.write("[IOException]" + inFileName + " : " + ex.Message);
return 0;
}
catch (System.UnauthorizedAccessException ex)
{
Trace.write("[UnauthorizedAccessException]" + inFileName + " : " + ex.Message);
return 0;
}
mainForm.currentFileProgressBar.Minimum = 0;
mainForm.currentFileProgressBar.Maximum = Convert.ToInt32(streamIn.Length);
mainForm.currentFileProgressBar.Value = 0;
mainForm.Text = '[' + text + ']';
BinaryReader inFile = new BinaryReader(streamIn);
BinaryWriter outFile = new BinaryWriter(new FileStream(outFileName, FileMode.Create));
Trace.write("Out file name : " + ((FileStream)(outFile.BaseStream)).Name);
const int BUFFER_LENGHT = 8388608;
byte[] buffer = new byte[BUFFER_LENGHT];
int amountRead;
const int CONVERSION = ((1024 * 1024) / 1000);
Stopwatch stopwatchCompteurDatas = new Stopwatch();
stopwatchCompteurDatas.Start();
long currentFileAmountRead = 0;
while ((amountRead = inFile.Read(buffer, 0, BUFFER_LENGHT)) > 0)
{
outFile.Write(buffer, 0, amountRead);
dataCounter += amountRead;
currentFileAmountRead += amountRead;
mainForm.currentFileProgressBar.Value += amountRead;
mainForm.currentFileProgressBar.Invalidate();
using (Graphics gr = mainForm.currentFileProgressBar.CreateGraphics())
{
gr.DrawString(Convert.ToString((100 * currentFileAmountRead) / streamIn.Length) + "% - " + inFileName, SystemFonts.DefaultFont, Brushes.Black, new PointF(10, mainForm.currentFileProgressBar.Height / 2 - (gr.MeasureString("45" + "%", SystemFonts.DefaultFont).Height / 2.0F)));
}
if (dataCounter > (36870912))
{
elapsedTime += stopwatchCompteurDatas.ElapsedMilliseconds;
stopwatchCompteurDatas.Restart();
if (elapsedTime > 0)
{
double rate = dataCounter / (elapsedTime * CONVERSION);
mainForm.Text = Convert.ToString(rate) + " Mb/s [" + text + ']';
}
dataCounter = 0;
elapsedTime = 0;
}
}
inFile.Close();
outFile.Close();
return 0;
}
表单类中的一些代码:
// Drag'n drop Callback
void mainForm_DragDrop(object sender, DragEventArgs e)
{
// Extract the data from the DataObject-Container into a string list
FileList = (string[])e.Data.GetData(DataFormats.FileDrop, false);
processFileList();
}
private async void processFileList()
{
_totalProcessFileProgressBar.Minimum = 0;
_totalProcessFileProgressBar.Maximum = FileList.Length-1;
Trace.write("_totalProcessFileProgressBar.Maximum : " + _totalProcessFileProgressBar.Maximum);
_totalProcessFileProgressBar.Value = 0;
_totalProcessFileProgressBar.Step = 1;
if ("" == _destinationFolderSelector.SelectedPath)
{
DialogResult result = this._destinationFolderSelector.ShowDialog();
if(DialogResult.Cancel == result)
{
return;
}
else
{
_destinationFolderSelector.SelectedPath += '\\';
}
}
Trace.write("destinationFolderSelector.SelectedPath : " + _destinationFolderSelector.SelectedPath);
int filesCounter= 1;
foreach (string File in FileList)
{
this.Text += File + "\n";
var context = TaskScheduler.FromCurrentSynchronizationContext();
await Program.move(File, _destinationFolderSelector.SelectedPath + System.IO.Path.GetFileName(File),
(compteurFichiers++).ToString() + " / " + FileList.Length.ToString());
//Program.move(File, _destinationFolderSelector.SelectedPath + System.IO.Path.GetFileName(File), (compteurFichiers++).ToString() + " / " + FileList.Length.ToString());
Trace.write(File);
//++_totalProcessFileProgressBar.Value;
_totalProcessFileProgressBar.PerformStep();
Trace.write("_totalProcessFileProgressBar.Value : " + _totalProcessFileProgressBar.Value + " / " + _totalProcessFileProgressBar.Maximum);
_totalProcessFileProgressBar.Invalidate();
}
}
希望你能帮忙解决这个问题...在我身边,我读到了关于异步的文档,我不知道它的工作方式。
答案 0 :(得分:0)
我建议您使用Task.Run(...)。看起来像无效/重绘相关的错误,因为您在UI线程上完成所有操作。类似的东西:
var context = TaskScheduler.FromCurrentSynchronizationContext();
Task.Run(() =>
{
Program.move(File, _destinationFolder.SelectedPath + System.IO.Path.GetFileName(File),
(fileCounter++).ToString() + " / " + FileList.Length.ToString());
Trace.write(File);
}).ContinueWith((task) => ++_totalProcessFileProgressBar.Value, context);
希望它有助于推动你朝着正确的方向前进!
答案 1 :(得分:0)
令人遗憾的是,问题中的代码示例并不是更好。更完整的将允许更好的答案。也就是说,我相信您在这里真正需要的是使用async
/ await
模式:
// Making the assumption here that the method is a button's Click event handler
private async void button1_Click(object sender, EventArgs e)
{
_totalProcessFileProgressBar.Minimum = 0;
_totalProcessFileProgressBar.Maximum = FileList.Length;
_totalProcessFileProgressBar.Value = 0;
int fileCounter = 1;
foreach (string File in FileList)
{
await Task.Run(() => Program.move(File,
_destinationFolder.SelectedPath + System.IO.Path.GetFileName(File),
(fileCounter++) + " / " + FileList.Length));
Trace.write(File);
++_totalProcessFileProgressBar.Value;
}
}
这导致在UI线程继续时在工作线程中处理每个“移动”操作。当每个操作完成时,执行使用UI线程返回紧跟await
之后的语句,即Trace.write(File);
方法。
根据实际的实施情况,有可能将Program.move()
方法设为async
方法,允许您放弃Task.Run()
来电,只需await
Program.move()
直接致电。由于给出了不完整的代码示例,我无法提供更具体的建议。
请注意,上述假设Trace.write(File);
不是一项耗时的操作。如果是,那么它应该包含在工作线程的任务中,而不是在它之后。或者,如果Trace.write()
方法需要访问某个UI对象,那么您也可以将其转换为async
方法,使用Task
执行耗时的部分。工作线程但仍然访问UI线程中的UI对象。同样,通过更完整的代码示例,可以在此处提供更完整的答案。不幸的是,我所能做的就是尽力解决最明显的可能性。