hi, i have send form context to another class to run function there, but the fun show out the messagebox but not update form text , why ?
i need the function start to update form title
i sending form context to timer class as parameter
the function start work in interval but the method cant update the
form control
this is form class
using System;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WindowsFormsApplication8
{
public partial class Form1 : Form
{
public Form1()
{
//form constractor
InitializeComponent();
}
timer mytimer;
private void Form1_Load(object sender, EventArgs e)
{
}
private void Elipse()
{ //the code for timer :) //yazeed coding
//MessageBox.Show(" ");
this.Text=" jkghjg";
}
private void button1_Click(object sender, EventArgs e)
{
mytimer = new timer();
mytimer.elipse += Elipse;
mytimer.Interval = 1000;
mytimer.start(this);
}
}
}
this is timer class
class timer
{
bool isstart;
public delegate void Del();
public Del elipse;
public static void UserRep() { }
public bool Enable { get; set; }
public int Interval { get; set; }
public timer()
{
Enable = false;
Interval = 1000;//default is 1 sec
isstart = false;
elipse = new Del(UserRep);
}
public void start(Form Context)
{
Context.BeginInvoke((MethodInvoker)async delegate
{
Enable = true;
isstart = true;
do
{
await Task.Delay(Interval);
new Thread(() =>
{
elipse(); //the replacment running now (interface thrad protected)
}).Start();
}
while (isstart);
Enable = false;
});
}
public void stop()
{
isstart = false;
}
}
AND thanks
As you are starting a new thread, you need to call elipse in the Form context:
Replace:
new Thread(() =>
{
elipse();
}).Start();
with
new Thread(() =>
{
Context.BeginInvoke(elipse);
}).Start();
Thanks Robert, good improvement , the code running successfully i add the post to see what others say, for code correct :) i keep this method like this for other developer to understand that they can add more code here
i find lot of post that they use long code to perform small task,
here is light code for many methods used in many project and helpful
this code is same as Microsoft timer implemented by me
here it is
using System;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WindowsFormsApplication8
{
public partial class Form1 : Form
{
public Form1()
{
//form constractor
InitializeComponent();
}
timer mytimer;
private void Form1_Load(object sender, EventArgs e)
{
//perform event click for button automaticly
button1.PerformClick();
}
private void Elipse()
{
//the code for timer :) //yazeed coding ,,,, write any other code
new Thread(() => MessageBox.Show("Successful")).Start();
Text = DateTime.Now.TimeOfDay.Seconds.ToString();
}
private void button1_Click(object sender, EventArgs e)
{
mytimer = new timer();
mytimer.elipse += Elipse;
mytimer.Interval = 1000;
mytimer.Enable = true;
mytimer.start(this);
}
}
}
class timer
{
bool isstart;
internal delegate void Del();
internal Del elipse;
static void UserRep() { }
internal bool Enable { get; set; }
internal int Interval { get; set; }
internal timer(int val=100)
{
Enable = false;
Interval = val>0?val:100;//default is 1 sec
isstart = false;
elipse = new Del(UserRep);
}
internal void start(Form Context)
{
new Thread(async () =>
{
isstart = true;
do
{
await Task.Delay(Interval);
new Thread(() => Context.BeginInvoke((MethodInvoker)delegate
{
elipse(); //the replacment running now (interface thrad protected)
})).Start();
}
while (isstart);
}).Start();
}
internal void stop()
{
isstart = false;
}
}
Related
not very expert of Threading under Windows.
I have a Main WinForm that opens a child form in it's ctor.
public partial class Main : Form
{
public Main()
{
InitializeComponent();
ImgRxUI formStart = new ImgRxUI();
formStart.MdiParent = this;
formStart.WindowState = FormWindowState.Maximized;
formStart.Show();
}
etc..
The ImgRxUI Form (child form) starts a Thread passing to 2 Actions (delegates in simple form).
public partial class ImgRxUI : Form
{
private ImgReceiver oImgReceiver = null;
public ImgRxUI()
{
InitializeComponent();
this.WindowState = FormWindowState.Maximized;
this.ShowIcon = false;
oImgReceiver = new ImgReceiver(UpdateImage, Log);
oImgReceiver.startService();
}
public void UpdateImage(byte[] ProtocolType)
{
...do stuff...
}
public void Log(string Text)
{
this.Invoke((MethodInvoker)delegate
{
LogMethod(Text);
tLog.ScrollToCaret();
});
}
private void LogMethod(string Text)
{
tLog.AppendText(Text + Environment.NewLine);
}
The ImgReceiver as I said starts a thread that listens on a socket...
public class ImgReceiver
{
private Action<byte[]> ImgReceived;
private Action<string> Log;
private System.Threading.Thread Thread_ImgReceiver = null;
public ImgReceiver(Action<byte[]> ImageReceivedDelegate, Action<string> LogDelegate)
{
this.ImgReceived = ImageReceivedDelegate;
this.Log = LogDelegate;
}
public void startService()
{
Thread_ImgReceiver = new System.Threading.Thread(startListening);
Thread_ImgReceiver.IsBackground = true;
Thread_ImgReceiver.Start();
}
[SecurityPermissionAttribute(SecurityAction.Demand, ControlThread = true)]
public void killService()
{
Thread_ImgReceiver.Abort();
System.Threading.Thread.Sleep(1000);
}
public void startListening()
{ ...do stuff...}
When I close the ImgRxUI form the following event on the form itself gets called
private void ImgRxUI_FormClosing(object sender, FormClosingEventArgs e)
{
oImgReceiver.killService();
}
Hear rises the error in the title.
Wht ?
Thaks
Change the kill Service method to
[SecurityPermissionAttribute(SecurityAction.Demand, ControlThread = true)]
public void killService(Action action)
{
action.Invoke();
System.Threading.Thread.Sleep(1000);
}
Change the access level Thread_ImgReceiver to public
public System.Threading.Thread Thread_ImgReceiver = null;
and call killService to
private void ImgRxUI_FormClosing(object sender, FormClosingEventArgs e)
{
oImgReceiver.killService(new Action(delegate { oImgReceiver.Thread_ImgReceiver.Abort(); }));
}
I am developing Windows Store Application. I need to implement a metronome. This metronome should have bpm settings. User should be able to increase/decrease it.
Here is my code so far:
namespace App1
{
public sealed partial class MainPage : Page
{
public class TickArgs : EventArgs
{
public DateTime Time { get; set; }
}
public class Metronome
{
public event TickHandler Tick = (m, e) => { };
public delegate void TickHandler(Metronome m, TickArgs e);
public void Start()
{
while (true)
{
System.Threading.Tasks.Task.Delay(3000);
Tick(this, new TickArgs { Time = DateTime.Now });
}
}
}
public class Listener
{
public void Subscribe(Metronome m, TextBlock tb, MediaElement mmx)
{
m.Tick += (mm, e) => mmx.Play();
}
}
public MainPage()
{
this.InitializeComponent();
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
}
private void Button_Click(object sender, RoutedEventArgs e)
{
Metronome m = new Metronome();
Listener l = new Listener();
l.Subscribe(m, tbcheck, mediaElement1);
m.Start();
}
}
}
How can i modify this code to have BPM settings?
My regards
Instead of uisng Task.Delay it may be easier to just use a Timer
An you can just pass the BBM into the Start method and set the interval based on that
public class Metronome
{
private DispatcherTimer _timer;
public event TickHandler Tick;
public delegate void TickHandler(Metronome m, TickArgs e);
public Metronome()
{
_timer = new DispatcherTimer();
_timer.Tick += Timer_Tick;
}
private void Timer_Tick(object sender, EventArgs e)
{
if (Tick != null)
{
Tick(this, new TickArgs { Time = DateTime.Now });
}
}
public void Start(int bbm)
{
_timer.Stop();
_timer.Interval = TimeSpan.FromSeconds(60 / bbm);
_timer.Start();
}
}
private void Button_Click(object sender, RoutedEventArgs e)
{
Metronome m = new Metronome();
Listener l = new Listener();
l.Subscribe(m, tbcheck, mediaElement1);
m.Start(8); // 8bbm
}
I'm making an application for a friend's birthday, where a window with changing compliments is supposed to pop up.
The window freezes, however, and the labels don't change. I Googled it, and read something about using Backgroundworker in order to seperate the GUI-thread from the changing process.
Still doesn't work.
This is my 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;
using System.Threading;
namespace ProjectL
{
public partial class Form1 : Form
{
private MessageHandler theHandler = new MessageHandler();
private BackgroundWorker theBackgroundWorker = new BackgroundWorker();
public Form1()
{
InitializeComponent();
}
private void StartButton_Click(object sender, EventArgs e)
{
StartButton.Visible = false;
theBackgroundWorker.DoWork += new DoWorkEventHandler(theBackgroundWorker_doYourWork);
//theBackgroundWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(theBackgroundWorker_doYourWork);
theBackgroundWorker.RunWorkerAsync();
theHandler.RunMessage(hBDLabel, youAreLabel, mainLabel, this);
}
void theBackgroundWorker_doYourWork(object sender, DoWorkEventArgs e)
{
theHandler.RunMessage(hBDLabel, youAreLabel, mainLabel, this);
}
}
}
This is what's supposed to happen from the background, using a class I've named MessageHandler:
class MessageHandler
{
public List<String> GenerateComplimentTexts()
{
List<String> stringList = new List<String>();
//Adding a bunch of compliments into a List<String>
return stringList;
}
public void RunMessage(Label hBDLabel, Label youAreLabel, Label mainLabel, Form1 form)
{
List<String> stringList = GenerateComplimentTexts();
Thread.Sleep(2000);
form.Text = "Happy Birthday Goose!!!";
hBDLabel.Text = "Happy Birthday Goose!";
Thread.Sleep(3000);
youAreLabel.Text = "You are...";
Thread.Sleep(2000);
foreach (String e in stringList)
{
mainLabel.Text = e;
//form.Test = e
Thread.Sleep(1000);
}
Thread.Sleep(3000);
mainLabel.Text = "";
youAreLabel.Text = FinalMessage;
}
private String _finalMessage = "FINAL MESSAGE";
public String FinalMessage {get {return _finalMessage;}}
}
Still, nothing changes on my window. Everything is pretty much frozen, except for the text in the top-bar of the form itself, if I choose to uncomment
form.Text = e;
Any advice?
You could achieve it using Timers instead of a BackgroundWorker.
It would probably look like this :
MainForm :
public partial class Form1 : Form
{
private Timer timer;
private MessageHandler theHandler = new MessageHandler();
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
timer = new Timer();
timer.Interval = 1000;
timer.Tick += TimerOnTick;
// Initialize the other labels with static text here
}
private void TimerOnTick(object sender, EventArgs eventArgs)
{
theHandler.ShowNext(label1);
}
private void StartButton_Click(object sender, EventArgs e)
{
timer.Start();
}
}
And the MessageHandler class :
public class MessageHandler
{
private List<String> compliments = new List<string>();
private int index = 0;
public MessageHandler()
{
GenerateComplimentTexts();
}
private void GenerateComplimentTexts()
{
List<String> stringList = new List<String>();
//Adding a bunch of compliments into a List<String>
compliments = stringList;
}
public void ShowNext(Label label)
{
label.Text = compliments.ElementAt(index);
index = (index >= compliments.Count - 1) ? 0 : index + 1;
}
}
To update the UI, use the ReportProgress method of the background worker. ReportProgress raises the ProgressChanged event and you can update your UI from there. Be sure to set the WorkerReportsProgress property of the backgroundworker to true.
Try this code:
private void StartButton_Click(object sender, EventArgs e)
{
StartButton.Visible = false;
theBackgroundWorker.DoWork += new DoWorkEventHandler(theBackgroundWorker_doYourWork);
theBackgroundWorker.ProgressChanged += new ProgressChangedEventHandler(theBackgroundWorker_ProgressChanged);
theBackgroundWorker.RunWorkerAsync();
}
void theBackgroundWorker_doYourWork(object sender, DoWorkEventArgs e)
{
var w = sender as BackgroundWorker;
List<String> stringList = GenerateComplimentTexts();
Thread.Sleep(2000);
w.ReportProgress(0, "Happy Birthday Goose!!!");
w.ReportProgress(1, "Happy Birthday Goose!");
Thread.Sleep(3000);
w.ReportProgress(2, "You are...");
Thread.Sleep(2000);
foreach (String e in stringList)
{
w.ReportProgress(3, e);
Thread.Sleep(1000);
}
Thread.Sleep(3000);
w.ReportProgress(3, "");
w.ReportProgress(2, FinalMessage);
}
void theBackgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
var msg = e.UserState.ToString();
switch (e.ProgressPercentage)
{
case 0:
form.Text = msg;
break;
case 1:
hBDLabel.Text=msg;
break;
case 2:
youAreLabel.Text =msg;
break;
case 3:
mainLabel.Text=msg;
break;
}
}
Have a try with this:
1.) Copy Timer to Form
2.) Copy the following Code into the timer1_tick-Event.
private int _counter;
private int _currentIndex;
private void timer1_Tick(object sender, EventArgs e)
{
switch (_counter)
{
case 1:
form.Text = "Happy Birthday Goose!!!";
hBDLabel.Text = "Happy Birthday Goose!";
break;
case 2:
timer1.Interval = 3000;
break;
case 3:
youAreLabel.Text = "You are...";
break;
case 4:
if (stringlist.count = (_currentIndex -1))
{
timer1.Enabled = false;
}else {
mainLabel.Text = e;
timer1.Interval = 1000;
return;
}
break;
}
_counter ++;
}
Not the most elegant way, but it should work.
Is there any chance that timer_Tick could be called after myForm_FormClosing
in the code below.
If there is a chance: Is it sufficient to call timer.Stop() within myForm_FormClosing in order to avoid that timer_Tick gets called after myForm_FormClosing?
using System;
using System.Windows.Forms;
using System.ComponentModel;
namespace Test
{
static class Program
{
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MyForm());
}
}
class MyForm : Form
{
private IContainer components;
private Timer timer;
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
public MyForm()
{
components = new Container();
timer = new Timer(components);
timer.Interval = 50;
timer.Tick += timer_Tick;
timer.Enabled = true;
FormClosing += myForm_FormClosing;
}
private void timer_Tick(object sender, EventArgs e)
{
}
private void myForm_FormClosing(object sender, FormClosingEventArgs e)
{
}
}
}
Update:
After receving a few hints (thanks for helping) I basically have chosen the following code to achive what I want.
Please not that timer1_Tick could still be called after myForm_FormClosing was called!
This solution just introduces a flag (i called it doWork) which stops the code within timer1_Tick to be executed after myForm_FormClosing was called.
using System;
using System.Windows.Forms;
using System.ComponentModel;
namespace Test
{
static class Program
{
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MyForm());
}
}
class MyForm : Form
{
private IContainer components;
private Timer timer;
private bool doWork = true;
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
public MyForm()
{
components = new Container();
timer = new Timer(components);
timer.Interval = 50;
timer.Tick += timer_Tick;
timer.Enabled = true;
FormClosing += myForm_FormClosing;
}
private void timer_Tick(object sender, EventArgs e)
{
if (doWork)
{
//do the work
}
}
private void myForm_FormClosing(object sender, FormClosingEventArgs e)
{
doWork = false;
}
}
}
Yes it is possible. According to the docs ...
Occurs before the form is closed.
When a form is closed, it is disposed, releasing all resources
associated with the form.
The timer will not be disposed until after the FormClosing event. Here is a very contrived example of how it can happen. You will see that you hit the debugger breakpoint on the Timer tick after FormClosing has been called.
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.Diagnostics;
using System.Threading.Tasks;
using System.Threading;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
private System.Windows.Forms.Timer _time = new System.Windows.Forms.Timer();
private Task _t1 = null;
private Task _t2 = null;
private bool _closingFlag = false;
public Form1()
{
InitializeComponent();
_time.Interval = 50;
_time.Tick += (s, e) => {
textBox1.Text = DateTime.Now.ToString();
if (_closingFlag) Debugger.Break();
};
_time.Start();
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
_closingFlag = true;
_t1 = Task.Factory.StartNew(() => { Thread.Sleep(1000); });
_t2 = Task.Factory.StartNew(() => { Thread.Sleep(1000); });
Task.WaitAll(_t1, _t2);
}
}
}
If you use a the timer System.Windows.Forms.Timer the UI thread must be idle to process a tick from the timer, so from my understanding that's is not possible.
Could happen if you use a timer with its own thread, as a System.Timers.Timer. In this case we could avoid what you mention by implementing something like this:
class MyForm : Form
{
private System.Timers.Timer timer;
private Object justForLocking = new Object();
private Boolean safeToProceed = true;
[...]
public MyForm()
{
components = new Container();
timer = new System.Timers.Timer();
timer.Interval = 50;
timer.Elapsed += new System.Timers.ElapsedEventHandler(timer_Elapsed);
timer.Start();
FormClosing += myForm_FormClosing;
}
void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
// In case that this code is being executed after
// the method myForm_FormClosing has adquired the
// exclusive lock over our dummy resource,
// the timer thread will wait until the resource if released.
// Once is released, our control flag will be set to false
// and the timer should just return and never execute again.
lock(justForLocking)
{
if (safeToProceed)
{
// Do whatever you want to do at this point
}
}
}
private void myForm_FormClosing(object sender, FormClosingEventArgs e)
{
lock(justForLocking)
{
safeToProceed = false;
}
timer.Stop();
// Do something else
}
[...]
}
This other SO question has relevant information.
EDIT: the code above is only valid if a System.Timers.Timer is used instead of System.Windows.Forms.Timer
I dont believe so but it would be best anyways to call timer.stop() regardless. if you were needing it to though you should create the timer object in program.cs
I need help in troubleshooting my code. I have 3 classes. Class 1 is a WinForm with Progressbar on it. Class 2 is where the event is fired. Class 3 is the EventArg for the progress. The program compiles with out any errors, but when I click the button, the progress bar does not move!.
namespace WindowsFormsApplication1
{
class Class1
{
//Declaring a delegate
public delegate void StatusUpdateHandler(object sender, ProgressEventArgs e);
//Declaraing an event
public event StatusUpdateHandler OnUpdateStatus;
public int recno;
public void Func()
{
//time consuming code
for (recno = 0; recno <= 100; recno++)
{
UpdateStatus(recno);
}
}
public void UpdateStatus(int recno)
{
// Make sure someone is listening to event
if (OnUpdateStatus == null) return; <--------------OnUpdateStatus is always null not sure why?
ProgressEventArgs args = new ProgressEventArgs(recno);
OnUpdateStatus(this, args);
}
}
}
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
private Class1 testClass;
public Form1()
{
InitializeComponent();
testClass = new Class1();
testClass.OnUpdateStatus += new Class1.StatusUpdateHandler(UpdateStatus);
}
public void button1_Click(object sender, EventArgs e)
{
Class1 c = new Class1();
c.Func();
}
public void UpdateStatus(object sender, ProgressEventArgs e)
{
progressBar1.Minimum = 0;
progressBar1.Maximum = 100;
progressBar1.Value = e.Recno;
}
}
}
namespace WindowsFormsApplication1
{
public class ProgressEventArgs : EventArgs
{
public int Recno { get; private set; }
public ProgressEventArgs(int recno)
{
Recno = recno;
}
}
}
You're using two different objects of Class1.
In button click handler, the object c is not the same as member object testClass. Use testClass in place of c and it shud work
public void button1_Click(object sender, EventArgs e)
{
testClass.Func();
}
You never added an event handler to c's event.
You did add a handler to testClass' event, but testClass is never used.