The requirement is that if user hasn't clicked anything on the winform application in the past 60 seconds, it should perfom an auto-logout action. So apart from resetting the counter on each menu, each button, etc, which is overwhelming, is there any simpler method to detect user has been inactive for 60 seconds?
I'm using this code to calculate inactivity time. It work really good, I hope it could help you too.
public struct LASTINPUTINFO
{
public uint cbSize;
public uint dwTime;
}
[DllImport("User32.dll")]
private static extern Boolean GetLastInputInfo(ref LASTINPUTINFO plii);
/// <summary>
/// Get inactivity time
/// </summary>
/// <returns>Inactivity time in ms</returns>
public static int GetIdleTime()
{
LASTINPUTINFO lastInputInfo = new LASTINPUTINFO();
lastInputInfo.cbSize = (UInt32) System.Runtime.InteropServices.Marshal.SizeOf(lastInputInfo);
if (GetLastInputInfo(ref lastInputInfo))
{
UInt32 lastInputTick = lastInputInfo.dwTime;
if (lastInputTick == 0)
return 0;
return (Environment.TickCount - (Int32)lastInputInfo.dwTime);
}
else
return 0;
}
//In your method :
if (GetIdleTime() >= yourTime)
{
//logout
}
Related
I have WPF allocation and I want to be able to open only one instance of my application.
So i have this 2 classes:
public sealed class SingleInstance
{
public static bool AlreadyRunning()
{
bool running = false;
try
{
// Getting collection of process
Process currentProcess = Process.GetCurrentProcess();
// Check with other process already running
foreach (var p in Process.GetProcesses())
{
if (p.Id != currentProcess.Id) // Check running process
{
if (p.ProcessName.Equals(currentProcess.ProcessName) == true)
{
running = true;
IntPtr hFound = p.MainWindowHandle;
if (User32API.IsIconic(hFound)) // If application is in ICONIC mode then
User32API.ShowWindow(hFound, User32API.SW_RESTORE);
User32API.SetForegroundWindow(hFound); // Activate the window, if process is already running
break;
}
}
}
}
catch { }
return running;
}
}
And:
public class User32API
{
[DllImport("User32.dll")]
public static extern bool IsIconic(IntPtr hWnd);
[DllImport("User32.dll")]
public static extern bool SetForegroundWindow(IntPtr hWnd);
[DllImport("User32.dll")]
public static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
public const int SW_RESTORE = 9;
}
App.xaml:
protected override void OnStartup(StartupEventArgs e)
{
if (SingleInstance.AlreadyRunning())
App.Current.Shutdown(); // Just shutdown the current application,if any instance found.
base.OnStartup(e);
}
So with this solution only one instance is allow but in case the user try to open another instance i can see that in the task bar i have new icon of my application, this icon automatically close when the mouse is over but I want to prevent this icon to be show so I remove this from App.xaml:
StartupUri="MainWindow.xaml"
And now my application not started (probably started but i cannot see it).
Any chance to achieve what I want ?
I need to call MainWindow but I don't know from where
UPDATE
So I try this approach:
protected override void OnStartup(StartupEventArgs e)
{
if (SingleInstance.AlreadyRunning())
App.Current.Shutdown(); // Just shutdown the current application,if any instance found.
base.OnStartup(e);
new MainWindow().Show();
}
And still i can see the second (and third and so...) icons when the user try to open another instance
I am trying to display a simple second counter. I have a dispatchertimer with a tick interval of 1 second and a textbox which I update in the tick handler with the current amount of seconds. There is a tiny amount of work in the tick handler, namely a call to 'tostring()' on some ints.
My issue is that the seconds are slower than they should be. Even if I set the interval to 100 milliseconds and make a check when elapsed, it is still slower than it should be. (over the course of a minute it is roughly 6 seconds slow).
Can anyone point me in the right direction for displaying a second counter that is accurate?
EDIT: Some code here (in .xaml.cs). It is taken from an example which works fine. The difference is that I am setting the Text property of a TextBox, rather than a Value property of another control.
...
this.timer.Interval = TimeSpan.FromMilliseconds(100);
...
private void OnDispatcherTimer_Tick(object sender, EventArgs e) {
if (this.currentValue > TimeSpan.Zero) {
this.currentValue = this.currentValue.Value.Subtract(TimeSpan.FromMilliseconds(100));
} else {
// stop timer etc
}
this.seconds.Text = this.currentValue.Value.Seconds.ToString();
}
Your way of keeping track of time is flawed. You're incrementing a counter each time the timer ticks, but there's no guarantee your timer will execute every 100 ms. And even if it did, you'd have to take into account the execution time of your code. Therefore, no matter what you do, your counter will drift.
What you must do is storing the date at which you started your counter. Then, every time the timer ticks, you compute the number of seconds that have elapsed:
private DateTime TimerStart { get; set; }
private void SomePlaceInYourCode()
{
this.TimerStart = DateTime.Now;
// Create and start the DispatcherTimer
}
private void OnDispatcherTimer_Tick(object sender, EventArgs e) {
var currentValue = DateTime.Now - this.TimerStart;
this.seconds.Text = currentValue.Seconds.ToString();
}
If you care about precise time a dispatchertimer is not good choice.
I thing you should separate counting seconds(time) and displaying on screen.
Use a System.Threading.Timer and use Dispatcher.BeginInvoke() in Timer callback.
simple example:
public partial class MainPage : PhoneApplicationPage
{
private DateTime _startDate;
private int _secondDuration;
private Timer _timer;
// Constructor
public MainPage()
{
InitializeComponent();
_startDate = DateTime.Now;
_secondDuration = 0;
_timer= new Timer(timerCallback, null, 0, 10);
}
private void timerCallback(object state)
{
var now = DateTime.Now;
if (now > _startDate + TimeSpan.FromSeconds(1))
{
_secondDuration += 1;
_startDate = now;
Dispatcher.BeginInvoke(() => { Counter.Text = _secondDuration.ToString(); });
}
}
}
After every 10 milisecond timer checks for one second has elapsed and print to textbox elapsed seconds
or you can do this like:
public partial class MainPage : PhoneApplicationPage
{
private Timer _timer;
private int _secondDuration;
// Constructor
public MainPage()
{
InitializeComponent();
_timer = new Timer(timerCallback, null, 0, 1000);
}
private void timerCallback(object state)
{
_secondDuration += 1;
Dispatcher.BeginInvoke(() => { Counter.Text = _secondDuration.ToString(); });
}
}
I currently use a valueconverters in XAML to display my viewmodel DateTime fields in "x minutes ago" format. I need to have them updated periodically without causing too much overhead. At any one time I have a dozen on screen, and a few dozen off screen. What is the best strategy?
In the constructor of the viewmodel object, have them register themselves to a static 'ViewRefresher' that periodically goes through all the objects and fires PropertyChanged handlers, on the registered fields.
Refresh the content/items control objects that are holding my objects
Something else?
I will go ahead and try both approaches above while I wait for answers and report back in case it helps someone else.
Update:
OK, thanks to csteinmueller for putting me on the events path. Much cleaner than registering/deregistering objects. I believe the following strategy should not be leaky.
public class DateTimeC: INotifyPropertyChanged
{
public DateTime DT {get; set;}
public event PropertyChangedEventHandler PropertyChanged;
public DateTimeC(DateTime dt)
{
DT = dt;
ViewRefresher.FiveSecondsTick += () =>
{ PropertyChanged(this, new PropertyChangedEventArgs("DT")); };
}
}
public delegate void TickHandler();
public static class ViewRefresher
{
private static DispatcherTimer dt = new DispatcherTimer();
private static int counter = 0;
public static event TickHandler FiveSecondsTick;
public static event TickHandler OneMinuteTick;
static ViewRefresher()
{
dt.Interval = TimeSpan.FromSeconds(5);
dt.Tick += Tick;
dt.Start();
}
private static void Tick(object sender, EventArgs e)
{
if (FiveSecondsTick != null)
FiveSecondsTick();
if (counter++ != 12) return;
counter = 0;
if (OneMinuteTick != null)
OneMinuteTick();
}
}
Would have been nice if I could derive from DateTime directly instead of inlining as a field, but it's sealed.
UPDATE 2: This does seem to have a memory leak after all. You need to unhook event for DateTimeC to be garbage-collected, or use a weak reference.
I would choose a System.Timer object togehther with your first approach (all ViewModels register to a collection or event in a static class)
Timer timer;
AutoResetEvent autoEvent = new AutoResetEvent(true);
TimerCallback callback = new TimerCallback(MyCallback);
timer = new Timer(callback, autoEvent, new TimeSpan(0), new Timespan(5));
What is the correct/managed way to SelectAll in a .NET listview that is in virtual mode?
When a ListView's VirtualMode is enabled, the notion of selecting a ListViewItem goes away. The only thing you select are indexes. These are accessible through the SelectedIndices property.
Workaround #1
The first hack is to add iteratively add every index to the SelectedIncides collection:
this.BeginUpdate();
try
{
for (int i = 0; i < this.VirtualListSize; i++)
this.SelectedIndices.Add(i);
}
finally
{
this.EndUpdate();
}
In addition to being poorly designed (a busy loop counting to a hundred thousand), it's poorly performing (it throws an OnSelectedIndexChanged event every iteration). Given that the listview is in virtual mode, it is not unreasonable to expect that there will be quite a few items in the list.
Workaround #2
The Windows ListView control is fully capable of selecting all items at once. Sending the listview a LVM_SETITEMSTATE message, telling it so "select" all items.:
LVITEM lvi;
lvi.stateMask = 2; //only bit 2 (LVIS_SELECTED) is valid
lvi.state = 2; //setting bit two on (i.e. selected)
SendMessage(listview.Handle, LVM_SETITEMSTATE, -1, lvi); //-1 = apply to all items
This works well enough. It happens instantly, and at most only two events are raised:
class NativeMethods
{
private const int LVM_SETITEMSTATE = LVM_FIRST + 43;
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct LVITEM
{
public int mask;
public int iItem;
public int iSubItem;
public int state;
public int stateMask;
[MarshalAs(UnmanagedType.LPTStr)]public string pszText;
public int cchTextMax;
public int iImage;
public IntPtr lParam;
public int iIndent;
public int iGroupId;
public int cColumns;
public IntPtr puColumns;
};
[DllImport("user32.dll", EntryPoint = "SendMessage", CharSet = CharSet.Auto)]
public static extern IntPtr SendMessageLVItem(HandleRef hWnd, int msg, int wParam, ref LVITEM lvi);
/// <summary>
/// Select all rows on the given listview
/// </summary>
/// <param name="listView">The listview whose items are to be selected</param>
public static void SelectAllItems(ListView listView)
{
NativeMethods.SetItemState(listView, -1, 2, 2);
}
/// <summary>
/// Set the item state on the given item
/// </summary>
/// <param name="list">The listview whose item's state is to be changed</param>
/// <param name="itemIndex">The index of the item to be changed</param>
/// <param name="mask">Which bits of the value are to be set?</param>
/// <param name="value">The value to be set</param>
public static void SetItemState(ListView listView, int itemIndex, int mask, int value)
{
LVITEM lvItem = new LVITEM();
lvItem.stateMask = mask;
lvItem.state = value;
SendMessageLVItem(new HandleRef(listView, listView.Handle), LVM_SETITEMSTATE, itemIndex, ref lvItem);
}
}
But it relies on P/Invoke interop. It also relies on the truth that the .NET ListView is a wrapper around the Windows ListView control. This is not always true.
So i'm hoping for the correct, managed, way to SelectAll is a .NET WinForms ListView.
Bonus Chatter
There is no need to resort to P/Invoke in order to deselect all items in a listview:
LVITEM lvi;
lvi.stateMask = 2; //only bit 2 (LVIS_SELECTED) is valid
lvi.state = 1; //setting bit two off (i.e. unselected)
SendMessage(listview.Handle, LVM_SETITEMSTATE, -1, lvi); //-1 = apply to all items
the managed equivalent is just as fast:
listView.SelectedIndices.Clear();
Bonus Reading
Ian Boyd wonders how to SelectAll items of a non-virtual ListView
Making "select all" faster definitely helps someone who wants to add Ctrl+A support
Well I'm using a Window as my custom message box with a couple of controls which are displayed/populated with text depending on which constructor is called.
I have a defined event, which is subscribed to via the original class, this fires once the button has been clicked.
However I can't see how to use this effectively, preferably I'd like to return a bool whether Yes or No was clicked, however obviously my code will carry on executing, hence the method which is subscibed to the button click. Below is some example code to make the issue clearer.
Message Box Window
public partial class CustomMessageBox : Window
{
public delegate void MessageBoxHandler(object sender, EventArgs e);
public event MessageBoxHandler MessageBoxEvent;
public CustomMessageBox()
{
InitializeComponent();
}
public CustomMessageBox(string message)
{
InitializeComponent();
this.txtdescription.Text = message;
}
public CustomMessageBox(string message, string title, string firstBtnText)
{
InitializeComponent();
this.lbltitle.Content = title;
this.txtdescription.Text = message;
this.btnstart.Content = firstBtnText;
}
}
public static class MessageBoxButtonClick
{
public static bool Yes { get; set; }
public static bool No { get; set; }
public static bool Cancel { get; set; }
}
Window Which Instantiates the MessageBox Window
private void StartProcess_Click(object sender, System.Windows.RoutedEventArgs e)
{
foreach (var result in results)
{
if(result.ToBeProcessed)
_validResults.Add(new ToBeProcessed(result.Uri, result.Links));
}
_msgbox = new CustomMessageBox("Each Uri's backlinks will now be collected from Yahoo and filtered, finally each link will be visited and parsed. The operation is undertaken in this manner to avoid temporary IP Blocks from Yahoo's servers.", "Just a FYI", "OK");
_msgbox.MessageBoxEvent += (MessageBoxHandler);
if (_msgBoxProceed)
{
_msgbox.Close();
Yahoo yahoo = new Yahoo();
yahoo.Status.Sending += (StatusChange);
//What I'd like to happen here is the code simply stop, like it does when calling a messagebox is winforms
//e.g.
// if(ProceedClicked == true)
// do stuff
// yahoo.ScrapeYahoo(_validResults[Cycle].Uri, _validResults[Cycle].LinkNumber);
//Cycle++;
}
else
{
_msgbox.Close();
}
}
private void MessageBoxHandler(object sender, EventArgs e)
{
if (MessageBoxButtonClick.Yes)
{
ProceedClicked = true;
}
else
{
ProceedClicked = false;
}
}
Hopefully that makes it clear enough, I can't put any execution code ie call a certain method due to using it multiple times throughout my application.
Very hard to understand what the problem exactly is. Also the code you wrote here, doesn't seemt to have any calls, that would actually show the CustomMessageBoxWindow.
But I'll take a stab at this...
First of all, am I right in guessing that in your main Window you want your code to wait at if(_msgBoxProceed) until the user actually presses a button in your CustomMessageBoxWindow (currently it just shows the message box and continues executing the next statements)?
If so then I'm guessing you are showing your message box window with the Show() method. Use ShowDialog() instead. That will cause code execution to stop, until the message box gets closed.
If you don't want to use a modal dialog then there are two options. Either use thread syncrhonization objects (eg AutoResetEvent) or set up a new event for when the message box closes and continue your code execution in the closed event handler (in StartProcess_Click the last line would be a call to _msgBox.Show() and everything from if(_msgBoxProceed) would be in the closed event handler).