Progress Bar not updating using BackgroundWorker - c#

I'm trying to read a file and display the progress on the screen.
It should be displayed on a Progress Bar (progress) and a textbox (progress_text).
This is the code I'm using:
public partial class MainWindow : Window
{
public static List<String> file = new List<String>();
public long currentPosition = 0;
String line;
long length;
public BackgroundWorker worker = new BackgroundWorker();
public MainWindow()
{
InitializeComponent();
worker.WorkerReportsProgress = true;
worker.DoWork += worker_DoWork;
worker.ProgressChanged += worker_ProgressChanged;
}
private void Start(object sender, RoutedEventArgs e)
{
worker.RunWorkerAsync();
}
void worker_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker bg = sender as BackgroundWorker;
Dispatcher.Invoke(() =>
{
progress.Minimum = 0;
progress.Maximum = 100;
FileInfo fi = new FileInfo(upload.Text);
length = fi.Length;
int percent;
using (StreamReader sr = new StreamReader(upload.Text, System.Text.Encoding.ASCII))
{
while (sr.EndOfStream == false)
{
line = sr.ReadLine();
file.Add(line);
currentPosition += line.Count();
percent = (int)(100.0 / length * currentPosition);
bg.ReportProgress(percent);
}
}
});
}
void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
progress.Value = e.ProgressPercentage;
progress_text.Text = "reading " + currentPosition + " out of " + length;
}
}
XAML:
<Window x:Class="ProgressBarUploadFile.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525"
>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="20*"/>
<RowDefinition Height="20*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="20*"/>
<ColumnDefinition Width="20*"/>
</Grid.ColumnDefinitions>
<Button Grid.Row="0" Grid.Column="0" Content="Select File" FontSize="15" Click="Upload_file"/>
<TextBox x:Name="upload" Grid.Row="0" Grid.Column="1" Text="" />
<Button Grid.Row="1" Grid.Column="0" Content="Start upload" FontSize="15" Click="Start"/>
<ProgressBar Name="progress" Grid.Row="1" Grid.Column="1" />
<TextBlock Name="progress_text" Grid.Row="1" Grid.Column="1" VerticalAlignment="Bottom"/>
</Grid>
When I run it in debug, it seems to be working.
But the progress bar and textbox are updated only when the file is read completely.
I followed a few tutorials, such as:
https://msdn.microsoft.com/en-us/library/cc221403%28v=vs.95%29.aspx?f=255&MSPPError=-2147217396
http://www.wpf-tutorial.com/misc-controls/the-progressbar-control/
But I can't figure it out..
I think it's something very small, but I can't find it.
Thank you!

Try this code:
private void Start(object sender, RoutedEventArgs e)
{
progress.Minimum = 0;
progress.Maximum = 100;
worker.RunWorkerAsync();
}
BackgroundWorker bg = sender as BackgroundWorker;
FileInfo fi = new FileInfo(#"File");
length = fi.Length;
int percent;
using (StreamReader sr = new StreamReader(#"File", System.Text.Encoding.ASCII))
{
while (sr.EndOfStream == false)
{
line = sr.ReadLine();
file.Add(line);
currentPosition += line.Count();
percent = (int)(currentPosition / length) * 100;
bg.ReportProgress(percent);
Thread.Sleep(100);
}
}

Your code has this problem:
(int)(a / b) * 100 will calculate a/b first then convert it to int and then *100, so before a reaches b, the a/b will always be 0.* and (int)(a/b) will always be 0 so the final value 0*100 will always be 0.
Suddenly when a=b then (int)(a/b) become 1 and the final value changed to 100. That is why your progress bar will not be updated until the file is read completely
So, you should use percent = (int)(currentPosition * 100 / length);
Or as #jmc suggested in the comment: use percent = (int)(100.0 / length * currentPosition);

Related

WPF Drag Control during runtime

I been working with winforms, so my knowledge of WFP is non existent, this is something i am trying to test.
In code I am generating few buttons and placing them on Canvas. Than after clik on any button, i am moving that button around, and after second click button should stay at the position where mouse cursor was when clicked.
If mouse cursor go outside canvas then button will stop follow it.
My problem is, that button is moving, but only when mouse cursor is over that button or any other control, but it is not moving while mouse cursor is traveling over Canvas.
XAML
<Window x:Class="WpfTestDrag.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfTestDrag"
mc:Ignorable="d"
Title="MainWindow" Height="522" Width="909">
<Grid>
<Grid.ColumnDefinitions >
<ColumnDefinition Width="20"/>
<ColumnDefinition Width="130*"/>
<ColumnDefinition Width="33*"/>
<ColumnDefinition Width="120"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions >
<RowDefinition Height="40" />
<RowDefinition Height="*" />
<RowDefinition Height="20" />
</Grid.RowDefinitions>
<Canvas Grid.Column="1" Grid.Row="1" x:Name="cnvTest" Width="auto" Height="auto" PreviewMouseMove="CnvTest_PreviewMouseMove"/>
<TextBlock x:Name="txbStatus" Grid.Column="1" Grid.Row="2" Grid.ColumnSpan="2"/>
</Grid>
</Window>
C#
public partial class MainWindow : Window
{
Button bts;
Boolean isUsed = false;
public MainWindow()
{
InitializeComponent();
CreateButtons();
}
private void CreateButtons()
{
var xPos = 10.0;
var yPos = 15.0;
var Rnd = new Random();
for (int i = 0; i < 3; i++)
{
var btn = new Button();
btn.Name = "btn" + i;
btn.Content = "Button - " + i;
btn.Tag = "Tag" + i;
btn.Width = 150;
btn.Height = 150;
btn.Click += Btn_Click;
Canvas.SetLeft(btn, xPos);
Canvas.SetTop(btn, yPos);
cnvTest.Children.Add(btn);
xPos = xPos + btn.Width + Rnd.Next(-15,40);
yPos = yPos + btn.Height + Rnd.Next(-15, 40);
}
}
private void Btn_Click(object sender, RoutedEventArgs e)
{
bts = sender as Button;
if (isUsed == false)
{
isUsed = true;
}
else
{
isUsed = false;
}
}
private void CnvTest_PreviewMouseMove(object sender, MouseEventArgs e)
{
Point p = Mouse.GetPosition(cnvTest);
if (isUsed == true)
{
Canvas.SetLeft(bts, p.X);
Canvas.SetTop(bts, p.Y);
txbStatus.Text = bts.Name.ToString() + " isUsed:" + isUsed.ToString() + " -> xPos:" + p.X.ToString() + " yPos:" + p.Y.ToString();
}
}
}
Should I use something else than Canvas for this?
You should set the Background property of the Canvas to Transparent (or any other Brush) for it to respond to the mouse events:
<Canvas Grid.Column="1" Grid.Row="1" x:Name="cnvTest" Width="auto" Height="auto" PreviewMouseMove="CnvTest_PreviewMouseMove"
Background="Transparent"/>

How to create variable number of RichTextBoxOverflow elements

I'm trying in every way to get out of the loop that must create multiple RichTextBlockOverflow controls based on arbitrary input text length but without success. The HasOverflowContent property doesn't update either synchronously or asynchronously.
The variable bool "ThereIsText" I can not understand when and how to make it false to stop the loop.
The link with the text to paste in the paragraph "Run" is: text to paste.
MainPage.xaml:
<Page
x:Class="Text_Viewer_Test_UWP.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:Text_Viewer_Test_UWP"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid x:Name="Menù" HorizontalAlignment="Left" Width="290" Padding="0" Margin="0,21,0,0">
<Grid Background="White">
<Grid.RowDefinitions>
<RowDefinition Height="50"/>
<RowDefinition Height="50"/>
<RowDefinition Height="50"/>
</Grid.RowDefinitions>
<Button Grid.Row="0" x:Name="btnLoadText" Click="btnLoadText_Click" Content="Display text" HorizontalAlignment="Center" VerticalAlignment="Center" Width="270" Foreground="White" Height="32"/>
<TextBlock Grid.Row="1" x:Name="txtPage" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Grid>
</Grid>
<Grid x:Name="BaseGrid" Margin="320,10,30,10" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Background="Black">
<ScrollViewer x:Name="PageViewer" Background="White" VerticalScrollBarVisibility="Disabled" HorizontalScrollBarVisibility="Visible" VerticalScrollMode="Disabled" HorizontalScrollMode="Enabled">
<StackPanel x:Name="StackViewer" VirtualizingStackPanel.VirtualizationMode="Recycling" Orientation="Horizontal"/>
</ScrollViewer>
</Grid>
</Grid>
MainPage.xaml.cs:
public sealed partial class MainPage : Page
{
RichTextBlock TextOneRich = new RichTextBlock() { Margin = new Thickness(20) };
List<RichTextBlockOverflow> TextList = new List<RichTextBlockOverflow>();
bool ThereIsText = true;
public MainPage()
{
this.InitializeComponent();
StackViewer.Children.Add(TextOneRich);
TextOneRich.Width = 400;
TextOneRich.TextAlignment = TextAlignment.Justify;
}
private async void btnLoadText_Click(object sender, RoutedEventArgs e)
{
TextList.Clear();
TextOneRich.Blocks.Clear();
StackViewer.Children.Clear();
StackViewer.Children.Add(TextOneRich);
Paragraph paragraphText = new Paragraph();
paragraphText.Inlines.Clear();
paragraphText.Inlines.Add(new Run { Text = "PasteTextHere" });
await Task.Run(async () =>
{
await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
{
TextOneRich.Blocks.Add(paragraphText);
});
}).ContinueWith(async t =>
{
await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
{
TextList.Add(new RichTextBlockOverflow() { Width = 400, Margin = new Thickness(20) });
StackViewer.Children.Add(TextList[0]);
TextOneRich.OverflowContentTarget = TextList[0];
});
});
await Task.Run(async () =>
{
await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, async () =>
{
while (ThereIsText)
{
await Task.Run(async () =>
{
await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
{
TextList.Add(new RichTextBlockOverflow() { Width = 400, Margin = new Thickness(20) });
StackViewer.Children.Add(TextList[TextList.Count - 1]);
TextList[TextList.Count - 2].OverflowContentTarget = TextList[TextList.Count - 1];
txtPage.Text = TextList.Count.ToString();
});
});
}
});
});
}
}
If you need to do a lot of manipulation of UI objects, and you want to keep the UI responsive while you do that(1) then you can generally just await for a single millisecond, which will allow the UI to process any input messages etc.
Trying to access the HasOverflowContent property is problematic since it requires a layout pass to complete, and that could take an arbitrary amount of time. We could just await an arbitrary amount of time - say 50ms - but that wouldn't be ideal. Instead, you can use a technique similar to the one from "Waiting for XAML layout to complete" with a slight adjustment.
This XAML and code adds 1000 lines of text to a set of RichTextBlock / RichTextBlockOverflow controls and does so while keeping the UI responsive (the ball keeps moving, and you can scroll the list at any time):
XAML:
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<StackPanel Margin="20" HorizontalAlignment="Stretch" x:Name="container">
<Ellipse Width="20" Height="20" Margin="0, 5" Fill="red"
x:Name="animation" HorizontalAlignment="Left"/>
<Button Content="Go" Click="Go" Margin="0,0,0,5"/>
<ScrollViewer MaxHeight="500">
<StackPanel x:Name="thePanel"/>
</ScrollViewer>
</StackPanel>
</Grid>
Code:
public static class Extensions
{
// This helper function is essentially the same as this answer:
// https://stackoverflow.com/a/14132711/4184842
//
// It adds an additional forced 1ms delay to let the UI thread
// catch up.
public static Task FinishLayoutAsync(this FrameworkElement element)
{
TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>();
// Setup handler that will be raised when layout has completed.
EventHandler<object> handler = null;
handler = (s, a) =>
{
element.LayoutUpdated -= handler;
tcs.SetResult(true);
};
element.LayoutUpdated += handler;
// Await at least 1 ms (to force UI pump) and until the Task is completed
// If you don't wait the 1ms then you can get a 'layout cycle detected' error
// from the XAML runtime.
return Task.WhenAll(new[] { Task.Delay(1), tcs.Task });
}
}
public sealed partial class MainPage : Page
{
public MainPage()
{
InitializeComponent();
// Simple animation to show the UI is not frozen
BadUiAnimation_DontDoThis();
}
// Very VERY bad way of doing animation, but it shows
// that the UI is still responsive. Normally you should
// use StoryBoards to do animation.
void BadUiAnimation_DontDoThis()
{
DispatcherTimer dt = new DispatcherTimer();
dt.Interval = TimeSpan.FromMilliseconds(33);
int delta = 4;
const int width = 20;
dt.Tick += (s, a) =>
{
var leftOffset = animation.Margin.Left;
if (leftOffset + delta < 0)
{
delta *= -1;
leftOffset = 0;
}
else if (leftOffset + delta + width > container.ActualWidth)
{
delta *= -1;
leftOffset = container.ActualWidth - width;
}
else
{
leftOffset += delta;
}
animation.Margin = new Thickness(leftOffset, 5, 0, 5);
};
dt.Start();
}
private async void Go(object sender, RoutedEventArgs e)
{
// Helper function
void AppendSimpleString(string s)
{
RichTextBlock rtb = new RichTextBlock();
rtb.Blocks.Add(CreateParagraphWithText(s));
thePanel.Children.Add(rtb);
}
// Another helper function
Paragraph CreateParagraphWithText(string s)
{
var p = new Paragraph();
var r = new Run();
r.Text = s;
p.Inlines.Add(r);
return p;
}
// Disable the button so you can't click it again until the
// insertion is over
(sender as Button).IsEnabled = false;
thePanel.Children.Clear();
AppendSimpleString($"Begin...{Environment.NewLine}");
// Generate some dummy strings to add to the page
var strings = new StringBuilder();
for (int i = 0; i < 1000; i++)
strings.Append($"This is line {i + 1}{Environment.NewLine}");
string text = strings.ToString();
// Create initial block with far too much text in it
var source = new RichTextBlock();
source.MaxHeight = 100;
source.Blocks.Add(CreateParagraphWithText(text));
thePanel.Children.Add(source);
// Create the first overflow and connect it to the original textblock
var prev = new RichTextBlockOverflow
{
MaxHeight = 100,
Margin = new Thickness(0, 10, 0, 0)
};
thePanel.Children.Add(prev);
source.OverflowContentTarget = prev;
// Wait for layout to complete so we can check the
// HasOverflowContent property
await prev.FinishLayoutAsync();
// Keep creating more overflows until there is no content left
while (prev.HasOverflowContent)
{
var next = new RichTextBlockOverflow
{
MaxHeight = 100,
Margin = new Thickness(0, 10, 0, 0)
};
thePanel.Children.Add(next);
prev.OverflowContentTarget = next;
// Wait for layout to complete, which will compute whether there
// is additional overflow (or not)
await prev.FinishLayoutAsync();
prev = next;
};
AppendSimpleString($"Done!{Environment.NewLine}");
// Enable interaction with the button again
(sender as Button).IsEnabled = true;
}
}
(1): Note that you probably want to do something to limit interaction with your UI while this is happening, which might require you to disable some controls or otherwise make sure the user doesn't mess with your app's state. The sample does this by disabling and then re-enabling the button.

How to show ProgressBar when method is call

I would like to show a ProgressBar when I call a method, so I have try to do this code:
if (parametro.chiave == "VIDEO")
{
//BISOGNA CARICARE IL VIDEO
String urlVideo=caricaVideoOnline(parametro.valore);
....
}
String caricaVideoOnline(string nomeFileVideo)
{
try
{
libreriaYouTube = new UploadVideo(ConfigurationManager.AppSettings["usernameYoutube"],
ConfigurationManager.AppSettings["passwordYouTube"],
ConfigurationManager.AppSettings["developmentKeyYouTube"],
ConfigurationManager.AppSettings["applicationNameYouTube"]);
libreriaYouTube.listaVideoToUpload.Add(nomeFileVideo);
// String video = libreriaYouTube.caricaVideo();
Thread t = new Thread(delegate()
{
for (int i = 0; i < 100000; i++)
{
if (i == 0)
{
ProgressBar progress = new ProgressBar();
progress.Show();
}
Console.WriteLine(i);
}
});
t.SetApartmentState(ApartmentState.STA);
t.Start();
String video= libreriaYouTube.caricaVideo();
video = libreriaYouTube.caricaVideo();
return video;
}
catch (Exception e)
{
log.Error(e);
return null;
}
}
This code found but I show the ProgressBar but it is locked, I don't see the bar run.
This is a code of ProgressBar.xaml
<Window x:Class="Gestore.ProgressBar"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Caricamento video" Height="100" Width="300"
>
<Grid Margin="20">
<ProgressBar Minimum="0" Maximum="100" Name="pbStatus" IsIndeterminate="True" Tag="Attendere....."/>
<Viewbox>
<TextBlock Text='Attendere ...' FontSize="2" x:Name="textVox"/>
</Viewbox>
</Grid>
</Window>
I see a couple of issues with your code:
You should access pbStatus, not create a new progress bar in code
You never update the value of your progress bar ("pbStatus.Value=...")
You can't update the progress bar from thread t. You need to invoke the application's UI thread to do this
The loop runs immediately through. Insert some sleep statements to control its timing behaviour.
The following sample code should work.
Xaml:
<StackPanel Orientation="Vertical">
<ProgressBar Name="pbStatus" Minimum="0" Maximum="100" Height="20"></ProgressBar>
<Button Click="ButtonBase_OnClick">Press me</Button>
</StackPanel>
Code behind:
private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
Thread t = new Thread(delegate()
{
for (int i = 0; i < 100; i++)
{
this.Dispatcher.Invoke(()=>
{
pbStatus.Value = i;
});
Thread.Sleep(500);
}
});
t.Start();
}

WPF usercontrol out of bounds of the Grid

I have a WPF app that I'm testing which loads a XML and visualizes it in a usercontrol. Now the issue I'm having is that every time I load my user control the HorizontalAlignment is okay, but the VerticalAlignment doesn't adept to the height size of the usercontrol.
Anyone has an idea how to solve this?
MainWindow.xaml
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:UserControls="clr-namespace:RackBuildingTesT.UserControls" x:Class="RackBuildingTesT.MainWindow"
Title="MainWindow" Height="578" Width="758" SizeChanged="Window_SizeChanged_1">
<Grid>
<DockPanel HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<Border DockPanel.Dock="Top" BorderBrush="Black" BorderThickness="1">
<Grid>
<Label Content="Welke rack laden" HorizontalAlignment="Left" VerticalAlignment="Top"/>
<ComboBox x:Name="RackChooser" HorizontalAlignment="Left" Margin="100,0,0,0" VerticalAlignment="Top" Width="120" SelectionChanged="RackChooser_SelectionChanged"/>
</Grid>
</Border>
<Border DockPanel.Dock="Top" BorderBrush="Black" BorderThickness="1">
<Grid x:Name="RackGrid" Margin="0,0,0,0">
</Grid>
</Border>
</DockPanel>
</Grid>
MainWindow.xaml.cs
public MainWindow()
{
InitializeComponent();
LoadRackCombo();
}
private void LoadRackCombo()
{
var files = Directory.GetFiles(Properties.Settings.Default.FilePathXMLRack);
foreach (var item in files)
{
RackChooser.Items.Add(item);
}
}
private void RackChooser_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
this.RackGrid.Children.Clear();
this.Cursor = Cursors.Wait;
if (RackChooser.SelectedIndex == -1)
MessageBox.Show("Select a rack");
else
{
string rackFile = Convert.ToString(RackChooser.Items[RackChooser.SelectedIndex]);
UserControls.RackBuilder r = new UserControls.RackBuilder();
RackGrid.HorizontalAlignment = System.Windows.HorizontalAlignment.Stretch;
RackGrid.VerticalAlignment = System.Windows.VerticalAlignment.Stretch;
r.Width = RackGrid.Width;
r.Height = RackGrid.Height;
var _r = TRack.CreateFromXMLFile(rackFile, null);
r.set_Rack(_r);
RackGrid.Children.Add(r);
}
this.Cursor = Cursors.Arrow;
}
private void Window_SizeChanged_1(object sender, SizeChangedEventArgs e)
{
RackGrid.Width = this.Width;
RackGrid.Height = this.Height;
}
RackBuilder.xaml.cs (xaml page is standard WPF usercontrol)
public RackBuilder()
{
InitializeComponent();
}
public TRack fRack { get; set; }
public void set_Rack(TRack value)
{
this.fRack = value;
this.InvalidateVisual();
}
protected override void OnRender(DrawingContext drawingContext)
{
if (this.fRack != null)
{
var xScale = this.Width / this.fRack.Size.Width;
var yScale = this.Height / this.fRack.Size.Height;
var smallest = 0.0;
if (xScale < yScale)
smallest = xScale;
else
smallest = yScale;
foreach (var hole in this.fRack.HolePositions)
{
drawingContext.DrawEllipse(Brushes.Aquamarine, null, new Point(hole.Position.X * xScale, hole.Position.Y * yScale),
hole.Diameter * smallest * 0.5, hole.Diameter * smallest * 0.5);
}
}
}
Result
Instead of adding your Control to a Grid, use the ContentControl and add it to its Content-Property.
It also stretches its child automatically.
I fixed it with putting the MainWindow SizeToContent to WidthAndHeight.

backgroundworker+wpf -> frozen window

-progressbar always 0%
-the window is froozen (while DoWork r.)
-if System.threading.thread.sleep(1) on - works perfectly
whats the problem?
private void btnNext_Click(object sender, RoutedEventArgs e)
{
this._worker = new BackgroundWorker();
this._worker.DoWork += delegate(object s, DoWorkEventArgs args)
{
long current = 1;
long max = generalMaxSzam();
for (int i = 1; i <= 30; i++)
{
for (int j = i+1; j <= 30; j++)
{
for (int c = j+1; c <= 30; c++)
{
for (int h = c+1; h <= 30; h++)
{
for (int d = h+1; d <= 30; d++)
{
int percent = Convert.ToInt32(((decimal)current / (decimal)max) * 100);
this._worker.ReportProgress(percent);
current++;
//System.Threading.Thread.Sleep(1); - it works well
}
}
}
}
}
};
this._worker.WorkerReportsProgress = true;
this._worker.RunWorkerCompleted += delegate(object s, RunWorkerCompletedEventArgs args)
{
this.Close();
};
this._worker.ProgressChanged += delegate(object s, ProgressChangedEventArgs args)
{
this.statusPG.Value = args.ProgressPercentage;
};
this._worker.RunWorkerAsync();
}
<Window x:Class="SzerencsejatekProgram.Create"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Létrehozás" mc:Ignorable="d" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" Height="500" Width="700">
<DockPanel>
<Button DockPanel.Dock="Right" Name="btnNext" Width="80" Click="btnNext_Click">Tovább</Button>
<StatusBar DockPanel.Dock="Bottom">
<StatusBar.ItemsPanel>
<ItemsPanelTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="auto"/>
<ColumnDefinition Width="auto"/>
</Grid.ColumnDefinitions>
</Grid>
</ItemsPanelTemplate>
</StatusBar.ItemsPanel>
<StatusBarItem Grid.Column="1">
<TextBlock Name="statusText"></TextBlock>
</StatusBarItem>
<StatusBarItem Grid.Column="2">
<ProgressBar Name="statusPG" Width="80" Height="18" IsEnabled="False" />
</StatusBarItem>
<StatusBarItem Grid.Column="3">
<Button Name="statusB" IsCancel="True" IsEnabled="False">Cancel</Button>
</StatusBarItem>
</StatusBar>
</DockPanel>
</Window>
Your code runs a very tight loop and at its center it calls ReportProgress().
This means that your MessageQueue is swamped with requests to execute the Progress updates.
If you build some delay (Thread.Sleep(100)) into the Bgw thread you will see the responsiveness improve.
A more practical solution is to move the reporting out to the outer loop. In your case:
for (int i = 1; i <= 30; i++)
{
int percent = (i * 100) / 30;
_worker.ReportProgress(percent);
for(int j = 0; ....)
....
}
If you only have 1 loop, build in a delay: 'if ((counter % 100) == 0) ...`
Your target here is the user, aim for between 10 and 100 calls to Reportprogress.
Your anonymous method for the ProgressChanged event will run on UI thread. since you're reporting frequent progress it will be queued up in by the dispatcher and blocks the UI.
if (current++ % onePercent == 0)
{
int percent = Convert.ToInt32(((decimal)current / (decimal)max) * 100);
this._worker.ReportProgress(percent, new WorkerUserState { current = current, max = max });
}
this works well.

Categories