Dows anyone know how I can build a timeout feature into a windows forms app.
The app is event driven, but I am thinking of somehow using a timer which counts down for say 10minutes, and one the timer ticks then we time out the user.
The problem I have is how can I reset the timer each time the mouse is moved or clicked.
Any help appreciated.
Cheers
you can use System.Windows.Forms.Timer.
you can drag it from your toolbox to the designer surface.
Use the properties window to set the Interval Property to the time span you want(miliseconds), the Enabled property should be set to false.
on the for load set the timer Enabled property to true.
(The event handler in the sample are written using c# - sorry about that)
private void Form1_Load(object sender, EventArgs e)
{
timer1.Enabled = true;
}
Double click the timer tick event to register to the event, and close the form on the timer tick
private void timer1_Tick(object sender, EventArgs e)
{
Close();
}
In setting timer.Interval to 0 it does not work ?
Private Sub Form1_MouseMove(ByVal sender As System.Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles MyBase.MouseMove
Me.Timer1.Stop()
Me.Timer1.Start()
End Sub
As bad as it seems, I think the best way for that is to use a system.timer object with a set interval of a few milliseconds at most.
What I saw once is the use of a global variable that would get the time of the last action and that variable would be set to Now (using a global function for example) each time an action is performed. In your timer elapsed event, you check if now if bigger that the last action with your 10 minutes limit and act accordingly.
As for multi-form app, you could either use a different timer on each form , or only have the timer run on your main form.
Hope that helps.
Related
This appears to be an IDE bug specific to VB in VS 2013. The following code produces a compiler warning:
The Task returned from this Async Function will be dropped, and any exceptions in it ignored. Consider changing it to an Async Sub so its exceptions are propagated.
Well, clearly it already is an Async Sub (void in C#). While the general rule is to avoid Async Subs, it's perfectly acceptable—and even advised—to do so with top-level event handlers such as this.
That's why I'm calling this an IDE bug. It only manifests when we set an event handler in VB (using either AddHandler or the Handles keyword). I'm not finding other reports of it, which frankly is odd... I can't imagine I'm the only one seeing it.
But to the question: can anyone report whether this nuisance has been fixed in VS 2015? If it has, I'll have further justification for upgrading sooner rather than later. (I have other reasons holding me back for the time being that aren't appropriate for discussion here.)
The source of the problem is a relaxed delegate without an implicit widening conversion.
The Click event accepts an Object as the first parameter, but the handler accepts Button which makes it a relaxed delegate.
Because the handler's signature is more restrictive than the event signature, the code as is will only compile with Option Strict Off, and generate the seemingly spurious warning about a dropped async task.
Note that the problem does not occur when a widening conversion exists (e.g. where the event has Button and the handler has Object).
To fix the problem, you can:
Change the handler's signature to match the event signature exactly:
Private Async Sub cmdStart_Click(sender As Object, e As RoutedEventArgs)
Wrap the AddressOf into a delegate constructor:
AddHandler cmdStart.Click, New RoutedEventHandler(AddressOf cmdStart_Click)
Ditch the AddressOf and wrap the call to the handler into a lambda:
AddHandler cmdStart.Click, Sub(sender As Object, e As RoutedEventArgs)
Me.cmdStart_Click(sender, e)
End Sub
As for why this is happening and whose fault that is (yours, IDE's or the compiler's), I cannot tell you for sure.
However there is one thing I can see.
These two lines of code:
AddHandler cmdStart.Click, AddressOf RelaxedHandler
AddHandler cmdStart.Click, Sub(a0 As Object, a1 As EventArgs)
Me.RelaxedHandler(a0, a1)
End Sub
produce identical IL code, as far as the ILSpy is concerned:
this.cmdStart.Click += delegate(object a0, EventArgs a1)
{
this.RelaxedHandler((Button)a0, a1);
}
;
this.cmdStart.Click += delegate(object a0, EventArgs a1)
{
this.RelaxedHandler((Button)a0, a1);
}
;
but the first line generates a warning and the second line does not.
I try to add code to Hardware Back Button on WP8.1
Private Sub onBackPressed(sender As Object, e As BackPressedEventArgs)
some code
End Sub
But when I press Back - my app just closes.
onBackPressed event is not happening at all, how can I fixed it?
Did you register for that event?
You need to first add this youself
HardwareButtons.BackPressed += HardwareButtons_BackPressed; ( sorry c# )
cfr http://invokeit.wordpress.com/2014/04/14/backbutton-handling-with-winprt-and-windows-phone-8-1-wpdev/
I know that for C# its easy.
Add this to the constructor:
HardwareButtons.BackPressed += this.Hardware_BackButton_Pressed;
And use:
public void Hardware_BackButton_Pressed(object sender, BackPressedEventArgs e)
{
// do things here..
}
In a DataGridView, pressing SHIFT and SPACE will by default select the entire row. The only solution I've found (referenced at vb.net DataGridView - Replace Shortcut Key with typed character) is to turn off the row select feature. While that works, it's not ideal, because I would still like to be able to select the whole row using the row selector (for example, to delete the row), and by changing the SelectionMode property to anything other than RowHeaderSelect I lose that ability. Is there a way to trap just the SHIFT+SPACE combination and replace it with a simple SPACE? It seems like none of the key events even recognize that keystroke when the control's MutiSelect property is set to True and the SelectionMode property is set to RowHeaderSelect, so I can't use those.
ETA: I thought maybe turning off MultiSelect and changing the selection mode to CellSelect, then adding an event handler for the RowHeaderMouseClick event would work...nope.
The best way I figured out how to accomplish this was to inherit from DataGridView and override the ProcessCmdKey method. Then you can intercept the Shift+Space and just send on Space. Just add this class to your project and switch all of your DataGridViews to MyDataGridViews. My solution draws inspiration from this DataGridView keydown event not working in C# SO question (that also explains why Zaggler's solution doesn't work) and this SendKeys in ProcessCmdKey: change Shift-Space to just a Space Bytes.com post. Sorry, but it's in C#.
class MyDataGridView : System.Windows.Forms.DataGridView
{
protected override bool ProcessCmdKey(ref System.Windows.Forms.Message msg, System.Windows.Forms.Keys keyData)
{
if (keyData == (System.Windows.Forms.Keys.Space | System.Windows.Forms.Keys.Shift))
{
// DataGridView is dumb and will select a row when the user types Shift+Space
// if you have the DGV set so that you can click a row header to select a row (for example, to delete the row)
// this method will intercept Shift+Space and just send on Space so that the DGV properly handles this.
// For example, if I type "ME TYPING IN ALL CAPS" it ends up looking like "METYPINGINALLCAPS".
// Or if I type "Note: I have some OS thing to talk about" it looks like "Note:Ihave some OSthing to talk about"
byte[] keyStates = new byte[255];
UnsafeNativeMethods.GetKeyboardState(keyStates);
byte shiftKeyState = keyStates[16];
keyStates[16] = 0; // turn off the shift key
UnsafeNativeMethods.SetKeyboardState(keyStates);
System.Windows.Forms.SendKeys.SendWait(" ");
keyStates[16] = shiftKeyState; // turn the shift key back on
UnsafeNativeMethods.SetKeyboardState(keyStates);
return true;
}
return base.ProcessCmdKey(ref msg, keyData);
}
[System.Security.SuppressUnmanagedCodeSecurity]
internal static class UnsafeNativeMethods
{
[System.Runtime.InteropServices.DllImport("user32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto)]
public static extern int GetKeyboardState(byte[] keystate);
[System.Runtime.InteropServices.DllImport("user32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto)]
public static extern int SetKeyboardState(byte[] keystate);
}
}
This was my solution:
private void dataGridView_CellBeginEdit(object sender, DataGridViewCellCancelEventArgs e)
{
dataGridView.SelectionMode = DataGridViewSelectionMode.CellSelect;
}
private void dataGridView_CellEndEdit(object sender, DataGridViewCellEventArgs e)
{
dataGridView.SelectionMode = DataGridViewSelectionMode.RowHeaderSelect;
}
Here this works fine for me....
Private Sub DataGridView1_KeyDown(sender As Object, e As System.Windows.Forms.KeyEventArgs) Handles DataGridView1.KeyDown
'Lets see what keys we have down shall we?'
If My.Computer.Keyboard.ShiftKeyDown And e.KeyCode = Keys.Space Then
DataGridView1.CurrentCell.Selected = False
End If
End Sub
Here's another way..
Private Sub DataGridView1_KeyDown(sender As Object, e As System.Windows.Forms.KeyEventArgs) Handles DataGridView1.KeyDown
'Lets see what keys we have down shall we?'
If My.Computer.Keyboard.ShiftKeyDown And e.KeyCode = Keys.Space Then
'SendKeys.Send(Keys.Space)
DataGridView1.CurrentCell.Selected = False
End If
End Sub
Just experiment with them and I hope something works out for you?
Quite a simple question, when the selected index of a list view is changed, the event fires twice, once for deselection and a second time to select the next item.
I need to use the event when selecting or deselecting at different times however whan deselecting only to reselect a moment later it makes half my ui flash from enabled being on to off and back on again, it also causes a fair bit of code to run so I just need a way of avoiding the deselection firing if it was another item that was clicked and not blank space (for deselection)
Dave R said to use a 100ms timer here : Am I missing something with my ListView selection event handling
which sounds like it would work but seems quite untidy or generally a bad way of doing it.
My only other idea was to use the click event and then find the item at the location? but I'd rather not go to the hassle
thanks in advance!
-EDIT-
I've just thought that the click event would fire first so I could set a flag that skips selection index changed code if the click event happened on an item and then resets the flag after it's been used therefore skipping the deselection? I'll have a look now but again doesnt feel like a very efficient or easy way of doing something that sounds quite simple?
Use the ItemSelectionChanged event instead - the ListViewItemSelectionChangedEventArgs can tell you which item caused it to fire, and whether it's selected or not.
i just tried another solution which is potentially without any delay, it worked for me:
If ListView1.Items(ListView1.FocusedItem.Index).Selected = False Then
'This is the deselected value
MsgBox("Deselected: " & ListView1.Items(ListView1.FocusedItem.Index).SubItems(0).Text)
Else
'This is the new selected value
MsgBox("Selected: " & ListView1.Items(ListView1.FocusedItem.Index).SubItems(0).Text)
End If
The following solution works even with a delay of 1 ms. To be sure it works probably you can choose a higher delay, 10 ms for example, but a delay of 100 ms will make it a bit laggy on selecting "nothing". Here's the C#-Code:
public class FixedListView : ListView
{
private Timer _ItemSelectionChangedTimer = new Timer();
private Timer _SelectedIndexChangedTimer = new Timer();
private ListViewItemSelectionChangedEventArgs _ItemSelectionChangedEventArgs;
private EventArgs _SelectedIndexChangedEventArgs;
public FixedListView()
{
this._ItemSelectionChangedTimer.Interval = 1;
this._SelectedIndexChangedTimer.Interval = 1;
this._ItemSelectionChangedTimer.Tick += (sender, e) =>
{
this.OnItemSelectionChanged(this._ItemSelectionChangedEventArgs);
this._ItemSelectionChangedEventArgs = null;
};
this._SelectedIndexChangedTimer.Tick += (sender, e) =>
{
this.OnSelectedIndexChanged(this._SelectedIndexChangedEventArgs);
this._SelectedIndexChangedEventArgs = null;
};
}
protected override void OnItemSelectionChanged(ListViewItemSelectionChangedEventArgs e)
{
if (this._ItemSelectionChangedTimer.Enabled)
{
this._ItemSelectionChangedTimer.Stop();
base.OnItemSelectionChanged(e);
}
else
{
this._ItemSelectionChangedEventArgs = e;
this._ItemSelectionChangedTimer.Start();
}
}
protected override void OnSelectedIndexChanged(EventArgs e)
{
if (this._SelectedIndexChangedTimer.Enabled)
{
this._SelectedIndexChangedTimer.Stop();
base.OnSelectedIndexChanged(e);
}
else
{
this._SelectedIndexChangedEventArgs = e;
this._SelectedIndexChangedTimer.Start();
}
}
}
And here is the VB-Code:
Public Class FixedListBox
Inherits ListView
Public Sub New()
Me._ItemSelectionChangedTimer.Interval = 1
Me._SelectedIndexChangedTimer.Interval = 1
AddHandler Me._ItemSelectionChangedTimer.Tick, _
Sub(sender, e)
Me.OnItemSelectionChanged(Me._ItemSelectionChangedEventArgs)
Me._ItemSelectionChangedEventArgs = Nothing
End Sub
AddHandler Me._SelectedIndexChangedTimer.Tick, _
Sub(sender, e)
Me.OnSelectedIndexChanged(Me._SelectedIndexChangedEventArgs)
Me._SelectedIndexChangedEventArgs = Nothing
End Sub
End Sub
Private _ItemSelectionChangedTimer As New Timer()
Private _SelectedIndexChangedTimer As New Timer()
Private _ItemSelectionChangedEventArgs As ListViewItemSelectionChangedEventArgs
Private _SelectedIndexChangedEventArgs As EventArgs
Protected Overrides Sub OnItemSelectionChanged(e As ListViewItemSelectionChangedEventArgs)
If Me._ItemSelectionChangedTimer.Enabled Then
Me._ItemSelectionChangedTimer.Stop()
MyBase.OnItemSelectionChanged(e)
Else
Me._ItemSelectionChangedEventArgs = e
Me._ItemSelectionChangedTimer.Start()
End If
End Sub
Protected Overrides Sub OnSelectedIndexChanged(e As EventArgs)
If Me._SelectedIndexChangedTimer.Enabled Then
Me._SelectedIndexChangedTimer.Stop()
MyBase.OnSelectedIndexChanged(e)
Else
Me._SelectedIndexChangedEventArgs = e
Me._SelectedIndexChangedTimer.Start()
End If
End Sub
End Class
You can use the control like a normal ListView but SelectedIndexChanged and ItemSelectionChanged will fire only once.
Have fun...
Just check in the SelectedIndexChanged event whether the focused item is null and exit.
ListView^ item = listView1-> FocusedItem; //get selected item
if (item == nullptr){return;) // this line exits when deselection event fires
String^ data1 = Convert::ToString ( item-> SubItems [0] ); // get your data from columns like so
MessageBox::Show (data1); // display
note that you could grab data under several columns by changing index provided in SubItems
And using timers and delays will just incur overhead especially with large databases causing your application to slow Code in visual C++ .NET but the same theory applies for C# and others
Enjoy!!
When the user closes my application I'd like to be able to prompt them with a confirmation if they have unsaved changes, and cancel the application's closing if they indicate to do so. The Application's Exit event does not allow cancellation. Is there any way to do this?
Catch the Closing event of the MainWindow instead:
App.Current.MainWindow.Closing += MainWindow_Closing;
Then you can set the Cancel property to true in the event handler if necessary:
private void MainWindow_Closing(object sender, System.ComponentModel.ClosingEventArgs e)
{
e.Cancel = true;
}
Hope this helps...
Chris