I created a default form in Visual Studio 2010 and on the form design I have not changed anything. I only added following code in Form1.cs:
using System;
using System.Windows.Forms;
namespace WinFormTest1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
this.TopMost = true;
this.ShowInTaskbar = true;
this.Load += new EventHandler(Form1_Load);
this.Shown += new EventHandler(Form1_Shown);
}
void Form1_Load(object sender, EventArgs e)
{
this.Opacity = 0;
}
void Form1_Shown(object sender, EventArgs e)
{
this.Opacity = 1;
}
}
}
Starting this program the form does not appear on the taskbar. It only appears on the task bar when made active any other window, and then activating this form.
What is the reason of such behavior?
Edited:
Why do I need to set the opacity of it in handler Form1_Load?
I created class FormAppearingEffect whose code below:
using System;
using System.Diagnostics;
using System.Threading;
using System.Windows.Forms;
namespace AG.FormAdditions
{
public class FormAppearingEffect
{
private Form form;
double originalOpacity;
public FormAppearingEffect(Form form)
{
this.form = form;
form.Load += form_Load;
form.Shown += form_Shown;
}
void form_Load(object sender, EventArgs e)
{
originalOpacity = form.Opacity;
form.Opacity = 0;
}
private void form_Shown(object sender, EventArgs e)
{
try
{
double currentOpacity = 0;
form.Opacity = currentOpacity;
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
for (int i = 1; currentOpacity < originalOpacity; i++)
{
currentOpacity = 0.1 * i;
form.Opacity = currentOpacity;
Application.DoEvents();
//if processor loaded and does not have enough time for drawing form, then skip certain count of steps
int waitMiliseconds = (int)(50 * i - stopwatch.ElapsedMilliseconds);
if (waitMiliseconds >= 0)
Thread.Sleep(waitMiliseconds);
else
i -= waitMiliseconds / 50 - 1;
}
stopwatch.Stop();
form.Opacity = originalOpacity;
}
catch (ObjectDisposedException) { }
}
}
}
In any form of program I use this class like this:
using System;
using System.Windows.Forms;
using AG.FormAdditions;
namespace WinFormTest1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
FormAppearingEffect frmEffects = new FormAppearingEffect(this);
}
}
}
Thus my form appears on the screen "gradually".
This is where I found a bug, which we are in this topic.
And that's it for this reason I need to set the opacity in the event handlers.
Related
I have a ClientForm (opened from MainWindow) which has a search button which on click takes around 12 seconds to process.
During search if user has clicked on that form multiple times "Not Responding" text get appears on its title bar which is ok, but after search completes ClientForm will lose focus or will get deactivate and MainWindow will get the focus - which is an issue.
Below is the code snippet.
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
// this is a wpf window
public MainWindow()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
var cf= new ClientForm();
cf.Show();
}
}
// This is a winform
public partial class ClientForm : Form
{
public ClientForm()
{
InitializeComponent();
}
private void Search_Click(object sender, EventArgs e)
{
Cursor.Current = Cursors.WaitCursor;
// Do some processing
Thread.Sleep(12000);
Cursor.Current = Cursors.Default;
}
}
Is this a .net framework issue?
I am not using background thread for search or have not used ShowDialog to display form. Would like to know how else this can be fixed and why this issue is occurring.
Thanks!!!
Using background threads, my own example
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WindowsFormsApp2
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
backgroundWorker1.WorkerReportsProgress = true;
backgroundWorker1.WorkerSupportsCancellation = true;
button2.Enabled = false;
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
for (int i = 0; i < 100; i++)
{
if (worker.CancellationPending == true)
{
e.Cancel = true;
break;
}
else
{
backgroundWorker1.ReportProgress(i);
Thread.Sleep(100);
}
}
}
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
progressBar1.Value = e.ProgressPercentage;
}
private void button1_Click(object sender, EventArgs e)
{
if (backgroundWorker1.IsBusy != true)
{
button1.Enabled = false;
button2.Enabled = true;
label1.Text = "Runing...";
// Start the asynchronous operation.
backgroundWorker1.RunWorkerAsync();
}
}
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
button1.Enabled = true;
button2.Enabled = false;
label1.Text = "Complete";
}
private void button2_Click(object sender, EventArgs e)
{
if (backgroundWorker1.WorkerSupportsCancellation == true)
{
// Cancel the asynchronous operation.
backgroundWorker1.CancelAsync();
button1.Enabled = true;
button2.Enabled = false;
label1.Text = "Cancel";
}
}
}
}
Thanks for your help but I have got the answer to this weird behavior in below link.
https://learn.microsoft.com/en-us/windows/win32/win7appqual/preventing-hangs-in-windows-applications?redirectedfrom=MSDN
Window with "Not Responding" is not the actual window as actual one is set to hidden and thus deactivated. To resolve this, I have remove the GhostWindowFunctionality and now there is no loss of focus.
Only cons is user can not move, minimize, and close the unresponsive application but we have task manager to close/kill such app.
// This is a winform
public partial class ClientForm : Form
{
[DllImport("user32.dll")]
public static extern void DisableProcessWindowsGhosting();
public ClientForm()
{
InitializeComponent();
DisableProcessWindowsGhosting(); // This will disable it
}
private void Search_Click(object sender, EventArgs e)
{
Cursor.Current = Cursors.WaitCursor;
// Do some processing
Thread.Sleep(12000);
Cursor.Current = Cursors.Default;
}
}
Experts
I would like to shuffle windows forms automatically every after 5 mins. windows forms contains Multiple querys , Multiple videos, Multiple powerpoints.
I am having three windows forms, as follows.
Forms 1 code :
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Daily_System {
public partial class Form1: Form {
public Form1() {
InitializeComponent();
timer1.Enabled = true;
timer1.Interval = 5000;
timer1.Tick += timer1_Tick;
timer1.Start();
}
private void Form1_Load(object sender, EventArgs e) {
this.WindowState = FormWindowState.Maximized;
CenterToScreen();
}
private Timer timer1 = new Timer();
private void button1_Click_1(object sender, EventArgs e) {
this.WindowState = FormWindowState.Minimized;
Form2 f = new Form2(); // This is bad
timer2.Enabled = true;
}
private void timer2_Tick(object sender, EventArgs e) {
button1.PerformClick();
}
}
}
Forms 2: Microsoft Powerpoint file
multiple powerpoint files from network folder(path)
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using PowerPoint = Microsoft.Office.Interop.PowerPoint;
using Core = Microsoft.Office.Core;
namespace Daily_System {
public partial class Form2: Form {
public Form2() {
InitializeComponent();
this.WindowState = FormWindowState.Minimized;
timer1.Enabled = true;
timer1.Interval = 15000;
timer1.Start();
}
private void Tick(object sender, EventArgs e) {
Form3 Next = new Form3();
Next.Show();
this.Hide();
timer1.Stop(); //Stop timer after tick once
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
this.BeginInvoke(new MethodInvoker(delegate() {
button1.PerformClick();
}));
}
private void button1_Click(object sender, EventArgs e) {
Microsoft.Office.Interop.PowerPoint.Application pptApp = new Microsoft.Office.Interop.PowerPoint.Application();
Microsoft.Office.Core.MsoTriState ofalse = Microsoft.Office.Core.MsoTriState.msoFalse;
Microsoft.Office.Core.MsoTriState otrue = Microsoft.Office.Core.MsoTriState.msoTrue;
pptApp.Visible = otrue;
pptApp.Activate();
Microsoft.Office.Interop.PowerPoint.Presentations ps = pptApp.Presentations;
var opApp = new Microsoft.Office.Interop.PowerPoint.Application();
pptApp.SlideShowEnd += PpApp_SlideShowEnd;
var ppPresentation = ps.Open(# "C:\Users\ok\Downloads\Parks-WASD2017.pptx", ofalse, ofalse, otrue);
var settings = ppPresentation.SlideShowSettings;
settings.Run();
}
private void PpApp_SlideShowEnd(Microsoft.Office.Interop.PowerPoint.Presentation Pres) {
Pres.Saved = Microsoft.Office.Core.MsoTriState.msoTrue;
Pres.Close();
}
private void Form2_Load(object sender, EventArgs e) {
}
private void button2_Click(object sender, EventArgs e) {
this.WindowState = FormWindowState.Minimized;
Form3 f = new Form3(); // This is bad
f.Show(); /// f.Show();
timer1.Enabled = true;
this.Hide();
timer1.Stop(); //Stop timer after tick once
}
private void timer1_Tick_1(object sender, EventArgs e) {
button2.PerformClick();
}
}
}
Forms 3: Multiple video files (MP4,FLV,MOV,etc)
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Daily_System {
public partial class Form3: Form {
public Form3() {
InitializeComponent();
timer1.Enabled = true;
timer1.Interval = 15000;
timer1.Start();
}
private void Form3_Load(object sender, EventArgs e) {
axWindowsMediaPlayer1.settings.autoStart = true;
}
private void axWindowsMediaPlayer1_Enter_1(object sender, EventArgs e) {
axWindowsMediaPlayer1.URL = # "C:\Users\ok\Downloads\ok.mp4";
}
private void button1_Click(object sender, EventArgs e) {
this.WindowState = FormWindowState.Minimized;
Form1 f = new Form1(); // This is bad
f.Show(); /// f.Show();
timer1.Enabled = true;
this.Hide();
timer1.Stop(); //Stop timer after tick once
}
private void timer1_Tick_1(object sender, EventArgs e) {
button1.PerformClick();
}
}
}
Multiple video files from network folder(Path)
Requirement:
Each forms should change and display every after 5 min.
example : first form1 should display then after 5 mins form1 should minimized and form2 should show the slideshow and then after 5 mins form2 should minimized and form3 should play the video and then after 5 mins form3 should minimized and pause the video then form1 should display.
It should keep doing the same steps as above.
Final condition: All forms should stop exactly at 6 pm(Everyday) and it should start automatically at 7 am (Everyday).
Please advise...
One way is to create base class for forms to control minimizing and maximizing of them and also finding out when the specific form being minimized or maximized by overriding OnStart() and OnStop() methods. This can be done as follow:
Define new base class named CustomForm:
public class CustomForm : Form
{
public static List<CustomForm> AllForms = new List<CustomForm>();
private static int CurrentFormIndex = 0;
private static Timer SliderTimer = new Timer() { Interval = 5000 }; // { Interval = 5 * 60000 };
public static void Start(params CustomForm[] forms)
{
AllForms.AddRange(forms);
forms[0].Show();
forms[0].WindowState = FormWindowState.Maximized;
AllForms[0].OnStart(AllForms[0]);
SliderTimer.Tick += SliderTimer_Tick;
SliderTimer.Start();
}
private static void SliderTimer_Tick(object sender, EventArgs e)
{
SliderTimer.Stop();
// Minimizing current form
AllForms[CurrentFormIndex].OnStop(AllForms[CurrentFormIndex]);
AllForms[CurrentFormIndex].WindowState = FormWindowState.Minimized;
// Maximizing next form
int NextFormIndex = (CurrentFormIndex + 1) % AllForms.Count;
if (!AllForms[NextFormIndex].Visible)
AllForms[NextFormIndex].Show();
AllForms[NextFormIndex].WindowState = FormWindowState.Maximized;
AllForms[NextFormIndex].OnStart(AllForms[NextFormIndex]);
CurrentFormIndex = NextFormIndex;
SliderTimer.Start();
}
// Application will exits when one of forms being closed
protected override void OnFormClosed(FormClosedEventArgs e)
{
base.OnFormClosed(e);
Application.Exit();
}
// For overriding in forms to Start something such as playing or etc
protected virtual void OnStart(CustomForm Sender)
{
}
// For overriding in forms to Stop something such as playing or etc
protected virtual void OnStop(CustomForm Sender)
{
}
}
Change Program class as follow:
static class Program
{
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
CustomForm.Start(new Form1(), new Form2(), new Form3());
Application.Run();
}
}
Change your forms to inherit CustomForm instead of Form as follow:
public partial class Form1 : CustomForm
{
public Form1()
{
InitializeComponent();
}
private void Form1_Shown(object sender, EventArgs e)
{
// axWindowsMediaPlayer1.URL = #"C:\Users\ok\Downloads\ok.mp4";
WMPLib.IWMPMedia v1 = axWindowsMediaPlayer1.newMedia(#"d:\1.mp4");
axWindowsMediaPlayer1.currentPlaylist.appendItem(v1);
WMPLib.IWMPMedia v2 = axWindowsMediaPlayer1.newMedia(#"d:\2.mp4");
axWindowsMediaPlayer1.currentPlaylist.appendItem(v2);
WMPLib.IWMPMedia v3 = axWindowsMediaPlayer1.newMedia(#"d:\3.mp4");
axWindowsMediaPlayer1.currentPlaylist.appendItem(v3);
}
// To start playing video and etc when form being maximized
protected override void OnStart(CustomForm Sender)
{
axWindowsMediaPlayer1.Ctlcontrols.play();
}
// To stop playing video and etc when form being minimized
protected override void OnStop(CustomForm Sender)
{
axWindowsMediaPlayer1.Ctlcontrols.pause();
}
}
Form2:
public partial class Form2 : CustomForm
{
Microsoft.Office.Interop.PowerPoint.Presentation ppPresentation;
Microsoft.Office.Interop.PowerPoint.SlideShowSettings settings;
Microsoft.Office.Interop.PowerPoint.Application opApp;
int StartingSlide = 1;
public Form2()
{
InitializeComponent();
}
protected override void OnStart(CustomForm Sender)
{
Microsoft.Office.Interop.PowerPoint.Application pptApp = new Microsoft.Office.Interop.PowerPoint.Application();
Microsoft.Office.Core.MsoTriState ofalse = Microsoft.Office.Core.MsoTriState.msoFalse;
Microsoft.Office.Core.MsoTriState otrue = Microsoft.Office.Core.MsoTriState.msoTrue;
pptApp.Visible = otrue;
pptApp.Activate();
Microsoft.Office.Interop.PowerPoint.Presentations ps = pptApp.Presentations;
opApp = new Microsoft.Office.Interop.PowerPoint.Application();
opApp.SlideShowNextSlide += OpApp_SlideShowNextSlide;
ppPresentation = ps.Open(#"c:\a.pptx", ofalse, ofalse, otrue);
settings = ppPresentation.SlideShowSettings;
settings.RangeType = Microsoft.Office.Interop.PowerPoint.PpSlideShowRangeType.ppShowSlideRange;
settings.StartingSlide = StartingSlide;
settings.Run();
}
private void OpApp_SlideShowNextSlide(Microsoft.Office.Interop.PowerPoint.SlideShowWindow Wn)
{
StartingSlide = Wn.View.CurrentShowPosition;
}
protected override void OnStop(CustomForm Sender)
{
ppPresentation.Close();
//opApp.Quit();
Process.Start("cmd", "/c taskkill /im POWERPNT.EXE");
}
}
There are a lot of possible ways to do this. Winforms is a Lego box and lets you snap the pieces together any way you want. Deriving your own class from one of the built-in winforms classes is a basic strategy. What you need is a little controller that takes care of the form switching. Best kind of class to override is ApplicationContext. The default one you get is a very simple one that merely ensures that the main form is shown and terminates the app when you close it.
Let's derive our own. This is a potentially heavy-weight app, these are not cheap forms. So we want to specify the forms to switch by their Type instead of their instance, creating and destroying them when the forms gets switched. You'll want the app to terminate whenever the current one is closed by the user. Copy/paste this code into the Program.cs file:
class FormSwitcher : ApplicationContext {
Timer switcher;
Type[] forms;
int formIndex;
Form currentForm;
bool switching;
public FormSwitcher(params Type[] forms) {
this.forms = forms;
switcher = new Timer() { Enabled = true };
switcher.Interval = System.Diagnostics.Debugger.IsAttached ? 3000 : 5 * 60000;
switcher.Tick += SwitchForm;
formIndex = -1;
SwitchForm(this, EventArgs.Empty);
}
private void SwitchForm(object sender, EventArgs e) {
switching = true;
formIndex += 1;
if (formIndex >= forms.Length) formIndex = 0;
var newform = (Form)Activator.CreateInstance(forms[formIndex]);
newform.FormClosed += delegate { if (!switching) this.ExitThread(); };
if (currentForm != null) {
newform.StartPosition = FormStartPosition.Manual;
newform.Bounds = currentForm.Bounds;
}
newform.Show();
if (currentForm != null) currentForm.Close();
currentForm = newform;
switching = false;
}
}
Hopefully it is obvious what it does, if not then let me know and I'll add comments. Now you can modify the Main() method in that same file, you pass an instance of this class to the Application.Run() method. I'll copy/paste the code I tested:
[STAThread]
static void Main() {
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new FormSwitcher(typeof(Form1), typeof(Form2)));
}
Here is sample code that creates the 3 forms, then every 5 seconds switches which is maximized (others are minimized). The application exits when any form is closed. I've put comments throughout, and following it is code you can use to pause playback on forms:
internal static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
private static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
//here we create our 3 forms. note, you can create and show as many as you want here
//the application will automatically loop through them
new Form1().Show();
new Form2().Show();
new Form().Show();
//minimize all forms, and set a close handler
foreach (Form form in Application.OpenForms)
{
form.WindowState = FormWindowState.Minimized;
form.FormClosed += Form_FormClosed;
}
//start a thread to manage switching them
Task.Run((Action)Go);
//start the main UI thread loop
Application.Run();
}
private static void Go()
{
while (true)
{
//loop through all forms
foreach (Form form in Application.OpenForms)
{
//show it (send execution to UI thread)
form.Invoke(new MethodInvoker(() =>
{
form.Show();
form.WindowState = FormWindowState.Maximized;
}));
//wait 5 seconds
Thread.Sleep(5000);
//minimize it (send execution to UI thread)
form.Invoke(new MethodInvoker(() =>
{
form.WindowState = FormWindowState.Minimized;
}));
}
}
}
private static void Form_FormClosed(object sender, FormClosedEventArgs e)
{
Application.Exit();
}
}
Now for forms that need to take action when minimized/maximized, add a Resize handler like this into the code on the form:
private void Form1_Resize(object sender, EventArgs e)
{
if (WindowState == FormWindowState.Minimized)
{
//stop any playback
} else
{
//start any playback
}
}
For a school project I am creating a pong game connected to the arduino, where if you hold a button pressed the racket moves in one direction and if you don't it moves in the other. The game works fine if I don't use arduino data as an input. I tried using different functions but it doesnt work.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO.Ports;
namespace pong
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
}
}
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO.Ports;
namespace pong
{
public partial class Form1 : Form
{
SerialPort port1 = new SerialPort();
public int points = 0;
public int speed_left = 0;
public int speed_top = 0;
public Form1()
{
InitializeComponent();
timer1.Enabled = true;
Cursor.Hide(); //skrije kurzor
this.TopMost = true;
this.Bounds = Screen.PrimaryScreen.Bounds;
this.FormBorderStyle = FormBorderStyle.None;
racket.Top = panel1.Bottom - (panel1.Bottom / 10);
SerialPort port1 = new SerialPort("COM3");
port1.BaudRate = 9600;
port1.Parity = Parity.None;
port1.StopBits = StopBits.One;
port1.DataBits = 8;
port1.Handshake = Handshake.None;
port1.RtsEnable = true;
port1.Open();
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void timer1_Tick(object sender, EventArgs e)
{
if(!port1.IsOpen)
{
port1.Open();
port1.ReadTimeout = 1000;
}
if (port1.IsOpen)
{
if (port1.ReadExisting()=="")
{
racket.Left = racket.Left - 0;
}
else
{
racket.Left = racket.Left + 10;
}
}
ball.Left += speed_left;
ball.Top += speed_top;
if(ball.Bottom >=racket.Top && ball.Bottom <= racket.Bottom && ball.Left >= racket.Left && ball.Right <= racket.Right)
{
speed_left += 2;
speed_top += 2;
speed_top = -speed_top;
points += 1;
label2.Text = points.ToString();
}
if(ball.Left<=panel1.Left)
{
speed_left = -speed_left;
}
if (ball.Right >= panel1.Right)
{
speed_left = -speed_left;
}
if(ball.Top <= panel1.Top)
{
speed_top = -speed_top;
}
if(ball.Bottom>=panel1.Bottom)
{
timer1.Enabled=false;
}
}
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
if(e.KeyCode==Keys.Escape)
{
this.Close();
}
}
private void label1_Click(object sender, EventArgs e)
{
}
}
}
arduino:
void setup() {
// put your setup code here, to run once:
pinMode(8,INPUT);
digitalWrite(8,LOW);
}
void loop() {
Serial.begin(9600);
while(1){
if(digitalRead(8)==HIGH)
{
Serial.write('1');
}
}
}
I would suggest putting a breakpoint in timer1_Tick, I suspect it is not going to be called at all because you haven't called
timer1.Start();
to start the timer.
I am learning backgroundworker class in WPF. The code below is in file MainWindow.xaml.cs
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 System.ComponentModel;
namespace FrontEnd
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private BackgroundWorker backGroundWorker;
public MainWindow()
{
InitializeComponent();
backGroundWorker = ((BackgroundWorker)this.FindResource("backgroundWorker"));
}
private void button1_Click(object sender, RoutedEventArgs e)
{
button1.IsEnabled = false;
Flow pro = new Flow(20,10);
backGroundWorker.RunWorkerAsync(pro);
}
private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
Flow pro = (Flow)e.Argument;
e.Result = pro.NaturalNumbers();
}
private void backgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
progressBar1.Value= e.ProgressPercentage;
}
private void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if ((int)e.Result == 1) MessageBox.Show("DONE");
progressBar1.Value = 0;
}
}
}
The code below is in file Flow.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
namespace FrontEnd
{
class Flow
{
long i;
//private int x,y;
public int X
{
get; set;
}
public int Y
{
get; set;
}
public Flow(int x, int y)
{
X = x;
Y = y;
}
public int NaturalNumbers()
{
for (i = 0; i < 9999; i++)
{
Console.WriteLine(i);
long iteration = i * 100 / 9999;
if ((i % iteration == 0) &&
(backgroundWorker != null) && backgroundWorker.WorkerReportsProgress)
{
backgroundWorker.ReportProgress(iteration);
}
}
return 1;
}
}
}
Error : The name 'backgroundWorker' does not exist in the current
context
How can I make progress bar working?
Here's a simple example that works:
public partial class BackgroundWorkerPage : Page
{
private readonly BackgroundWorker _worker = new BackgroundWorker();
public BackgroundWorkerPage()
{
InitializeComponent();
_worker.DoWork += WorkerOnDoWork;
_worker.WorkerReportsProgress = true;
_worker.ProgressChanged += WorkerOnProgressChanged;
}
private void WorkerOnProgressChanged(object sender, ProgressChangedEventArgs progressChangedEventArgs)
{
progressBar.Value = progressChangedEventArgs.ProgressPercentage;
}
private void WorkerOnDoWork(object sender, DoWorkEventArgs doWorkEventArgs)
{
for (int i = 0; i <= 100; i++)
{
Thread.Sleep(50);
_worker.ReportProgress(i);
}
}
private void Button_Click_1(object sender, System.Windows.RoutedEventArgs e)
{
_worker.RunWorkerAsync();
}
}
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<ProgressBar x:Name="progressBar" Height="23" Minimum="0" Maximum="100"/>
<Button Grid.Row="1" Height="23" Content="Start" Click="Button_Click_1"/>
</Grid>
And you need to change your code a bit
private void WorkerOnDoWork(object sender, DoWorkEventArgs doWorkEventArgs)
{
var flow = new Flow(_worker);
flow.NaturalNumbers();
}
internal class Flow
{
private readonly BackgroundWorker _worker;
public Flow(int x, int y)
{
X = x;
Y = y;
}
public Flow(BackgroundWorker worker)
{
_worker = worker;
}
public int X { get; set; }
public int Y { get; set; }
public int NaturalNumbers()
{
for (int i = 0; i <= 9999; i++)
{
int iteration = i*100/9999;
// your if(...) fails with divide by zero exception
_worker.ReportProgress(iteration);
}
return 1;
}
}
Introduction
Whenever we try to do some long running operation on the UI without freezing it, we need to run it in a separate thread.In this article we will look into the BackgroundWorker class , as one of the various solutions to this problem with a simple example. BackgroundWorker executes an operation on a separate thread and provide a notification to UI Thread whenever necessary.
Straight To Experiment
Let us create a UI as under
The objective is that,when we will click on the "Populate" button, at the same time we should be able to write something in the "Textbox".
Now let us look into the code which is without BackgroundWorker
public partial class WithOutBackgroundThread : Form
{
List<Employee> lstEmp;
public WithOutBackgroundThread()
{
InitializeComponent();
lstEmp = new List<Employee>();
}
private void btnPopulate_Click(object sender, EventArgs e)
{
GetEmployeeRecords();
dataGridView1.DataSource = lstEmp;
lblStatus.Text = "Work Completed";
}
//Prepare the data
private void GetEmployeeRecords()
{
for (int i = 1; i <= 10; i++)
{
// Simulate a pause
Thread.Sleep(1000);
lstEmp.Add(new Employee { EmpId = i, EmpName = "Name" + i });
}
}
}
The code is pretty straightforward.In the "GetEmployeeRecords()" method, we are preparing the data.We have introduce the "Thread.Sleep(1000)" to make a delay. And in the "Populate" button click event, we are populating the Gird.
But if we execute this code, the UI will become unresponsive and henceforth, we cannot perform any task on the "Textbox" which is our objective.
Henceforth let us change our code to the below
public partial class WithBackgroundThread : Form
{
BackgroundWorker workerThread;
List<Employee> lstEmp;
public WithBackgroundThread()
{
InitializeComponent();
lstEmp = new List<Employee>();
workerThread = new BackgroundWorker();
workerThread.DoWork += new DoWorkEventHandler(workerThread_DoWork);
workerThread.RunWorkerCompleted += new RunWorkerCompletedEventHandler(workerThread_RunWorkerCompleted);
}
private void btnPopulate_Click(object sender, EventArgs e)
{
workerThread.RunWorkerAsync();
}
private void workerThread_DoWork(object sender, DoWorkEventArgs e)
{
GetEmployeeRecords();
}
private void workerThread_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
lblStatus.Text = "Work Completed";
dataGridView1.DataSource = lstEmp;
}
//Prepare the data
private void GetEmployeeRecords()
{
for (int i = 1; i <= 10; i++)
{
// Simulate a pause
Thread.Sleep(1000);
lstEmp.Add(new Employee { EmpId = i, EmpName = "Name" + i });
}
}
}
A lot of new things.We will explore one by one.
First, we need to declare BackgroundWorker Thread
BackgroundWorker workerThread = new BackgroundWorker();
Next,we need to subscribe to the events
workerThread.DoWork += new DoWorkEventHandler(workerThread_DoWork);
workerThread.RunWorkerCompleted += new RunWorkerCompletedEventHandler(workerThread_RunWorkerCompleted);
As a third step, we need to implement the two methods
private void workerThread_DoWork(object sender, DoWorkEventArgs e)
{
// run all background tasks here
GetEmployeeRecords();
}
private void workerThread_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
//update ui once worker complete its work
lblStatus.Text = "Work Completed";
dataGridView1.DataSource = lstEmp;
}
The "DoWork" event is raised when we call the "RunWorkerAsync" method. This is where we start the operation that performs the potentially time-consuming work.The "RunWorkerCompleted" event is fired when the background operation has completed, has been canceled, or has raised an exception
As a last step, invoke the "RunWorkerAsync" from the "Populate" button click event.
private void btnPopulate_Click(object sender, EventArgs e)
{
workerThread.RunWorkerAsync();
}
The "RunWorkerAsync" starts execution of a background operation.
Now if we run our application we will be able to populate the grid as well as write something on the "Textbox".
Thanks
I have a problem with C# multi-threading.
Form contents are two buttons and two lables.
If I press on the first button, going looping from 1..to 60000, to update label1. ( It works)
If I press on the second button, going looping from 1..to 6000 to update label2,(and my form is lagged). (is not responding)
Please help!
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;
namespace ThreadTest
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
Thread thread = new Thread(new ThreadStart(countNumbers));
thread.IsBackground = true;
thread.Start();
}
private void button2_Click(object sender, EventArgs e)
{
Thread thread2 = new Thread(new ThreadStart(countNumbers2));
thread2.Start();
}
public void countNumbers()
{
try
{
for (int i = 0; i < 60000; i++)
{
this.Invoke((MethodInvoker)delegate()
{
label2.Text = "" + i.ToString();
}
);
}
}
catch (Exception e)
{
}
}
public void countNumbers2()
{
try
{
for (int i = 0; i < 60000; i++)
{
this.Invoke((MethodInvoker)delegate()
{
label4.Text = "" + i.ToString();
}
);
}
}
catch (Exception e)
{
}
}
private void label3_Click(object sender, EventArgs e)
{
}
}
}
Try using a Forms.Timer in the form and poll a value at regular intervals to update the label in a controlled way. Updating the UI the way you do puts way to much load on the system.
A System.Windows.Forms.Timer runs on the GUI thread.
Just make sure to guard the shared resource in some way, this example uses a volatile member to handle thread synchronization.
You do not need the extra Thread.Sleep(10), it is just there to simulate some load.
private volatile int _counter;
private readonly Timer _timer = new System.Windows.Forms.Timer();
public Form1()
{
InitializeComponent();
_timer.Tick += TimerTick;
_timer.Interval = 20; // ~50 Hz/fps
_timer.Start();
}
void TimerTick(object sender, EventArgs e)
{
_label.Text = _counter.ToString();
}
private void Form1_Load(object sender, EventArgs e)
{
Thread thread = new Thread(CountNumbers) {IsBackground = true};
thread.Start();
}
public void CountNumbers()
{
for (int i = 0; i < 60000; i++)
{
_counter++;
Thread.Sleep(10); // <-- Simulated work load
}
}
Of course, you can easily expand this example to fit your example with two different counters, calculated on separate threads but still using only one Timer to update the entire UI.
You end up with lagging because Invoke (switching to another thread) is very expensive operation and you are calling it too frequently
Try giving this.Refresh() or Application.DoEvents() in your loop
Try to use lock statement
lock (this)
{
label2.Text = "" + i.ToString();
}
you shoud change your code to
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;
namespace WindowsFormsApplication23
{
public partial class Form3 : Form
{
public Form3()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
Thread thread = new Thread(new ThreadStart(countNumbers));
thread.IsBackground = true;
thread.Start();
}
private void button2_Click(object sender, EventArgs e)
{
Thread thread2 = new Thread(new ThreadStart(countNumbers2));
thread2.Start();
}
public void countNumbers()
{
try
{
for (int i = 0; i < 60000; i++)
{
this.Invoke((MethodInvoker)delegate()
{
lock (this)
{
label2.Text = "" + i.ToString();
}
}
);
}
}
catch (Exception e)
{
}
}
public void countNumbers2()
{
try
{
for (int i = 0; i < 60000; i++)
{
this.Invoke((MethodInvoker)delegate()
{
lock (this)
{
label4.Text = "" + i.ToString();
}
}
);
}
}
catch (Exception e)
{
}
}
private void label3_Click(object sender, EventArgs e)
{
}
}
}
Put some synchronization mechanism there
You can use
1.lock(this);
2.monitor.enter(obj); and monitor.exit(obj);
lock (this){
label2.Text = "" + i.ToString();
}
monitor.enter(obj);
label2.Text = "" + i.ToString();
monitor.exit(obj);