I just got into WPF and am currently trying my luck with the Background worker, so I figured I'd just open any file using the FileOpenDialog
, loop through all the bytes inside the file and report the total progress via worker.ReportProgress
in percentage ... alas, this only works for like ~20 times and then it gets really stuck and suddenly stops at 100%.
Here's my code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Microsoft.Win32;
using System.IO;
using System.Threading;
using System.ComponentModel;
namespace BitStream
{
public partial class MainWindow : Window
{
private int bytes = 0;
private long length = 0;
public MainWindow()
{
InitializeComponent();
}
private void selectFile_Click(object sender, RoutedEventArgs e)
{
BackgroundWorker bw = new BackgroundWorker();
OpenFileDialog ofd = new OpenFileDialog();
if ((bool)ofd.ShowDialog())
{
FileInfo fi = new FileInfo(ofd.FileName);
this.length = fi.Length;
bw.DoWork += bw_DoWork;
bw.RunWorkerCompleted += bw_RunWorkerCompleted;
bw.ProgressChanged += bw_ProgressChanged;
bw.WorkerReportsProgress = true;
Stream str = ofd.OpenFile();
bw.RunWorkerAsync(str);
}
}
private void bw_DoWork(object sender, DoWorkEventArgs e)
{
Stream str = (Stream)e.Argument;
int singleByte = 0;
this.Dispatcher.Invoke(
new Action(() =>
{
int currentProgress = 0;
while ((singleByte = str.ReadByte()) != -1)
{
label1.Content = singleByte;
bytes++;
currentProgress = Convert.ToInt32(((double)bytes) / length * 100);
if (currentProgress > progress)
{
progress = currentProgress;
((BackgroundWorker)sender).ReportProgress(progress);
Thread.Sleep(100);
}
}
}
), System.Windows.Threading.DispatcherPriority.Render);
}
private void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
label2.Content = e.ProgressPercentage + "% completed";
}
private void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
}
}
}
Labels 1 and 2 are there for showing the current byte and the current progress in %.
Feel free to also criticize every other aspect of my code, I just got started with WPF today.
Edited DoWork-Method:
private void bw_DoWork(object sender, DoWorkEventArgs e)
{
Stream str = (Stream)e.Argument;
int singleByte = 0;
int currentProgress = 0;
while ((singleByte = str.ReadByte()) != -1)
{
this.Dispatcher.Invoke(
new Action(() =>
{
label1.Content = singleByte;
}), System.Windows.Threading.DispatcherPriority.Render);
bytes++;
currentProgress = Convert.ToInt32(((double)bytes) / length * 100);
if (currentProgress > progress)
{
progress = currentProgress;
this.Dispatcher.Invoke(
new Action(() =>
{
((BackgroundWorker)sender).ReportProgress(progress);
}), System.Windows.Threading.DispatcherPriority.Render);
Thread.Sleep(500);
}
}
}
Thanks,
Dennis
So assuming you really want to make a cross thread call for each byte (which I wouldn't recommend), the code would look something like:
private void bw_DoWork(object sender, DoWorkEventArgs e)
{
Stream str = (Stream)e.Argument;
int singleByte = 0;
int currentProgress = 0;
while ((singleByte = str.ReadByte()) != -1)
{
bytes++;
this.Dispatcher.Invoke(
new Action(() =>
{
label1.Content = singleByte;
}
), System.Windows.Threading.DispatcherPriority.Render);
currentProgress = Convert.ToInt32(((double)bytes) / length * 100);
if (currentProgress > progress)
{
progress = currentProgress;
((BackgroundWorker)sender).ReportProgress(progress);
Thread.Sleep(100);
}
}
}
The idea being that you can only manipulate a DispatcherObject on the thread on which it was created.