i got code inglobal.asax page:
void Application_Start(object sender, EventArgs e)
{
// Code that runs on application startup
System.Timers.Timer timScheduledTask = new System.Timers.Timer();
// Timer interval is set in miliseconds,
// In this case, we'll run a task every minute
timScheduledTask.Interval = 60 * 1000;
timScheduledTask.Enabled = true;
// Add handler for Elapsed event
timScheduledTask.Elapsed += new System.Timers.ElapsedEventHandler(timScheduledTask_Elapsed);
}
void timScheduledTask_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
// Over here i want to call function that i have in asp.net page
}
my problem here that in timScheduledTask_Elapsed function, i want to call to function that i have in asp.net page (Contacts.aspx.cs).
Any idea how to call this function??
It would need to be a static method of the page as the application class has no way of knowing the current page instance.
A rough example can be seen below.
somepage.aspx:
public class SomePage : Page
{
public static void DoSomething()
{
...
}
}
global.asax:
void Application_Start(object sender, EventArgs e)
{
...
// Add handler for Elapsed event
timScheduledTask.Elapsed += new System.Timers.ElapsedEventHandler(timScheduledTask_Elapsed);
}
void timScheduledTask_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
SomePage.DoSomething();
}
However, this does mean that anything in DoSomething() must not rely on anything instance specific in the page.
I would rethink your approach.
Also note that timers are a bad idea here IMHO, if the application process unloads your timers will never get called so you cannot really rely on them.
If you need to call a PAGE method from outside, you have a very bad design. Before doing anything else I'd advise you to do some research on separating your code into multiple layers, so such situation can never happen.
If you however still insist you want to do it your way (you'll understand sooner or later anyway), simplest solution is to make the requested page method static. That way you can call it anytime without a reference to an actual instance.
I'd make the code into a non-visual class and call it.
If you need it to be visual, make it a visual user control and include it on a master page that you use.
I agree that trying to call something on a different page when that's not the page running is just asking for problems.
Related
I've run into this several times. My app receives some event (e.g. WndProc) and needs to return quickly. The code that needs to run takes some time, and does not need to be executed before returning from the event handler.
My current solution is to start a timer for a short time, and in the Tick event - run that code.
But that seems like the wrong tool for this case, and is prone to some errors (like running the code more than once, for example).
So, is there any ExecuteWhenThisThreadIsIdle scheme?
EDIT
A C#/.NET solution would be best, but a framework specific solution would be welcome too. Mainly Winforms. (But also WPF, UWP, Xamarin.Forms, ...)
The code needs to run on the same thread as the event handler. (Usually the UI thread.)
In WinForms, you can subscribe to Application.Idle.
For example ...
private bool _wndProcEventHooked = false;
protected override void WndProc(ref Message m) {
// Run your code here
}
private void Application_Idle(Object sender, EventArgs e) {
if (!this._wndProcEventHooked) {
// Hook your wndProc event here.
this._wndProcEventHooked = true;
}
}
In WPF this can be done using DispatcherTimer:
var timer = new DispatcherTimer
(
TimeSpan.FromMinutes(10),
DispatcherPriority.ApplicationIdle,// Or DispatcherPriority.SystemIdle
(s, e) => MessageBox.Show("Timer"),
Application.Current.Dispatcher
);
I have one main windows form and within that form I have custom controls that represents different screens in application. I want to access this control's child controls. There's something I'm not getting here...sometimes I get this error:
Cross-thread operation not valid:
Control 'lblText' accessed from a thread
other than the thread it was created on.
but sometimes everything works OK. I don't completelly understand why the error...probably something with external device (MEI BillAcceptor) which has an event (inside Form1 class) that does the changes to the control... so let me write a simple code...
//user control
public partial class Screen2 : UserControl
{
public void changeValue(string txt)
{
lblText.Text = txt;
}
}
and the method changeValue is called from a form1 when particular event is rised...
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
BillAcceptor.SomeBillAcceptorEvent +=
new SomeBillAcceptorEventHandler(changeText);
}
private void changeText(object sender, EventArgs args)
{
_screen2.changeValue("some text");
}
}
So the most annoying thing is that sometimes everything actually works... So my question is "do I have to use Invoke here?" or how do I solve this with less changes to the application...
In your handler. do something like this.
if (this.InvokeRequired)
{
Invoke(new MethodInvoker(() =>
{
_screen2.changeValue("some text");
}));
}
else
{
_screen2.changeValue("some text");
}
I would guess that the event is being raised on a seperate thread other that the main UI thread.
Yes you need to use Invoke if there is a possibility of that method being called from a different thread.
You can check this.InvokeRequired(), if true, then use invoke, if false do a normal call.
This occurs due to thread unsafe call
You should make only thread safe calls in program
Check this link.
The short answer is yes, you must use Invoke. See this question and its accepted answer if you need details.
The reason the exception is only thrown some of the time, by the way, comes down to timing. You currently have a race condition in which sometimes you get lucky and sometimes you don't.
By the way, here is pretty handy pattern for this sort of thing.
Refactor any code that sets form values into its own private void method(s).
In this new method, call InvokeRequired. If it returns true, call Invoke, passing the current method so as to recurse back into it. If it returns false, go ahead and make the change.
Call this new method from the event handler.
For example:
private void ChangeScreen2() {
if (this.InvokeRequired) {
this.Invoke(new MethodInvoker(ChangeScreen2));
}
else {
_screen2.changeValue("some text");
}
}
private void changeText(object sender, EventArgs args)
{
ChangeScreen2();
}
The idea being that you sequester all code that modifies the form into these methods that always begin with a check of InvokeRequired and always Invoke themselves if so required. This pattern works with .NET 1.0 onward. For even neater approach, see the accepted answer to this question, which works with .NET 3.0 and later.
Im aware this may be a slightly odd question, but given a Page class that looks like this:
public class abc:Control
{
public abc()
{
this.Init+=new EventHandler(foo);
this.Load+=new EventHandler(foo);
}
void foo(object sender, eventargs e)
{
//determine whether or not this.Init has already fired.
}
}
I know I could do this by setting a global boolean 'hasinitfired', but I was wondering if this was not necessary or if something as part of the .net library already existed.
Why do you need to know init is fired or not. Init always gets fired during postback or callback. Go through ASP.net page lifecycle, and you will know what all events fired after init and what all before. If you intend to use same handler for different events, yes make a class variable to identify the current event. I recommend attach different handler, and call another method with different param value.
like,
public class abc:Control
{
public abc()
{
this.Init+=new EventHandler(foo1);
this.Load+=new EventHandler(foo2);
}
void foo1(object sender, eventargs e)
{
foo('init');
}
void foo2(object sender, eventargs e)
{
foo('load');
}
void foo(string from)
{
// do something
}
}
This will give cleaner solution and flexibility to add functionality.
I'm guessing you want to know if init has fired when foo runs. As #Adam said, tracing would let you do that if you wanted to see what your app was doing.
Whilst it's running, the best way as I see it would be with a flag, as you suggested.
Simon
This looks like something you'd use the .NET Trace class for. You can use trace to put text in the Visual Studio output window.
Trace.WriteLine("Method called.");
Tracing in .NET has more options than my example:
http://www.15seconds.com/issue/020910.htm
Even further to this, you could use a PostSharp aspect to decorate this method, but that is a third party library.
I want to have a Timer to update the global variable like every 10 sec, so I put a timer in my Global.asax.cs:
void Application_Start(object sender, EventArgs e)
{
Timer aTimer = new Timer();
aTimer.Interval = 10*1000;
aTimer.Tick += aTimer_Tick;
aTimer.Start();
}
void aTimer_Tick(object sender, EventArgs e)
{
// Update Data
}
But weird thing is nothing happen after 10 sec. I wonder if is possible to do it like that?
Thanks in advance.
Use System.Timers.Timer instead of System.Windows.Forms.Timer
The former uses Elasped as the event handler and will function as expected almost anywhere in an application. The latter is tailored for winforms and should be used on Form1_Load() not on application start.
ASP.NET requests and events are not designed to take a long time. You should consider writing a Windows Service, depending on what you're trying to achieve (what are you trying to achieve?).
I guess that the Timer object is destroyed after the Application_Start void is closed. So, try to assign it to an application variable.
I have a web service with two methods:
RetrieveFirstLevelOptions() and RetrieveSecondLevelOptions(int levelOneOption).
The GUI contains two comboBoxes: FirstLevelOptionsCombo and SecondLevelOptionsCombo.
I am having trouble with creating a control flow for the initialization stage when I have to make a request to RetrieveFirstLevelOptions() and then, once the results are in, call RetrieveSecondLevelOptions(default levelOneOption = 0).
The problem is that since everything happens asynchronously I don't know what the best approach is to allow this behaviour take place once and only once, at the beginning.
An option I would love to have is to attach a second event handler to the RetieveFirstLevelOptionsCompleted event and have it remove itself after running only once. But it looks like such a behaviour is impossible to get.
Another option would be to have a boolean flag to indicate whether in Initialization phase and if it is, then the handler for RetrieveFirstLevelOptionsCompleted would execute some additional logic. However this idea makes it look like all event handlers would have to check for state information and do different things depending on the current state. This seems to be bad design because the control flow seems to be descentralized.
I want to have a centralized control flow mechanism that will make the decisions in one spot. But how can this be done when everything is executed asynchronously?
"An option I would love to have is to attach a second event handler to the RetieveFirstLevelOptionsCompleted event and have it remove itself after running only once. But it looks like such a behaviour is impossible to get."
Is there some reason this isn't working:
class Example
{
SomeWebService myService;
Example()
{
// do stuff
myService.RetrieveFirstLevelOptionsCompleted += MyHandlerMethod;
}
void MyHandlerMethod(object sender, RetrieveFirstLevelOptionsCompletedEventArgs e)
{
// do stuff
myService.RetrieveFirstLevelOptionsCompleted -= MyHandlerMethod;
// potentially attach next event handler for all subsequent calls
myService.RetrieveFirstLevelOptionsCompleted += MyHandlerMethod2;
}
}
The pattern that I usually use in a situation like this is to create a wrapper around the Async web service proxy method that accepts a callback method. The callback method then gets passed to the RetrieveFirstLevelOptionsAsync() method like so:
public void RetrieveFirstLevelOptions(Action callback)
{
client.RetrieveFirstLevelOptionsAsync(callback);
}
void client_RetrieveFirstLevelOptionsCompleted(object sender, AsyncCompletedEventArgs e)
{
var callback = e.UserState as Action;
if (callback != null)
{
callback();
}
}
So when you call RetrieveFirstLevelOptions(), you just pass the callback that you want to run only once, and you don't ever have to worry about it getting called multiple times. Presumably you'd put your call to RetrieveSecondLevelOptions() within that callback.