将 wpf 进度条与库中的函数同步的正确方法
Proper way to sync a wpf progress bar with function from a library
我正在使用库中的函数来处理非常大的 word 文件,但我无法更改此函数。
在处理过程中,我想显示一个进度条,因为无论哪种方式,应用程序看起来都冻结了,用户不知道它实际上在工作。
现在我正在使用这样的工人:
private void btnClick(object sender, RoutedEventArgs e)
{
BackgroundWorker worker = new BackgroundWorker();
worker.RunWorkerCompleted += worker_RunWorkerCompleted;
worker.WorkerReportsProgress = true;
worker.DoWork += worker_DoConvertOne;
worker.ProgressChanged += worker_ProgressChanged;
worker.RunWorkerAsync();
}
private void worker_DoConvertOne(object sender, DoWorkEventArgs e)
{
var worker = sender as BackgroundWorker;
//The progress bar is filled on 20%
worker.ReportProgress(0);
worker.ReportProgress(10);
worker.ReportProgress(20);
//Processing
myLongLastingFunction(bigWordFile);
//The progress bas is full
worker.ReportProgress(100, "Done Processing.");
}
private void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
MessageBox.Show("Converting finished!");
TestProgressBar.Value = 0;
ProgressTextBlock.Text = "";
}
private void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
TestProgressBar.Value = e.ProgressPercentage;
ProgressTextBlock.Text = (string)e.UserState;
}
它正在工作,但它是一种解决方法,我想知道是否有解决我的问题的正确方法。提前致谢。 :)
如果您的 myLongLastingFunction
没有报告任何进度,则无法判断在任何时候完成了多少工作。
然而,正如 Satyaki Chatterjee 已经建议的那样,您可以使用无限进度条。
我从你的问题中了解到,改变 myLongLastingFunction
不可能让你定期更新进度,而且该功能目前不存在此功能。
对于无法确定任务持续时间的这些情况,带有依赖项 属性 IsIndeterminate="True"
的进度条是向用户提供此信息的公认方式。这使进度条动画连续滚动。
XAML
<ProgressBar Margin="10" IsIndeterminate="True" />
我个人更喜欢 Windows Phone 上看到的动画移动点。一个例子已经实现 here.
如果这不是您所需要的,下一个最佳方法是估计总时间,然后用 DispatchTimer
细分这段时间以提供周期性事件以增加进度条。这显然有两个问题,要么在达到 100% 之前完成(这不是一件坏事),要么达到 100% 并卡在那里,因为实际时间比估计时间长得多。第二个不良影响会使应用程序再次看起来不活动。
如果您使用的是 4.5,那么您可以使用 IProgress。请参考这个例子
[https://code.msdn.microsoft.com/Progress-of-a-Task-in-C-cdb179ee][1]
读取.txt(Word)文件时可以通过ProgressBar
和BackgroundWorker
显示当前进度。您应该只计算 1 percent
对应 ProgressBar
的比例。让我们看看工作示例:
后面的代码:
public partial class MainWindow : Window
{
BackgroundWorker bw;
long l_file;
public MainWindow()
{
InitializeComponent();
}
string fileName = "";
private void InitializeBackgroundWorker()
{
bw = new BackgroundWorker();
bw.DoWork += Bw_DoWork;
bw.ProgressChanged += Bw_ProgressChanged;
bw.WorkerReportsProgress = true;
}
private void Bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
progressBar.Value = e.ProgressPercentage;
}
private void Bw_DoWork(object sender, DoWorkEventArgs e)
{
ReadFile(fileName);
}
private void btnOpenFLD_Click(object sender, RoutedEventArgs e)
{
progressBar.Minimum = 0;
progressBar.Maximum = 100;
OpenFileDialog ofd = new OpenFileDialog();
if (ofd.ShowDialog() == true)
{
FileInfo fileInfo = new FileInfo(ofd.FileName);
l_file = fileInfo.Length;
fileName = ofd.FileName;
InitializeBackgroundWorker();
bw.RunWorkerAsync();
}
}
private void ReadFile(string fileName)
{
string line;
long onePercent = l_file / 100;
long lineLength = 0;
long flagLength = 0;
using (StreamReader sr = new StreamReader(fileName, System.Text.Encoding.ASCII))
{
while (sr.EndOfStream == false)
{
line = sr.ReadLine();
lineLength = line.Length;
flagLength += lineLength+2;
//Thread.Sleep(1);//uncomment it if you want to simulate a
//very heavy weight file
if (flagLength >= onePercent)
{
CountProgressBar += 1;
bw.ReportProgress(CountProgressBar);
flagLength %= onePercent;
}
}
}
}
int countProgressBar = 0;
private int CountProgressBar
{
get { return countProgressBar; }
set
{
if (countProgressBar < 100)
countProgressBar = value;
else
countProgressBar = 0;
}
}
}
XAML:
<Window x:Class="BackgroundWorkerProgressBarReadFile.MainWindow"
...The code omitted for the brevity...
xmlns:local="clr-namespace:BackgroundWorkerProgressBarReadFile"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="0.2*"/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<ProgressBar Margin="5" Name="progressBar"/>
<Button Grid.Row="1" Content="Open File Dialog" Name="btnOpenFLD"
Click="btnOpenFLD_Click"/>
</Grid>
</Window>
如果你在读取文件后做一些其他工作并且你想显示进度,那么在你完成所有工作后移动此代码即可。
if (flagLength >= onePercent)
{
CountProgressBar += 1;
bw.ReportProgress(CountProgressBar);
flagLength %= onePercent;
}
我正在使用库中的函数来处理非常大的 word 文件,但我无法更改此函数。 在处理过程中,我想显示一个进度条,因为无论哪种方式,应用程序看起来都冻结了,用户不知道它实际上在工作。 现在我正在使用这样的工人:
private void btnClick(object sender, RoutedEventArgs e)
{
BackgroundWorker worker = new BackgroundWorker();
worker.RunWorkerCompleted += worker_RunWorkerCompleted;
worker.WorkerReportsProgress = true;
worker.DoWork += worker_DoConvertOne;
worker.ProgressChanged += worker_ProgressChanged;
worker.RunWorkerAsync();
}
private void worker_DoConvertOne(object sender, DoWorkEventArgs e)
{
var worker = sender as BackgroundWorker;
//The progress bar is filled on 20%
worker.ReportProgress(0);
worker.ReportProgress(10);
worker.ReportProgress(20);
//Processing
myLongLastingFunction(bigWordFile);
//The progress bas is full
worker.ReportProgress(100, "Done Processing.");
}
private void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
MessageBox.Show("Converting finished!");
TestProgressBar.Value = 0;
ProgressTextBlock.Text = "";
}
private void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
TestProgressBar.Value = e.ProgressPercentage;
ProgressTextBlock.Text = (string)e.UserState;
}
它正在工作,但它是一种解决方法,我想知道是否有解决我的问题的正确方法。提前致谢。 :)
如果您的 myLongLastingFunction
没有报告任何进度,则无法判断在任何时候完成了多少工作。
然而,正如 Satyaki Chatterjee 已经建议的那样,您可以使用无限进度条。
我从你的问题中了解到,改变 myLongLastingFunction
不可能让你定期更新进度,而且该功能目前不存在此功能。
对于无法确定任务持续时间的这些情况,带有依赖项 属性 IsIndeterminate="True"
的进度条是向用户提供此信息的公认方式。这使进度条动画连续滚动。
XAML
<ProgressBar Margin="10" IsIndeterminate="True" />
我个人更喜欢 Windows Phone 上看到的动画移动点。一个例子已经实现 here.
如果这不是您所需要的,下一个最佳方法是估计总时间,然后用 DispatchTimer
细分这段时间以提供周期性事件以增加进度条。这显然有两个问题,要么在达到 100% 之前完成(这不是一件坏事),要么达到 100% 并卡在那里,因为实际时间比估计时间长得多。第二个不良影响会使应用程序再次看起来不活动。
如果您使用的是 4.5,那么您可以使用 IProgress。请参考这个例子 [https://code.msdn.microsoft.com/Progress-of-a-Task-in-C-cdb179ee][1]
读取.txt(Word)文件时可以通过ProgressBar
和BackgroundWorker
显示当前进度。您应该只计算 1 percent
对应 ProgressBar
的比例。让我们看看工作示例:
后面的代码:
public partial class MainWindow : Window
{
BackgroundWorker bw;
long l_file;
public MainWindow()
{
InitializeComponent();
}
string fileName = "";
private void InitializeBackgroundWorker()
{
bw = new BackgroundWorker();
bw.DoWork += Bw_DoWork;
bw.ProgressChanged += Bw_ProgressChanged;
bw.WorkerReportsProgress = true;
}
private void Bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
progressBar.Value = e.ProgressPercentage;
}
private void Bw_DoWork(object sender, DoWorkEventArgs e)
{
ReadFile(fileName);
}
private void btnOpenFLD_Click(object sender, RoutedEventArgs e)
{
progressBar.Minimum = 0;
progressBar.Maximum = 100;
OpenFileDialog ofd = new OpenFileDialog();
if (ofd.ShowDialog() == true)
{
FileInfo fileInfo = new FileInfo(ofd.FileName);
l_file = fileInfo.Length;
fileName = ofd.FileName;
InitializeBackgroundWorker();
bw.RunWorkerAsync();
}
}
private void ReadFile(string fileName)
{
string line;
long onePercent = l_file / 100;
long lineLength = 0;
long flagLength = 0;
using (StreamReader sr = new StreamReader(fileName, System.Text.Encoding.ASCII))
{
while (sr.EndOfStream == false)
{
line = sr.ReadLine();
lineLength = line.Length;
flagLength += lineLength+2;
//Thread.Sleep(1);//uncomment it if you want to simulate a
//very heavy weight file
if (flagLength >= onePercent)
{
CountProgressBar += 1;
bw.ReportProgress(CountProgressBar);
flagLength %= onePercent;
}
}
}
}
int countProgressBar = 0;
private int CountProgressBar
{
get { return countProgressBar; }
set
{
if (countProgressBar < 100)
countProgressBar = value;
else
countProgressBar = 0;
}
}
}
XAML:
<Window x:Class="BackgroundWorkerProgressBarReadFile.MainWindow"
...The code omitted for the brevity...
xmlns:local="clr-namespace:BackgroundWorkerProgressBarReadFile"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="0.2*"/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<ProgressBar Margin="5" Name="progressBar"/>
<Button Grid.Row="1" Content="Open File Dialog" Name="btnOpenFLD"
Click="btnOpenFLD_Click"/>
</Grid>
</Window>
如果你在读取文件后做一些其他工作并且你想显示进度,那么在你完成所有工作后移动此代码即可。
if (flagLength >= onePercent)
{
CountProgressBar += 1;
bw.ReportProgress(CountProgressBar);
flagLength %= onePercent;
}