This question already has answers here:
Detect if user Idle on windows universal app
(2 answers)
Closed 6 years ago.
I wanted to make a function that would timeout and navigate to the main page if the user is idle for a certain period of time. After a little research, I found that the ThreadPoolTimer should suit my needs. Testing it I decided to use a 10 sec interval.
timer =ThreadPoolTimer.CreatePeriodicTimer(Timer_Tick,TimeSpan.FromSeconds(10));
And this is where I'm at a loss. I couldn't figure out a way to check user input on a UWP without having to individually check PointerPressed, PointerExited, etc. So I did some more digging and I found a block of code that's supposed to give you a boolean value if the user is idle or not.
public static uint GetIdleTime()
{
LASTINPUTINFO lastInPut = new LASTINPUTINFO();
lastInPut.cbSize = (uint)Marshal.SizeOf(lastInPut);
GetLastInputInfo(ref lastInPut);
return ((uint)Environment.TickCount - lastInPut.dwTime);
}
public static bool IsUserIdle()
{
uint idleTime = (uint)Environment.TickCount - GetLastInputEventTickCount();
if (idleTime > 0)
{
idleTime = (idleTime / 1000);
}
else
{
idleTime = 0;
}
//user is idle for 10 sec
bool b = (idleTime >= 10);
return b;
}
private static uint GetLastInputEventTickCount()
{
LASTINPUTINFO lii = new LASTINPUTINFO();
lii.cbSize = (uint)Marshal.SizeOf(lii);
lii.dwTime = 0;
uint p = GetLastInputInfo(ref lii) ? lii.dwTime : 0;
return p;
}
[StructLayout(LayoutKind.Sequential)]
private struct LASTINPUTINFO
{
public static readonly int SizeOf = Marshal.SizeOf<LASTINPUTINFO>();
[MarshalAs(UnmanagedType.U4)]
public UInt32 cbSize;
[MarshalAs(UnmanagedType.U4)]
public UInt32 dwTime;
}
[DllImport("user32.dll")]
private static extern bool GetLastInputInfo(ref LASTINPUTINFO plii);
I then call the function in the tick function and use the conditional statement if IsUserIdle() is equal to true then navigate to the main page.
public static void Timer_Tick(object sender)
{
if (IsUserIdle() == true)
{
Frame.Navigate(typeof(MainPage));
}
}
But when I start it nothing happens, and after I set a couple breakpoints I found that IsUserIdle() never returns a true value even after 10 sec of inactivity. I am completely stuck so any help would be appreciated.
GetLastInputInfo isn't supported for Windows store apps:
Minimum supported client: Windows 2000 Professional [desktop apps only]
I'm not aware of any intrinsic UWP API to detect if the user is idle, but it's definitely possible to whip up your own mechanism for doing so.
I couldn't figure out a way to check user input on a UWP without having to individually check PointerPressed, PointerExited, etc.
What's so bad about that approach? Here's my attempt:
App.xaml.cs
public sealed partial class App : Application
{
public static new App Current => (App)Application.Current;
public event EventHandler IsIdleChanged;
private DispatcherTimer idleTimer;
private bool isIdle;
public bool IsIdle
{
get
{
return isIdle;
}
private set
{
if (isIdle != value)
{
isIdle = value;
IsIdleChanged?.Invoke(this, EventArgs.Empty);
}
}
}
protected override void OnLaunched(LaunchActivatedEventArgs e)
{
idleTimer = new DispatcherTimer();
idleTimer.Interval = TimeSpan.FromSeconds(10); // 10s idle delay
idleTimer.Tick += onIdleTimerTick;
Window.Current.CoreWindow.PointerMoved += onCoreWindowPointerMoved;
}
private void onIdleTimerTick(object sender, object e)
{
idleTimer.Stop();
IsIdle = true;
}
private void onCoreWindowPointerMoved(CoreWindow sender, PointerEventArgs args)
{
idleTimer.Stop();
idleTimer.Start();
IsIdle = false;
}
}
MainPage.xaml.cs
public sealed partial class MainPage : Page
{
protected override void OnNavigatedTo(NavigationEventArgs e)
{
App.Current.IsIdleChanged += onIsIdleChanged;
}
protected override void OnNavigatedFrom(NavigationEventArgs e)
{
App.Current.IsIdleChanged -= onIsIdleChanged;
}
private void onIsIdleChanged(object sender, EventArgs e)
{
System.Diagnostics.Debug.WriteLine($"IsIdle: {App.Current.IsIdle}");
}
}
Idle is detected when the pointer hasn't moved for 10s within the app window. This will work also for touch-only apps (like mobile apps) because PointerMoved will fire when the window is tapped, too.
Related
I have been working on this issues off and on for weeks. I hace a Visual Studio form view application that load a webpage on located on my server. What I would like is to have the application to reconnect and reload the web page if for whatever reason the connectivity drops out. The PC which runs the application is at a remote location so I am trying to force the application to reconnect.
At the moment I have a half working method but it does not always work. Is there a more robust way of writing the code below.
Many thanks in advance for your time.
My reconnect code:
using System;
using System.Runtime.InteropServices;
using System.Threading;
using System.Windows.Forms;
namespace NaveX_Browser
{
public partial class MainForm : Form
{
public MainForm()
{
if (!InternetExplorerBrowserEmulation.IsBrowserEmulationSet())
{
InternetExplorerBrowserEmulation.SetBrowserEmulationVersion();
}
InitializeComponent();
Cursor.Hide();
}
private void MainForm_Load(object sender, EventArgs e)
{
browser.DocumentTitleChanged += ValidateConnection;
}
private bool offline;
private void ValidateConnection(object sender, EventArgs e)
{
if (offline)
return;
//if (browser.DocumentTitle == "Internet Explorer cannot display the webpage" || browser.DocumentTitle == "Navigation Canceled" || browser.DocumentTitle == "This page can’t be displayed" || browser.DocumentTitle == "Broadband Link - Error")
if (browser.DocumentTitle != string.Empty)
{
offline = true;
browser.Visible = false;
ThreadPool.QueueUserWorkItem(obj => WaitConnection());
return;
}
browser.Visible = true;
}
private int countdown = 20;
private void WaitConnection()
{
while (!Native.IsOnline("http://www.example.com"))
{
Invoke((MethodInvoker)(() => { connectLbl.Text = String.Format(" Trying to connect ...[{0}]\n\nPlease check your Internet router\n\nNaveX Systems Limited", countdown--); }));
if (countdown == 0)
countdown = 20;
Thread.Sleep(TimeSpan.FromSeconds(5));
}
offline = false;
Invoke((MethodInvoker)(() =>
{
browser.Refresh();
browser.Visible = true;
countdown = 20;
}));
}
private void browser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
}
}
public class Native
{
[DllImport("wininet.dll", SetLastError = true)]
static extern bool InternetCheckConnection(string lpszUrl, int dwFlags, int dwReserved);
public static bool IsOnline(string url)
{
return InternetCheckConnection(url, 1, 0);
}
}
}
Update
While not the most elegant solution, one method that seems to work is to watch the relevant registry value. Here's an example using WMI to do this. I'd be happy to hear from anyone if there's a better solution than this.
using System;
using System.Management;
using System.Security.Principal;
using System.Windows.Forms;
using Microsoft.Win32;
public partial class MainForm : Form
{
public MainForm()
{
this.InitializeComponent();
this.UpdateModeFromRegistry();
var currentUser = WindowsIdentity.GetCurrent();
if (currentUser != null && currentUser.User != null)
{
var wqlEventQuery = new EventQuery(string.Format(#"SELECT * FROM RegistryValueChangeEvent WHERE Hive='HKEY_USERS' AND KeyPath='{0}\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\ImmersiveShell' AND ValueName='TabletMode'", currentUser.User.Value));
var managementEventWatcher = new ManagementEventWatcher(wqlEventQuery);
managementEventWatcher.EventArrived += this.ManagementEventWatcher_EventArrived;
managementEventWatcher.Start();
}
}
private void ManagementEventWatcher_EventArrived(object sender, EventArrivedEventArgs e)
{
this.UpdateModeFromRegistry();
}
private void UpdateModeFromRegistry()
{
var tabletMode = (int)Registry.GetValue("HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\ImmersiveShell", "TabletMode", 0);
if (tabletMode == 1)
{
Console.Write(#"Tablet mode is enabled");
}
else
{
Console.Write(#"Tablet mode is disabled");
}
}
}
Original Question
I'm interested in make some optimizations in my Windows Forms application based on whether a user is in "Tablet Mode" (or not) using the new Windows 10 Continuum feature.
There is some guidance on how to do this in a UWP project at https://msdn.microsoft.com/en-us/library/windows/hardware/dn917883(v=vs.85).aspx (i.e. check the current view's UserInteractionMode to see if it's UserInteractionMode.Mouse or UserInteractionMode.Touch), however I'm not sure if or how I can do the same in Windows Forms.
Would there be any way I can call the necessary UWP APIs from my Windows Forms application, or is there some Windows Forms equivalent I can use?
To get whether the system is in tablet mode or not, query the system metric ConvertibleSlateMode like so (not tested, but it should work fine as far back as XP):
public static class TabletPCSupport
{
private static readonly int SM_CONVERTIBLESLATEMODE = 0x2003;
private static readonly int SM_TABLETPC = 0x56;
private static Boolean isTabletPC = false;
public static Boolean SupportsTabletMode { get { return isTabletPC; }}
public static Boolean IsTabletMode
{
get
{
return QueryTabletMode();
}
}
static TabletPCSupport ()
{
isTabletPC = (GetSystemMetrics(SM_TABLETPC) != 0);
}
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto, EntryPoint = "GetSystemMetrics")]
private static extern int GetSystemMetrics (int nIndex);
private static Boolean QueryTabletMode ()
{
int state = GetSystemMetrics(SM_CONVERTIBLESLATEMODE);
return (state == 0) && isTabletPC;
}
}
(Documentation here)
I have looked everywhere for how to tell if Windows 10 is in tablet mode and here is the simplest solution I found:
bool bIsTabletMode = false;
var uiMode = UIViewSettings.GetForCurrentView().UserInteractionMode;
if (uiMode == Windows.UI.ViewManagement.UserInteractionMode.Touch)
bIsTabletMode = true;
else
bIsTabletMode = false;
// (Could also compare with .Mouse instead of .Touch)
According to this article, you cant listen to WM_SETTINGCHANGE message. Here is a short c# sample :
protected override void WndProc(ref Message m)
{
const int WM_WININICHANGE = 0x001A,
WM_SETTINGCHANGE = WM_WININICHANGE;
if (m.Msg == WM_SETTINGCHANGE)
{
if (Marshal.PtrToStringUni(m.LParam) == "UserInteractionMode")
{
MessageBox.Show(Environment.OSVersion.VersionString);
}
}
base.WndProc(ref m);
}
For Windows 10 you should then perform some COM Interfacing with some WinRT stuff, to check if you are in UserInteractionMode.Mouse (desktop) or UserInteractionMode.Touch (tablet).
The Com Interop stuff looks rather tricky but it seems to be the only way if you are in a stock win32 app.
As I mentioned in this question, I am trying to implement a feature in my app whereby placing a cursor over some point for a while (say 3-5 seconds) triggers a double-click event. Based on the answers provided in that thread, I wrote the following. This code is not working as expected. Can someone please help?
#region Timer Mouse Double Click event
timer.Elapsed += new ElapsedEventHandler(timer_Elapsed);
//Here, the timer for Timer click event will start when mouse hovers over an area
private void form_MouseHover(object sender, System.EventArgs e)
{
timer.Start();
}
private void form_MouseLeave(object sender, System.EventArgs e)
{
timer.Stop();
}
void timer_Elapsed(object sender, ElapsedEventArgs e)
{
timer.Stop();
DoubleClickEvent();
}
//This method allows the user to click a file/folder by hovering/keeping still the mouse for specified time
void DoubleClickEvent()
{
DoClickMouse(0x2); // Left mouse button down
DoClickMouse(0x4); // Left mouse button up
}
static void DoClickMouse(int mouseButton)
{
var input = new INPUT()
{
dwType = 0, // Mouse input
mi = new MOUSEINPUT() { dwFlags = mouseButton }
};
if (SendInput(1, input, Marshal.SizeOf(input)) == 0)
{
throw new Exception();
}
}
[StructLayout(LayoutKind.Sequential)]
struct MOUSEINPUT
{
int dx;
int dy;
int mouseData;
public int dwFlags;
int time;
IntPtr dwExtraInfo;
}
struct INPUT
{
public uint dwType;
public MOUSEINPUT mi;
}
[DllImport("user32.dll", SetLastError = true)]
static extern uint SendInput(uint cInputs, INPUT input, int size);
#endregion
At first glance if your expecting a double click your are only doing a single click.
Down then up is one mouse click, shouldn't you do.
void DoubleClickEvent()
{
DoClickMouse(0x2); // Left mouse button down
DoClickMouse(0x4); // Left mouse button up
DoClickMouse(0x2); // Left mouse button down
DoClickMouse(0x4); // Left mouse button up
}
I hope it's not bad etiquette to provide two answers, however this is very different from my previous answer I felt editing for improvements wasn't correct.
By the looks of it you only have an event handler on the form, once you hover over a control on your form that will trigger your MouseLeave event of the form.
What you need is to add an event handler to every control on your form, something like this should do it.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
this.MouseHover += new EventHandler(MouseHoverEvent);
this.MouseLeave +=new EventHandler(MouseLeaveEvent);
timer1.Tick += new EventHandler(timer1_Tick);
foreach (Control item in this.Controls)
{
item.MouseHover += new EventHandler(MouseHoverEvent);
item.MouseLeave += new EventHandler(MouseLeaveEvent);
}
}
void timer1_Tick(object sender, EventArgs e)
{
timer1.Stop();
DoubleClickEvent();
}
void MouseLeaveEvent(object sender, EventArgs e)
{
timer1.Stop();
}
void MouseHoverEvent(object sender, EventArgs e)
{
timer1.Start();
}
}
It might be better to write this code as a single call to SendInput passing all the mouse downs and ups in one array. If you do this, SendInput guarantees that no other keys get in between the sequence. For example if a user has Alt + N keys held in theory it could sneak in - and change the auto-clicker clicking Yes to instead trigger a No (with a Alt + N keys held).
That being said however, I think the answer to our question is here: SendInput doesn't perform click mouse button unless I move cursor
Basic Idea:
I use MouseAdapter so that I don't have to override everything under the sun.
my MouseAdapter object has a MouseTimer which extends a swing Timer,
and an ActionListener with an overridden anonymous actionPerformed method.
I may have over thought/ or under thought when to start and stop the timer object.
Basically all it does is print out when it is single clicked or when it is double clicked.
package mouseUtils;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.Timer;
/**
*
* #author jcpartri
*/
public class MyMouseAdapter extends MouseAdapter{
private Integer mouseDoubleClickInterval = (int)
Toolkit.getDefaultToolkit().getDesktopProperty("awt.multiClickInterval");
private MouseEvent event = null;
private ActionListener taskPerformer = new ActionListener(){
#Override
public void actionPerformed(ActionEvent e){
if(event.getClickCount() == 2){
//mouseDoubleClicked(event);
mouseTimer.stop();
}
if(event.getClickCount() == 1){
//mouseSingleClicked(event);
mouseTimer.stop();
}
}
};
Class MouseTimer is a child of class Timer. When the Timer fires after a delay, there is a check to see if there was a single or double click within that timespan.
private MouseTimer mouseTimer = new
MouseTimer(getMouseDoubleClickInterval(),taskPerformer);
//The DebugClock helps me to see how long a process that I have programmed takes from
start to finish.
private DebugClock clock = new DebugClock();
//Constructors
public MyMouseAdapter(){
super();
}
#Override
public void mouseClicked(MouseEvent e){
event = e;
if(e.getClickCount() == 1){
mouseTimer.setInitialDelay(mouseDoubleClickInterval);
mouseTimer.start();
}
mouseTimer.setNumOfClicks();
}
public void mouseSingleClicked(MouseEvent e){
p("Mouse was SingleClicked!!!\n");
}
public void mouseDoubleClicked(MouseEvent e){
p("Mouse was DoubleClicked!!!\n");
}
#Override
public void mouseMoved(MouseEvent e){
event = e;
mouseTimer.resetNumOfClicks();
mouseTimer.stop();
}
//Setters and Getters for MouseAdapter
public Integer getMouseDoubleClickInterval(){
return this.mouseDoubleClickInterval;
}
//Timer Classes
private class MouseTimer extends Timer{
//Constructors
public MouseTimer(int delay, ActionListener taskPerformer){
super(delay,taskPerformer);
}
//Instance variables
private int numOfClicks = 0;
//Setters and Getters
public int getNumOfClicks(){
return this.numOfClicks;
}
public void setNumOfClicks(){
this.numOfClicks++;
}
public void resetNumOfClicks(){
this.numOfClicks = 0;
}
}
//Basic Printing Classes
private void p(String message){
System.out.print(message);
}
}
class DebugClock{
private long startTime = 0;
private long endTime = 0;
//Setters and Getters
public long getStartTime(){
return this.startTime;
}
public void setStartTime(long start){
this.startTime = start;
}
public long getEndTime(){
return this.endTime;
}
public void setEndTime(long end){
this.endTime = end;
}
//Constructors
public DebugClock(){
}
//Methods
public float getTimeInMilliSeconds(){
float seconds = (this.endTime - this.startTime);
return seconds;
}
}
This is my first post here, but I've using this site regularly to help me with my own app's, and I should say that this site has been a great help to me, so thanks to everyone.
Now my question:
I'm developing my first software app that exchanges data between a sql server and the app itself. It's beeing developed in C#. Saving or retreiving data from the sql server database is no problem.
What I want is a way to inform the user of the delay between the local machine (where the app is installed) and the server. I can make some animations or simply display some text messages. What I need help with is how to create the code that activates/fires/runs when that server communication time is running.
If you can't understand the idea, picture a video game. When it's loading (in some games) you can see the loading screen before the game starts. I need some code that displays that "loading window" when the the app is downloading or uploading data from/to the server.
I would appreciate any code example or web site recommendation.
PS: Sorry for the extensive text, but I want to make sure everyone understand so I don't have to repeat it again :P
How do I implement a progress bar in C#?
How to create a smooth progress bar in Visual C#
ProgressBar Class
I have developed a simple PleaseWait class 2 years ago, but I didn't update this class, It works very well, have look hope this will give you an idea to implement your logic.
public partial class frmWait : Form
{
public frmWait()
{
InitializeComponent();
}
bool _isMoving = false;
int _moveStart_x = 0;
int _moveStart_y = 0;
private void tmrProgress_Tick(object sender, EventArgs e)
{
if (barProgress.Value == barProgress.Maximum)
barProgress.Value = barProgress.Minimum;
else
barProgress.Value += 1;
}
private void btnCancel_Click(object sender, EventArgs e)
{
Close();
PleaseWait.Abort();
}
protected override CreateParams CreateParams
{
get
{
System.Windows.Forms.CreateParams p = base.CreateParams;
p.ClassStyle += 0x20000;
p.ExStyle += 0x8000000;
return p;
}
}
protected override void WndProc(ref Message m)
{
const int WM_NCHITTEST = 132;
base.WndProc(ref m);
switch (m.Msg)
{
case WM_NCHITTEST:
if (m.Result.ToInt32() == 1)
m.Result = new IntPtr(2);
break;
}
}
private void panelEx1_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
_isMoving = true;
_moveStart_x = e.X;
_moveStart_y = e.Y;
}
}
private void panelEx1_MouseUp(object sender, MouseEventArgs e)
{
_isMoving = false;
}
private void pnlContainer_MouseMove(object sender, MouseEventArgs e)
{
if (_isMoving)
this.Location = new Point(Location.X + e.X - _moveStart_x, Location.Y + e.Y - _moveStart_y);
}
}
public class PleaseWait
{
#region Static Operations
private static Boolean _isAborted = false;
private static Boolean _isVisible = false;
private static frmWait _waitForm;
private static String _waitingState = "";
private static Boolean _autoClose = false;
private static Boolean _cancelable = false;
private static System.Threading.Thread _waiterThred;
public delegate void CancelButtonPressed();
public static event CancelButtonPressed OnCancel;
public static Boolean AutoClose
{
get { return PleaseWait._autoClose; }
set { PleaseWait._autoClose = value; }
}
public static string WaitingState
{
get { return PleaseWait._waitingState; }
set { PleaseWait._waitingState = value; }
}
public static bool IsVisible
{
get { return _isVisible; }
internal set { _isVisible = value; }
}
public static void ShowPleaseWait()
{
ShowPleaseWait("", _autoClose, false);
}
public static void ShowPleaseWait(string waitingState)
{
ShowPleaseWait(waitingState, _autoClose, false);
}
public static void ShowPleaseWait(bool autoClose)
{
ShowPleaseWait("", autoClose, false);
}
public static void ShowPleaseWait(string waitingState, bool autoClose, bool cancelable)
{
if (_waiterThred != null)
{
if (_isVisible)
{
// the please wait it woking, just continue and apply the changes
_waitingState = waitingState;
_autoClose = autoClose;
_cancelable = cancelable;
return;
}
else
{
_waiterThred.Abort();
_waiterThred = null;
}
}
_waitingState = waitingState;
_autoClose = autoClose;
_cancelable = cancelable;
_isAborted = false;
_isVisible = false;
if (_autoClose)
Application.Idle += new EventHandler(Application_Idle);
_waiterThred = new System.Threading.Thread(DisplayWaitingForm);
_waiterThred.IsBackground = true;
_waiterThred.Name = "Please Wait....";
_waiterThred.Start();
Application.DoEvents();
}
public static void Abort()
{
_isAborted = true;
}
private static void Application_Idle(object sender, EventArgs e)
{
if (_autoClose)
_isAborted = true;
}
private static void DisplayWaitingForm()
{
if (_waitForm != null)
{
if (!_waitForm.IsDisposed)
_waitForm.Dispose();
_waitForm = null;
_isVisible = false;
}
try
{
if (_isAborted)
return;
_waitForm = new frmWait();
if (_cancelable)
{
_waitForm.btnCancel.Enabled = true;
_waitForm.btnCancel.Click += new EventHandler(btnCancel_Click);
}
try
{
_isVisible = true;
_waitForm.Show();
_waitForm.Focus();
while (!_isAborted)
{
System.Threading.Thread.Sleep(15);
_waitForm.lblMessage.Text = _waitingState;
Application.DoEvents();
_waitForm.lblMessage.Text = _waitingState;
}
_isVisible = false;
}
finally
{
FreeWaitingForm();
}
}
finally
{
_isVisible = false;
}
}
static void btnCancel_Click(object sender, EventArgs e)
{
if (_waitForm.InvokeRequired)
{
_waitForm.BeginInvoke(new EventHandler(btnCancel_Click), new object[] { e });
}
else
{
if (OnCancel != null)
OnCancel.Invoke();
}
}
private static void FreeWaitingForm()
{
_waitingState = "";
_isVisible = false;
if (_waitForm == null)
{
return;
}
_waitForm.Hide();
if (!_waitForm.IsDisposed)
_waitForm.Dispose();
_waitForm = null;
}
#endregion
}
use like following code :
PleaseWait.ShowPleaseWait("Please wait", true, false);
// If second param is true then it will close the form automatically.
// If third param is true the it will expose a cancel button, so you can cancel your Asynchronous operations.
I didn't insert design code, you can understand by looking at code.
hope this help.
First let me thank you for your replies.
Toby your answer got me thinking about thread monitoring my sql connections but it was a bit tricky and confusing since the app is still in develop and will use a lot more connections.
S.Amani answer it wasn't quite what I want, but thanks to that I found a easier way. I created a form (could be anything else), placed a label saying: Saving To Data Base, took out the top bar, defined location and defined it's parent to be disabled when shown and enabled when closed. The following code is what I put inside my DataBaseInteractionClass
private Wait myCustomWaitDialog = new Wait(); // My Waiting form
private void SaveToDatabase(myObjectToSave obj) // Method called to save data do DB
{
// Create the connections and queries
(...)
// This is what I did
// Show Waiting Form
myCustomWaitDialog.Show();
// Instanciate the command that will carry the query and to DB
SqlCommand command = new SqlCommand(Queries.GetData(code), conn);
// This is important
//Create event that will fire when the command completes
command.StatementCompleted += new StatementCompletedEventHandler(command_StatementCompleted);
// Execute the transaction
SqlDataReader reader = command.ExecuteReader();
// Rest of the code (validations, close connections, try/catch, etc
(...)
}
void command_StatementCompleted(object sender, StatementCompletedEventArgs e)
{
// This is the method that closes my Waiting Dialog
myCustomWaitDialog.CloseDialog();
myCustomWaitDialog.Dispose();
}
It's not quite what I want yet, but is the best solution that I found so far. For now it will do :)
Anyway, thanks for the replies and I hope this helps someone else.
DUPLICATE: How can I programmatically determine if my workstation is locked?
How can I detect (during runtime) when a Windows user has locked their screen (Windows+L) and unlocked it again. I know I could globally track keyboard input, but is it possible to check such thing with environment variables?
A SessionSwitch event may be your best bet for this. Check the SessionSwitchReason passed through the SessionSwitchEventArgs to find out what kind of switch it is and react appropriately.
You can get this notification via a WM_WTSSESSION_CHANGE message. You must notify Windows that you want to receive these messages via WTSRegisterSessionNotification and unregister with WTSUnRegisterSessionNotification.
These posts should be helpful for a C# implementation.
http://pinvoke.net/default.aspx/wtsapi32.WTSRegisterSessionNotification
http://blogs.msdn.com/shawnfa/archive/2005/05/17/418891.aspx
http://bytes.com/groups/net-c/276963-trapping-when-workstation-locked
You can use ComponentDispatcher as an alternative way to get those events.
Here's an example class to wrap that.
public class Win32Session
{
private const int NOTIFY_FOR_THIS_SESSION = 0;
private const int WM_WTSSESSION_CHANGE = 0x2b1;
private const int WTS_SESSION_LOCK = 0x7;
private const int WTS_SESSION_UNLOCK = 0x8;
public event EventHandler MachineLocked;
public event EventHandler MachineUnlocked;
public Win32Session()
{
ComponentDispatcher.ThreadFilterMessage += ComponentDispatcher_ThreadFilterMessage;
}
void ComponentDispatcher_ThreadFilterMessage(ref MSG msg, ref bool handled)
{
if (msg.message == WM_WTSSESSION_CHANGE)
{
int value = msg.wParam.ToInt32();
if (value == WTS_SESSION_LOCK)
{
OnMachineLocked(EventArgs.Empty);
}
else if (value == WTS_SESSION_UNLOCK)
{
OnMachineUnlocked(EventArgs.Empty);
}
}
}
protected virtual void OnMachineLocked(EventArgs e)
{
EventHandler temp = MachineLocked;
if (temp != null)
{
temp(this, e);
}
}
protected virtual void OnMachineUnlocked(EventArgs e)
{
EventHandler temp = MachineUnlocked;
if (temp != null)
{
temp(this, e);
}
}
}
You absolutely don't need WM_WTSSESSION_CHANGE
Just use internal WTTS apis.