Periodic printing of shapes - c#

I am making an application using WPF and C#. What I'm trying to do is to print a lots of shapes on a canvas with some time in between when I push a button. At the moment when I push the button, everything just pops up at once. I have tried to sleep the thread for some time between every "print" but that doesn't help, it just take longer time before everything splash up at once. What I want to achive is that the shapes pop up one at a time with lets say 0.5 seconds in between. The code is the following:
private void Create_Click(object sender, RoutedEventArgs e)
{
Random random = new Random();
for (int i = 0; i < 50; i++)
{
Thread.Sleep(500);
Path f = FlowerFactory.createFlower(FlowerBP, true);
Canvas.SetLeft(f, random.Next(0, 1650));
Canvas.SetTop(f, random.Next(0,1000));
DrawBoard.Children.Add(f);
}}

You need to, first, run the loop in a background thread so that it doesn't block the UI from updating; and second, send the UI-rendering tasks back to the UI thread. For the first, you can use Task.Factory.StartNew, and for the second, use Dispatcher.Invoke:
Random random = new Random();
Task.Factory.StartNew(() =>
{
for (int i = 0; i < 50; i++)
{
Thread.Sleep(500);
Dispatcher.Invoke(DispatcherPriority.Render, new Action(() =>
{
Path f = FlowerFactory.createFlower(FlowerBP, true);
Canvas.SetLeft(f, random.Next(0, 1650));
Canvas.SetTop(f, random.Next(0,1000));
DrawBoard.Children.Add(f);
}));
}
});

It was bad decision to sleep your main thread that responsible for GUI.
Try to use DispatchTimer. For example:
DispatcherTimer m_dispatcherTimer = new DispatcherTimer();
int m_count = 50;
private void Init()
{
m_dispatcherTimer.Tick += new EventHandler(OnTick);
m_dispatcherTimer.Interval = new TimeSpan(0, 0, 1);
}
private void Create_Click(object sender, RoutedEventArgs e)
{
m_count = 50;
m_dispatcherTimer.Start();
}
private void OnTick(object sender, EventArgs e)
{
// Draw your shapes here
if(0>=--m_count)
{
m_dispatcherTimer.Stop();
}
}

using System.Reactive.Concurrency;
using System.Reactive.Linq;
...
var subscription = Observable.Interval(TimeSpan.FromSeconds(0.5)).Take(50).Subscribe(x=>CreateRandomFlower);

Related

Progress bar is jumping

When I start program, I need to load some projects and init them. So I make that all in Thread and create a progress bar (next PB). When loading is started everythink is OK, but in one moment PB is stop and jump to end when init will end.
Here Thread which add to progress bar every init bLock.
public void initMapBlocks(int n, int m)
{
this.Dispatcher.Invoke(delegate ()
{
Loader.Visibility = Visibility.Visible;
mainWindow.Visibility = Visibility.Hidden;
});
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
{
this.Dispatcher.Invoke(delegate ()
{
MapPart mp = new MapPart();
mainCanvas.Children.Add(mp);
Loader.addPoint(1);
});
}
}
this.Dispatcher.Invoke(delegate ()
{
Loader.Visibility = Visibility.Hidden;
mainWindow.Visibility = Visibility.Visible;
});
}
Did it`s possible to get full animation?
-------- Update --------
Here code where i add to progress bar value.
public void addPoint(int x)
{
itemCountAlready += x;
loaderBar.Value += x;
}
----- Update 2 -------
private void Window_Loaded(object sender, RoutedEventArgs e)
{
Thread thread = new Thread(new ThreadStart(() => initMapBlocks(100, 100)));
thread.Start();
}
Your initMapBlocks method produces (MapPart) and consumes (adds loader's value and mainCanvas children) at the same time. You can separate by using System.Collections.Generic.Queue
You can define your queue like this
private Queue<MapPart> myQueue = new Queue<MapPart>();
Instead of these guys
mainCanvas.Children.Add(mp);
Loader.addPoint(1);
You can write simply this for produce
myQueue.Enqueue(mp);
And you can define a DispatcherTimer in your constructor for consume
DispatcherTimer myTimer = new DispatcherTimer {
Interval = TimeSpan.FromMilliseconds(1)
};
myTimer.Tick += Consume;
myTimer.Start();
Your Consume method
private void Consume(object sender, EventArgs args) {
if (myQueue.Count > 0) {
//you don't need `this.Dispatcher.Invoke(delegate...` too
loaderBar.Value += myQueue.Dequeue();
mainCanvas.Children.Add(mp);
}
}

c# Fill textbox while listbox is being filled

This is my code:
private void _1_Load(object sender, EventArgs e)
{
FillA();
FillB();
// Tried these lines too but they show listbox values but not textbox value
// var t2 = Task.Run(() => FillA());
// FillB();
}
private void FillA()
{
this.Invoke(new MethodInvoker(delegate()
{
for (int i = 1; i > 0; i++)
{
listBox1.Items.Add(i.ToString());
listBox1.Update();
Thread.Sleep(25);
}
}));
}
private void FillB()
{
Thread.Sleep(3000); //1 seconds delay
textBox1.Text = "Hello World!";
}
When the page loads the listbox should starts showing the number 1, 2, 3... and then after few seconds of delay the textbox should show the Hello World! value but the listbox should keep growing. How do I ensure that first the listbox should start filling and then the textbox should fill. I don't want to wait for the filling of the listbox and then textbox to be filled.
Any advice would be appreciated.
Edit:
This is just a sample code. In actual production there would be two processes and the second process will start once the first process is started fetching data and storing in listbox.
The first process should keep on going. I can't stop it in middle as it would create inconsistency in the data.
Don't use Sleep. Instead use Timer-class:
https://msdn.microsoft.com/en-us/library/system.timers.timer(v=vs.110).aspx
Configure a timeout of 1s.
Hook up the Elapsed event for the timer:
aTimer.Elapsed += OnTimedEvent;
In method OnTimedEvent you can increment a integer-variable i.
Depending on value of i you fill first listbox and if value is higher fill the other Listbox.
You cannot add all items at once to the listbox and update the textbox in between as these operations are done synchronously in WindowsForms.
Instead you should add only a subset of items to the listbox, update the textbox and then continue adding items to the listbox.
To not freeze the GUI in between waiting for operations, you can use async\await combination instead of Thread.Sleep().
private async void _1_Load(object sender, EventArgs e)
{
await AddInitialListBoxItems();
await FillTextBox();
await AddRemainingListBoxItems();
}
private async Task AddInitialListBoxItems()
{
for (int i = 1; i < 10; i++)
{
listBox1.Items.Add(i.ToString());
listBox1.Update();
await Task.Delay(25);
}
}
private async Task FillTextBox()
{
await Task.Delay(3000); //1 seconds delay
textBox1.Text = "Hello World!";
}
private async Task AddRemainingListBoxItems()
{
for (int i = 11; i < 100; i++)
{
listBox1.Items.Add(i.ToString());
listBox1.Update();
await Task.Delay(25);
}
}
If you can use Timers instead of direct threading, this might help you. It worked on my pc:
Edit since you need the textbox to get written after some delay, you need to use a timer for it as well. I have edited the code below. Textbox is written after 1 seconds of listbox population starting.
public partial class Form1 : Form
{
int counter = 0;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
System.Windows.Forms.Timer timer = new System.Windows.Forms.Timer();
timer.Interval = 25;
timer.Tick += Timer_Tick;
timer.Start();
System.Windows.Forms.Timer timerTextbox = new System.Windows.Forms.Timer();
timerTextbox.Interval = 1000;
timerTextbox.Tick += TimerTextbox_Tick; ;
timerTextbox.Start();
}
private void TimerTextbox_Tick(object sender, EventArgs e)
{
FillB();
(sender as System.Windows.Forms.Timer).Stop();
}
private void Timer_Tick(object sender, EventArgs e)
{
listBox1.Items.Add(counter.ToString());
counter++;
listBox1.Update();
}
private void FillB()
{
textBox1.Text = "Hello World!";
}
}
Of course when you call Thread.Sleep(3000); //1 seconds delay on Load event (3000 ms is 3 seconds btw), your form will be shown 3 seconds late.

ShowDialog method without blocking other windows in WPF

I write program for sorting music.
For saving your time and better understanding of my issue,i will write short.
Here is my problem.
I have some cycle in MainMethod.
Here is cycle
private void OkButton(object sender, RoutedEventArgs e)//when i press ok button in Main window i run cycle
{
for (int i = 0; i < 50; i++)
{
//do something.
Window window1 = new Window();
window1.ShowDialog();//if i use ShowDialog it blocks MainWindow.
//window1.Show();if i use Show it continues creating new windows. in cycle.
}
}
So i need to delay executing MainWindow OkButton method,while window1 is opened.Without blocking Main Window.
You can use async/await and a semaphore along these lines:
private async void Button_Click(object sender, RoutedEventArgs e)
{
var signal = new SemaphoreSlim(0, 1);
for (int i = 0; i < 10; i++)
{
var window = new Window();
window.Closed += (s, _) => signal.Release();
window.Show();
await signal.WaitAsync();
}
}

Update multiple pictureboxes at the same time

I have four PictureBoxes (each PictureBox represents one dice) and a Timer that changes every 100ms source pictures (loaded in memory as List<Bitmap> imagesLoadedFromIncludedResources).
Code:
private List<PictureBox> dices = new List<PictureBox>();
private void timer_diceImageChanger_Tick(object sender, EventArgs e)
{
foreach (PictureBox onePictureBox in dices)
{
oneDice.WaitOnLoad = false;
onePictureBox.Image = //... ;
oneDice.Refresh();
}
}
I need to change all the images at once - at this moment, you can see that the images are changing from left to right with a small delay.
I tried variant with one Thread for each PictureBox (using Control.Invoke method from this answer) - it is visually little better but not perfect.
You can try to suspend form's layout logic:
SuspendLayout();
// set images to pictureboxes
ResumeLayout(false);
Parallel.ForEach
(
dices,
new ParallelOptions { MaxDegreeOfParallelism = 4 },
(dice) =>
{
dice.Image = ...;
dice.WaitOnLoad = false;
dice.Refresh();
}
);
The problem is that UI controls can only be accessed from the UI thread. If you want to use this approach, you must create a copy of your PictureBoxes and then replace the UI ones once the operation is done.
Another approach would be creating two PictureBoxes, with the first one just on the top of the other one (hiding the latter)... you change all the images and then, once the processing is complete, you iterate all the ones in the back putting them on the top which would result in a lesser delay.
I'd approach this differently - it's been a while since I've played with WinForms stuff, but I'd probably take more control over the rendering of the images.
In this example I've got the images all in one source bitmap stacked vertically, stored as a resource in assembly:
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
private Timer timer;
private Bitmap dice;
private int[] currentValues = new int[6];
private Random random = new Random();
public Form1()
{
InitializeComponent();
this.timer = new Timer();
this.timer.Interval = 500;
this.timer.Tick += TimerOnTick;
this.dice = Properties.Resources.Dice;
}
private void TimerOnTick(object sender, EventArgs eventArgs)
{
for (var i = 0; i < currentValues.Length; i++)
{
this.currentValues[i] = this.random.Next(1, 7);
}
this.panel1.Invalidate();
}
private void button1_Click(object sender, EventArgs e)
{
if (this.timer.Enabled)
{
this.timer.Stop();
}
else
{
this.timer.Start();
}
}
private void panel1_Paint(object sender, PaintEventArgs e)
{
e.Graphics.Clear(Color.White);
if (this.timer.Enabled)
{
for (var i = 0; i < currentValues.Length; i++)
{
e.Graphics.DrawImage(this.dice, new Rectangle(i * 70, 0, 60, 60), 0, (currentValues[i] - 1) * 60, 60, 60, GraphicsUnit.Pixel);
}
}
}
}
}
The source is here if it helps: http://sdrv.ms/Wx2Ets

C# Threading - an array of threads, where each thread contains a form with an image

I have an array of five threads. Each thread contains the same form, each form is put on to the screen in a different location (still working on that method :P).
I am trying to have each form load its contents (an image) before the other forms have finishing being placed. At the moment this works for the first form, but the others are blank or disappear :P
Originally each form would be placed but the method would need to finish before all the forms contents were displayed.
Any help would be appreciated, thanks :)
public partial class TrollFrm : Form
{
int number = 0;
public TrollFrm()
{
InitializeComponent();
startThreads();
}
private void TrollFrm_Load(object sender, EventArgs e)
{
}
private void TrollFrm_FormClosing(object sender, FormClosingEventArgs e)
{
e.Cancel = true;
}
public void startThreads()
{
Thread[] ThreadArray = new Thread[5];
for (int i = 0; i < 5; i++)
{
ThreadArray[i] = new Thread(new ThreadStart(createForm));
ThreadArray[i].Start();
}
}
public void createForm()
{
Form frm = new TrollChildFrm();
Random randomX = new Random();
Random randomY = new Random();
number++;
int xValue;
int yValue;
if (number % 2 == 0) //number is even.
{
xValue = (Convert.ToInt32(randomX.Next(1, 1920))) + 200;
yValue = (Convert.ToInt32(randomY.Next(1, 1080))) - 200;
}
else //number is not even.
{
xValue = (Convert.ToInt32(randomX.Next(1, 1920))) - 200;
yValue = (Convert.ToInt32(randomY.Next(1, 1080))) + 200;
}
frm.Show();
frm.Location = new Point(xValue, yValue);
Thread.Sleep(1000);
}
Your forms are not displaying correctly because they are not running on a thread with a message loop. The general rule is that all UI element accesses must occur on the main UI thread.
Since you have a call to Thread.Sleep(1000) I am going to assume that you want to wait 1 second between the initial display of each form. In that case I would use a System.Windows.Forms.Timer who's Tick event will call createForm directly. Enable the timer, let 5 Tick events come through, and then disable the timer. I see no need to create any threads at all.
The reason your forms aren't displaying is because you are running inside one method on the main UI thread. Instead, you could create a method that spawns a new form and launch that at certain intervals on another thread (making sure the form handling is done on the main UI thread). So you could do something like:
(Pseudo Code)
private const int TIME_THRESHOLD = 100;
int mElapsedTime = 0;
Timer mTimer = new Timer();
.ctor
{
mTimer.Elapsed += mTimer_Elapsed;
}
private void mTimer_Elapsed(...)
{
mElapsedTime++;
if (mElapsedTime >= TIME_THRESHOLD)
{
mElapsedTime = 0;
SpawnForm();
}
}
private void SpawnForm()
{
// Make sure your running on the UI thread
if (this.InvokeRequired)
{
this.BeginInvoke(new Action(SpawnForm));
return;
}
// ... spawn the form ...
}
This is just an example of what I was proposing - it would not look exactly like this in the code, but this should give you an idea of the execution steps.
I would suggest to use Thread.Sleep(1000) in this manner
Caller section
for (int i = 0; i < 5; i++)
{
ThreadArray[i] = new Thread(new ThreadStart(createForm));
ThreadArray[i].Start();
}
Thread.Sleep(1000);
Also in the method that executing the work for the thread.
while(!something)
{
Thread.Sleep(1000)
}

Categories

Resources