How to create Image in Timer method? - c#

For example. I have some Timer and i'm initializing it in my Window constructor.
public MainWindow()
{
InitializeComponent();
CheckTImer = new Timer(3000);
CheckTimer.Elapsed += CheckTimer_Elapsed;
CheckTimer.Start();
}
And this is my CheckTimer_Elapsed method:
void CheckTimer_Elapsed(object sender, ElapsedEventArgs e)
{
MessageBox.Show("FirstText");
Image IMG = new Image();
MessageBox.Show("SecondText");
}
Why it is loading only a first MessageBox window? But, if it would be function that is called not by a Timer all is OK.
public MainWindow()
{
InitializeComponent();
SomeFunc();
}
void SomeFunc()
{
MessageBox.Show("FirstText");
Image IMG = new Image();
MessageBox.Show("SecondText");
}

I believe this is a threading problem.
If I recall the event that is getting called from the timer is on a new thread. You are trying to do UI work which is not on the UI thread (which is not allowed). Couple of solutions to this, the simplest of which is to use a DispatcherTimer instead of a Timer. You can find it in System.Windows.Threading;
The Event that gets called from the DispatcherTimer is on the UI thread
Hope this helps

Related

WPF Access window created on different UI thread

I created new Window on a different thread because it has heavy UI operations, that was done to keep my main window run smoothly. Everything works perfectly. But here is the question:
How I can access newly created window?
After calling Dispatcher.Run() I can not manipulate visualisationWindow anymore. I want to keep access to that newly created window object.
Here is how my window created:
private void CreateVisualisationWindow()
{
Thread VisualisationWIndowThread = new Thread(new ThreadStart(ThreadStartingPoint));
VisualisationWIndowThread.SetApartmentState(ApartmentState.STA);
VisualisationWIndowThread.IsBackground = true;
VisualisationWIndowThread.Start();
}
private void ThreadStartingPoint()
{
Visualisation visualisationWindow = new Visualisation();
visualisationWindow.Show();
System.Windows.Threading.Dispatcher.Run();
}
Also I tried accessing it through System.Windows.Threading.Dispatcher.FromThread(VisualisationWIndowThread) but seems I misunderstand some core things.
I simulated your issue using two WPF Window objects and a timer to ensure that the Second Window was created before calling operations on it. Below is my code sample and it updates the second Windows TextBox every five seconds:
private Timer _timer;
private SecondWindow _secondWindow;
public MainWindow()
{
InitializeComponent();
CreateVisualisationWindow();
_timer = new Timer(Callback);
_timer.Change(5000, 5000);
}
private void Callback(object state)
{
UpdateSecondWindowText();
}
private void CreateVisualisationWindow()
{
Thread VisualisationWIndowThread = new Thread(ThreadStartingPoint);
VisualisationWIndowThread.SetApartmentState(ApartmentState.STA);
VisualisationWIndowThread.IsBackground = true;
VisualisationWIndowThread.Start();
}
private void ThreadStartingPoint()
{
_secondWindow = new SecondWindow();
_secondWindow.SecondWindowTextBlock.Text = "Hello";
_secondWindow.Show();
Dispatcher.Run();
}
private void UpdateSecondWindowText()
{
_secondWindow.Dispatcher.BeginInvoke(new Action(() =>
{
_secondWindow.SecondWindowTextBlock.Text = _secondWindow.SecondWindowTextBlock.Text + " World";
}));
}
So the trick is, you need to call the Dispatcher on the second Window in order to gain access to it.

WPF InitializeComponent doesn't seem to work with DispatcherTimer

I am new to C# and also to WPF, I am trying to understand how DispatcherTimer works with GUI (WPF). I want to make my application run a function every 2 seconds but still using the app itself, when I try the following code, the timer starts but I can't use the following Buttons (logout and exit), it's like the app freezes.
public MainLoggedWindow()
{
Globals.mainLoggedWindow = this;
InitializeComponent();
DispatcherTimer dt = new DispatcherTimer();
dt.Tick += new EventHandler(dtTiker);
dt.Interval = new TimeSpan(0, 0, 1);
dt.Start();
}
private void exit_button_Click(object sender, RoutedEventArgs e)
{
logout_button_Click(sender, e);
Environment.Exit(-1);
}
private void logout_button_Click(object sender, RoutedEventArgs e)
{
Globals.LOGGED_IN_USER.logout();
this.Hide();
Globals.mainWindow.Show();
}
private int increment = 0;
private void dtTiker(object sender,EventArgs e)
{
increment++;
Time.Content = increment.ToString();
}
DispatcherTimer runs on the UI thread. It means that when the DispatcherTimer invokes its Tick method the UI thread becomes busy handling that, and it doesn't have time to handle other UI input like button clicks, so the window freezes.
What you could do is increase the interval time for your DispatcherTimer - your question desription says that it's once every two seconds, but your initialisation logic has it every one second: dt.Interval = new TimeSpan(0, 0, 1);

WPF ContentControl some unclears

i have some usercontrols in my solution, in main window i just change content of ContentControl.
in one usercontrol there is a timer
BringTrinket trincket = new BringTrinket();
trincket.TrincketBringed += new TrincketBringedEventHandler(trincket_TrincketBringed);
this.contentSwitcher.Content = new BringTrinket();
}
void trincket_TrincketBringed(object sender, TrincketEventArgs e)
{
MessageBox.Show(e.TrincketNumber);
this.contentSwitcher.Content = new Loading();
}`
after some event Main Window should change content to (new Loading()), it's OK!
public partial class BringTrinket : UserControl, ISwitchable
{
public event TrincketBringedEventHandler TrincketBringed;
private DispatcherTimer timer;
public BringTrinket()
{
InitializeComponent();
/////////////////////////////////////////////////////////////////////////////
timer = new DispatcherTimer();
timer.Interval = new TimeSpan(0, 0, 0, 0, 1800);
timer.Tick += new EventHandler(timer_Tick);
timer.Start();
/////////////////////////////////////////////////////////////////////////////
}
/////////////////////////////////////////////////////////////////////////////
void timer_Tick(object sender, EventArgs e)
{
if (TrincketBringed != null)
{
TrincketBringed(this, new TrincketEventArgs("Hello"));
//TrincketBringed = null;
}
}
But after i've navigataged Timer in BringTrinket still working, how have i dispose that usercontrol? (I know i can set TrincketBringed to null, but timer will still be working)
I think not only timer, but also usercontrol remains in memory
So, your question is how to stop the timer? Use timer.Stop().
BTW, your code would read better if you rename TricketBringed to TrincketBrought.
It looks like your timer is inside of your first usercontrol. You would either need to stop the timer before losing the reference to that object, or better yet, move the timer out of your control.

Call method on the GUI thread from a timers thread

In my application I am using a timer to check for updates in an RSS feed, if new items are found I pop up a custom dialog to inform the user. When I run the check manually everything works great, but when the automatic check runs in the timers Elapsed event the custom dialog is not displayed.
First of all is this a thread issue? (I am assuming it is because both the manual and automatic check use the same code).
When I run the automatic check, do I have to invoke the method that runs the check from the Timers Elapsed event handler?
Is there something I need to do in my custom dialog class?
Edit:
this is a winforms application.
Here is an example of what the code is like. (Please don't point out syntax errors in this code example, this is just a simple example not real code).
public class MainForm : System.Windows.Forms.Form
{
//This is the object that does most of the work.
ObjectThatDoesWork MyObjectThatDoesWork = new ObjectThatDoesWork();
MyObjectThatDoesWork.NewItemsFound += new NewItemsFoundEventHandler(Found_New_Items);
private void Found_New_Items(object sender, System.EventArgs e)
{
//Display custom dialog to alert user.
}
//Method that doesn't really exist in my class,
// but shows that the main form can call Update for a manual check.
private void Button_Click(object sender, System.EventArgs e)
{
MyObjectThatDoesWork.Update();
}
//The rest of MainForm with boring main form stuff
}
public class ObjectThatDoesWork
{
System.Timers.Timer timer;
public ObjectThatDoesWork()
{
timer = new System.Timers.Timer();
timer.Interval = 600000;
timer.AutoReset = true;
timer.Elapsed += new new System.Timers.ElapsedEventHandler(TimeToWork);
timer.Start();
}
private void TimeToWork(object sender, System.Timers.ElapsedEventArgs e)
{
Update();
}
public void Update()
{
//Check for updates and raise an event if new items are found.
//The event is consumed by the main form.
OnNewItemsFound(this);
}
public delgate void NewItemsFoundEventHandler(object sender, System.EventArgs e);
public event NewItemsFoundEventHandler NewItemsFound;
protected void OnNewItemsFound(object sender)
{
if(NewItemsFound != null)
{
NewItemsFound(sender, new System.EventArgs());
}
}
}
After reading some of the comments and answers, I think my problem is that I am using a System.Timers.Timer not a System.Windows.Forms.Timer.
EDIT:
After changing to a Forms.Timer initial testing looks good (but no new items exist yet so have not seen the custom dialog). I added a bit of code to output the thread ID to a file when the update method is called. Using the Timers.Timer the thread ID was not the GUI thread, but using the Forms.Timer the thread ID is the same as the GUI.
Which timer are you using? System.Windows.Forms.Timer automatically fires the event on the UI thread. If you are using other one you will need to use Control.Invoke to call the method on UI thread.
You should use Forms.Timer here, or if you use other kind of timers, serialize calls to UI with .Invoke()
Is your application a WPF-Application? If so, you must delegate the work from your background-thread to the Dispatcher associated with the UI thread.
Post some code, so you can get better help and have a look at the Dispatcher class http://msdn.microsoft.com/en-us/library/system.windows.threading.dispatcher.invoke.aspx
private static System.Threading.SynchronizationContext _UI_Context;
//call this function once from the UI thread
internal static void init_CallOnUIThread()
{
_UI_Context = System.Threading.SynchronizationContext.Current;
}
public static void CallOnUIThread(Action action, bool asynchronous = false)
{
if (!asynchronous)
_UI_Context.Send((o) =>
{
action();
}, null);
else
_UI_Context.Post((o) =>
{
action();
}, null);
}

Why does System.Threading.Timer stop on its own?

I'm doing a small test project before I use System.Threading.Timer in a Windows Service project. It's working wonderfully, however the timer stops on its own after a minute or two.
The full source for the test project is:
using System;
using System.Windows.Forms;
using System.Threading;
namespace studyTimers {
public partial class Form1 : Form {
public Form1() {
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e) {
TimerCallback timerDelegate = new TimerCallback(tick);
System.Threading.Timer testTimer = new System.Threading.Timer(timerDelegate, null, 1000, 1000);
}
void tick(Object obj) {
if (label1.InvokeRequired) {
label1.Invoke(new MethodInvoker(() => tick(obj)));
} else {
label1.Text = DateTime.Now.ToString();
}
}
}
}
The goal is obviously to update a label with the current time. I am noticing that updating stops after a bit. Why would this be?
If you need a timer on a Windows Form then drop a System.Windows.Forms.Timer onto the form - there's no reason to use a System.Threading.Timer unless you need better resolution than 55 ms.
The reason the timer "stops" is because it's being garbage-collected. You're allowing it to go out of scope in the Form1_Load method because you only declare it as a local variable. In order to keep the timer "alive", it needs to be a private field on the form class so that the GC knows it's still needed.
In other words:
public partial class Form1 : Form
{
private System.Threading.Timer testTimer;
...
public void Form1_Load(object sender, EventArgs e)
{
TimerCallback timerDelegate = new TimerCallback(tick);
testTimer = new System.Threading.Timer(timerDelegate, null, 1000, 1000);
}
}
But again, in this case it's simplier to use System.Windows.Forms.Timer, which is an actual component in the toolbox that you can just drop onto the form.
Edit - As the comments now reveal, if this is just a test app and the real application is in a Windows Service, you cannot use System.Windows.Forms.Timer for that. Just remember not to let your System.Threading.Timer go out of scope.
Garbage collector collected the timer object, you should keep a reference to it.
this post will help: http://msdn.microsoft.com/en-us/library/system.threading.timer.aspx

Categories

Resources