I have an application in which I have to logout after say x seconds of inactivity.
I therefore have a timer going on and calculating a timespan from the last user acitivity resetted with:
dtLastActivity = DateTime.Now;
So the problem is that I don't think it's the best approach to associate EVERY single event in my program with the afore mentioned code.
But in the end I don't need EVERY event: all what is useful is to track KEYPRESS and MOUSEUP.
Would it be correct to track those two event in the MainWindow?
I have to admit that I still have not put into practice this (but I will) for I am not sure that this is the best approach for the purpose in the title.
Being new to WPF I am also not clear if tracking keyboard and mouse in the mainwindow shall not affect the behaviour in the children (that are the controls that effectively are the target of the event).
Thank you in advance for any help.
---EDIT---
The proposed solutions are very elegant. Particularly this one:
public static class IdleTimeDetector
{
[DllImport("user32.dll")]
static extern bool GetLastInputInfo(ref LASTINPUTINFO plii);
public static IdleTimeInfo GetIdleTimeInfo()
{
int systemUptime = Environment.TickCount,
lastInputTicks = 0,
idleTicks = 0;
LASTINPUTINFO lastInputInfo = new LASTINPUTINFO();
lastInputInfo.cbSize = (uint)Marshal.SizeOf(lastInputInfo);
lastInputInfo.dwTime = 0;
if (GetLastInputInfo(ref lastInputInfo))
{
lastInputTicks = (int)lastInputInfo.dwTime;
idleTicks = systemUptime - lastInputTicks;
}
return new IdleTimeInfo
{
LastInputTime = DateTime.Now.AddMilliseconds(-1 * idleTicks),
IdleTime = new TimeSpan(0, 0, 0, 0, idleTicks),
SystemUptimeMilliseconds = systemUptime,
};
}
}
but it is too automatic. I have no control over it.
E.g. if I use it from the beginning it gets idle BEFORE starting because my application has a quite long start time with splash screen, deserialization etc...
The solution proposed by Fruchtzwerg is much more similar to my needs because I get complete control over it. It has also the advantage that if I click on another application the timer is not resetted!!
I usually use the approach described by you. I running a timer and restart every interaction. The events of a window are:
PreviewMouseDown="Window_Action"
PreviewKeyDown="Window_Action"
Restarting the timer:
private void Window_Action(object Sender, InputEventArgs e)
{
IdleTimer.Stop();
IdleTimer.Start();
}
Never had any prolmems with this soultion. Restarting the timer takes under 80 ticks with a stopwatch. So the resources are in my opinion no problem.
Also you can specify the userinteractions by adding terms in your event.
The Preview-Events are not disturbing other events. This tunneling-behavoiur is described here.
Related
I've scoured this site and numerous other resources for trying to track this down.
I have a console application that I am trying to get have a system tray icon for.
That part works.
What I cannot actually get to work is adding a menu to it when I right click. I really just need an exit button that will shut it down.
My entire class is fairly small so I will include it. I have initialized this object in my main method and thats pretty much all I need since I drive this from the constructor. I've found resource that indicated I would not need a click event but I've tried both so Im not exactly sure.
I've tried patching this together from other resources but everyone seems to have a slightly different problem or I'm missing something.
Thanks for taking a look.
namespace PvsMessageLogger
{
public class SystemTray
{
private readonly string _systemDisplayName;
private readonly NotifyIcon _systemTray;
public SystemTray(string systemDisplayName)
{
_systemTray = new NotifyIcon();
_systemDisplayName = systemDisplayName;
InitializeSystemTray();
}
private void InitializeSystemTray()
{
_systemTray.Icon = new Icon(SystemIcons.Application, 40, 40);
_systemTray.Visible = true;
_systemTray.BalloonTipTitle = _systemDisplayName;
_systemTray.BalloonTipText = _systemDisplayName + " is running in the background";
MenuItem[] menuList = {new MenuItem("Exit", (s, e) => Application.Exit()) };
ContextMenu clickMenu = new ContextMenu(menuList);
_systemTray.ContextMenu = clickMenu;
_systemTray.ShowBalloonTip(1000);
}
}
}
Just found the answer in another thread, you must add Application.Run() after you create the icon.
You can find more details on Roman's answer.
so after more than a week of trying to solve it on my own I officially give up and turn to your help. Basically, it should not be so complicated so I have no idea why it does not work. I have a WPF app which contains a Main Window called surprise surpise...: Main_Window.
That window contain a user control called 'pageTransitionControl' that change its content according to what the client want to see. the 'pageTransitionControl' is there to support multiple animations and so on... Anyway, among all of the user controls, i have a preety havy uc called ucBanks. before it shows, the ucBanks load a lot of data, manipulating it and display it on a very beautiful and smart charts. the problem is it takes some time to load it, approximately 6-7 seconds so i need the UI to show 'Loading' animation during that time (another user control called 'ucSpinner').
I'm Trying to load the ucBanks on a different thread to avoid freezing the application and it works great: the ucSpinner is showed immidiatlly and the ucBanks is loading on the background but when i change the content of the 'pageTransitionControl' i get this error:
"The calling thread cannot access this object because a different thread owns it".
I think i tried basically everything but i must missing somthing or doing somthing wrong.
This is where it all start, the btn_click event that load ucBanks:
ShowSpinner();
Thread.Sleep(100);
Thread newThread = new Thread(new ThreadStart(LoadUc));
newThread.SetApartmentState(ApartmentState.STA);
newThread.IsBackground = true;
newThread.Start();
This is the ShowSpinner method:
private void ShowSpinner()
{
ucSpinner.Opacity = 1;
}
and this is the LoadUc method:
private void LoadUc()
{
ucOsh ucOshx = new ucOsh();
Utils.LoadUc(ucOshx, null, PageTransitions.PageTransitionType.GrowAndFade, true, this, null, true);
}
With the LoadUc i called static class called 'Utils' holding the 'LoadUc' method:
public static void LoadUc(System.Windows.Controls.UserControl ucParent, System.Windows.Controls.UserControl ucChild, PageTransitions.PageTransitionType tranType, bool removeChildrens = true, System.Windows.Window w = null, List<Plist.Plist> lst = null, bool hideMenu = false)
{
MainWindow win = null;
if (w != null) { win = (MainWindow)w; }
else { win = (MainWindow)System.Windows.Window.GetWindow(ucChild); }
win.Dispatcher.Invoke(
System.Windows.Threading.DispatcherPriority.ContextIdle, (System.Action)delegate
{
win.pageTransitionControl.TransitionType = tranType;
win.pageTransitionControl.PARAMS = lst;
win.pageTransitionControl.Tag = ucParent.ToString();
win.pageTransitionControl.pages.Push(ucParent);
win.pageTransitionControl.Content = ucParent; ----------->>>>This is where i get the error!!!
});
}
I understand that the main window is locked inside another thread but i cant see any other option to load it without freezing the entire app.
Does anyone have a suloution to my problem? SA :-) ?
What I have tried:
i tried working with background-worker, i chaned all of the settings of the dispatcher, loaded the user control inside and outside the threads...
I am building a dashboard style Windowsform, I have various timers to update the controls on the form, and all are working great, except one, the only one I am using a Label Control as the indicator.
I have various System.Timers to update the data of the indicators all stored in classes that run ever 5 minutes or so, then another timer set to update the GUI that runs every second. For some reason this code:
l_LastShipment.Text = GlobalStatic.fulfillmentInd.Caption;
within the GUI Update eventually errors in a StackOverflowException, usually after a couple of hours. fulfillmentInd.Caption is just a string variable in the class, and at the time of the error contains the proper data (Usually "0:01" or something similar).
Originally the GUI Timer was a System.Timer but was afraid the Invoke to update the Label was were the error was coming from, so switched the GUI timer to a Windows.Forms.Timer so it didn't require the Invoke, yet the error still occurs.
There is no recursion taking place, and I even monitored the time it takes the Update GUI function to run and it is always less than 1/10th of a second, even when the error occurs.
Here is the trimmed GUI Refresh function:
private void guiHandleTimer(object sender, EventArgs e)
{
//Refresh the Indicators
//Stopwatch
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
//Compact indicator
if (GlobalStatic.compactInd.Changed())
{
pb_Compact.Value = GlobalStatic.compactInd.value;
pb_Compact.Caption = GlobalStatic.compactInd.Caption;
pb_CompactTT.SetToolTip(pb_Compact, GlobalStatic.compactInd.tooltip);
GlobalStatic.compactInd.Reset();
}
//
//Other Indicators removed for readability
//
//Fulfillment Indicator
if (GlobalStatic.fulfillmentInd.Changed())
{
if (GlobalStatic.fulfillmentInd.value <= 59)
{
//Within an Hour, Light Yellow
p_fulfillment.BackColor = Color.LightYellow;
}
else if (GlobalStatic.fulfillmentInd.value <= 300)
{
//Between an hour and 5 hours, Change to Green
p_fulfillment.BackColor = Color.Green;
}
else
{
//Over 5 hours old, Grey
p_fulfillment.BackColor = Color.LightGray;
}
l_LastShipment.Text = GlobalStatic.fulfillmentInd.Caption; <-------This is the line that generates the StackOverflow ----->
ToolTip test = new ToolTip();
test.SetToolTip(p_fulfillment, GlobalStatic.fulfillmentInd.tooltip);
test.SetToolTip(l_LastShipment, GlobalStatic.fulfillmentInd.tooltip);
GlobalStatic.fulfillmentInd.Reset();
}
stopwatch.Stop();
TimeSpan t = stopwatch.Elapsed;
if(TimeSpan.Compare(largestTime,t)==-1)
{
//largestTime is shorter than t, change largestTime
largestTime = t;
}
T_GUI.Text = largestTime.ToString(#"hh\:mm\:ss\:fff");
}
Here is the Timer Setup, called during Form Load, the only place that GUIHandleTimer is mentioned in code:
//GUI Refresh Timer
System.Windows.Forms.Timer guiTimer = new System.Windows.Forms.Timer();
guiTimer.Interval = 1000;
guiTimer.Tick += new EventHandler(guiHandleTimer);
I solved the StackOverflow. The reason it took so long for me to figure it out and finally to ask here, is that Visual Studio was always code-breaking on the Label.Text line highlighted in my original question. Unfortunately, that was not the line causing the StackOverflow, it was the next line that was causing it.
ToolTip test = new ToolTip();
For some reason I didn't move that New ToolTip() out of the Handler after I was done fixing my ToolTips, so I was overloading new ToolTips into the Stack every second. Moving that line out of the function fixed the error.
The weird thing is that wasn't where Visual Studio was marking the StackOverflow error, causing much pain in attempting to resolve it.
New to threading, delegates, and garbage collection.
I have a C# program in Visual Studio 2013 that runs a loop on background thread to constantly update controls on a form in my main thread. While the loop is running (and only when the loop is running), Performance Monitor shows a small but steady increase in Private Bytes for that program.
When the background thread is stopped and joined, there is no decrease in the Private Bytes usage but it no longer increases. This program needs to run a long time with the looping thread so a small leak could become a problem after hours / days.
I can comment out the lines in the loop where it calls for the update method; this successfully curbs the issue. What am I doing to prevent garbage collection in that method?
P.S.: If you point me to a program for looking through the heap, please give me a step-by-step on how to install and use it. I've been a little burned out lately and what I've seen online so far isn't obvious enough for my brain at the moment.
private IAsyncResult iar; // Store the IAsyncResult to check for completion the next time I call it.
public delegate void Assisted_UpdateTimer(int totalSeconds, int secondsElapsed, int secondsRemaining);
public void UpdateTimer(int totalSeconds, int secondsElapsed, int secondsRemaining)
{
if (this.InvokeRequired || pbTimeBar.InvokeRequired) // If we need to be threadsafe
{
if (iar != null) // If we've invoked something before
{
if (iar.IsCompleted) // If the last thing we invoked has completed
{
this.EndInvoke(iar);
Assisted_UpdateTimer _delegate = new Assisted_UpdateTimer(UpdateTimer);
iar = this.BeginInvoke(_delegate, totalSeconds, secondsElapsed, secondsRemaining);
}
}
else // Invoke for the first time
{
Assisted_UpdateTimer _delegate = new Assisted_UpdateTimer(UpdateTimer);
iar = this.BeginInvoke(_delegate, totalSeconds, secondsElapsed, secondsRemaining);
}
}
else // The actual method code
{
TimeSpan timeElapsed = new TimeSpan(0, 0, secondsElapsed);
TimeSpan timeRemaining = new TimeSpan(0, 0, secondsRemaining);
int percent = (int)(((double)secondsElapsed / (double)totalSeconds) * 100);
if (pbTimeBar.Maximum != totalSeconds) pbTimeBar.Maximum = totalSeconds;
if (secondsElapsed >= 0) pbTimeBar.Value = secondsElapsed; // pbTimeBar is a progress bar
// Add text to progress bar
pbTimeBar.CreateGraphics().DrawString(percent + "%", new Font("Arial", (float)8.25, FontStyle.Regular), new SolidBrush(Color.FromArgb(255, 0, 0, 0)), new PointF(pbTimeBar.Width / 2 - 10, pbTimeBar.Height / 2 - 7));
labElapsed.Text = string.Format("{0:00}:{1:00}:{2:00} Elapsed", timeElapsed.Hours, timeElapsed.Minutes, timeElapsed.Seconds);
labRemaining.Text = string.Format("Remaining {0:00}:{1:00}:{2:00}", timeRemaining.Hours, timeRemaining.Minutes, timeRemaining.Seconds);
trayIcon.Text = string.Format("Toast Timer\nRemaining: {0:00}:{1:00}:{2:00}\nElapsed: {3}%", timeRemaining.Hours, timeRemaining.Minutes, timeRemaining.Seconds, percent);
}
}
I haven't checked your full code but the memory leak could be a possible output of strong delegate reference. You see, when you attach a delegate to the event of an object, the object will never be garbage collected unless the delegate reference is removed manually. Here is a documentation reference from msdn to help you understand the scenario better and with possible solutions -
http://msdn.microsoft.com/en-us/library/aa970850(v=vs.110).aspx
Listening for events can lead to memory leaks. The typical technique for listening to an event is to use the language-specific syntax that attaches a handler to an event on a source. For example, in C#, that syntax is: source.SomeEvent += new SomeEventHandler(MyEventHandler).
And for the last part of your question - I usually use Ant Profiler for memory testing. It is not free but the trial version usually works and gives you enough time to solve the issue.
http://www.red-gate.com/products/dotnet-development/ants-performance-profiler/
http://www.red-gate.com/products/dotnet-development/ants-memory-profiler/
Comment: I am guessing repeating call to UpdateTimer could make a possible memory leak if it is attaching new delegates in each call.
I'm making a simple Guess-The-Number game with a GUI. I need to wait on a loop waiting for the user to input a number in a text box and press "OK". How do I wait for an event inside a loop?
Note: I don't want message boxes. This is done in the main window, hence the need to wait for input.
EDIT: I should have explained myself better. I know that there's a loop inside the GUI. What I want is another loop inside a method. Maybe there's a better way to do this. I could code stuff inside the button's event handler, now that I think about it. Although I'd need global variables. Whataver, I'll think about it, but I hope my question is clearer now.
EDIT 2: Sorry that my question wasn't clear and the edit didn't do much help. First of all, the code is too big to be posted here. I'd probably have to post a screenshot of the GUI, so it wouldn't be of much use. Basically, I have two fields, "Max number" and "Number of allowed guesses". The user enters these two and clicks "Play". A new panel becomes available, with a text box and a "Guess" button. The user enters a guess, and the program checks to see if it's correct.
The purpose of the second infinite loop is to avoid global variables. See, each time the user clicks "Play", the game has to generate a new random number as the correct guess. If everything is done inside a method, no problem. But if the "Guess" button's event handler is called multiple times, the number has to be stored as an instance variable of the Form. Sure, it's not big deal, but I think the number should be a property of the method directing the current game, not of the Form.
I'd also have to keep track of the remaining number of guesses outside of the method. Again, it's no big deal. I just want to avoid globals if I can.
Again, I'm sorry that my question wasn't too clear. I'm kind of tired, and I didn't feel like writing too much. If this still isn't clear, then don't bother. I'll think of something.
C# automatically loops infinitely waiting for events until your form is closed. You just need to respond to the button click event.
Jason Down's suggestion is wise, create a new GuessingGame class and add it to your project. I know you're worried about "global variables" (which everyone is taught in school never to use unless you absolutely have to), but think about your design specifications for a minute.
But if the "Guess" button's event handler is called multiple times, the number has to be stored as an instance variable of the Form. Sure, it's not big deal, but I think the number should be a property of the method directing the current game, not of the Form.
As an alternative, store an instance of your GuessingGame class in the form. This is not a global variable! You said so yourself, the point of the game is keep track of the guesses and generate new numbers to guess every time "Play" is clicked. If you store an instance of the game in the form then open another form (e.g. a Help or About box), then the game's instance would not be available (thus, not global).
The GuessingGame object is going to look something like:
public class GuessingGame
{
private static Random _RNG = new Random();
private bool _GameRunning;
private bool _GameWon;
private int _Number;
private int _GuessesRemaining;
public int GuessesRemaining
{
get { return _GuessesRemaining; }
}
public bool GameEnded
{
get { return !_GameRunning; }
}
public bool GameWon
{
get { return _GameWon; }
}
public GuessingGame()
{
_GameRunning = false;
_GameWon = false;
}
public void StartNewGame(int numberOfGuesses, int max)
{
if (max <= 0)
throw new ArgumentOutOfRangeException("max", "Must be > 0");
if (max == int.MaxValue)
_Number = _RNG.Next();
else
_Number = _RNG.Next(0, max + 1);
_GuessesRemaining = numberOfGuesses;
_GameRunning = true;
}
public bool MakeGuess(int guess)
{
if (_GameRunning)
{
_GuessesRemaining--;
if (_GuessesRemaining <= 0)
{
_GameRunning = false;
_GameWon = false;
return false;
}
if (guess == _Number)
{
_GameWon = true;
return true;
}
else
{
return false;
}
}
else
{
throw new Exception("The game is not running. Call StartNewGame() before making a guess.");
}
}
}
This way, all the data related to the game is encapsulated within the class. Hooking up the events is easy in the codebehind of the form:
GuessingGame game = new GuessingGame();
private void btnPlay_Click(object sender, EventArgs e)
{
int numberOfGuesses = Convert.ToInt32(txtNumberOfGuesses.Text);
int max = Convert.ToInt32(txtMax.Text);
game.StartNewGame(numberOfGuesses, max);
}
private void btnGuess_Click(object sender, EventArgs e)
{
int guess = Convert.ToInt32(txtGuess.Text);
bool correct = game.MakeGuess(guess);
if (correct)
lblWin.Visible = true;
if (game.GameEnded)
{
// disable guess button, show loss label
}
}
You should probably look for a book to actually learn windows programming.
The very basics:
1) There is already an infinite loop deep down in the windows code somewhere. Any windows program is constantly looping and scanning for input.
2) Once input is found, this loop fires off an Event.
3) Your mission, should you choose to accept it, is to write event handlers to handle those events.
you are most likely doing it wrong as it has already been pointed out, but you can use this
Application.DoEvents();
to process events when you are on an actual loop
to do it the right way
- don't use a loop
- use an edit box for the input, then a button
- implement the button onclick event
Yes, and What if I am waiting for Speech events, it could happen anytime event when a function is running, I need to handle that without recursively call a function