In my app, I want to inform user when particular action had performed, like record updated successfully or new record added, but there's not inbuilt control to that can display such information. Is there anything similar to Android Toast.makeText for UWP?
Yes, UWP has Toast Notifications :)
Here is sample code to display simple notification:
private void ShowToastNotification(string title, string stringContent)
{
ToastNotifier ToastNotifier = ToastNotificationManager.CreateToastNotifier();
Windows.Data.Xml.Dom.XmlDocument toastXml = ToastNotificationManager.GetTemplateContent(ToastTemplateType.ToastText02);
Windows.Data.Xml.Dom.XmlNodeList toastNodeList = toastXml.GetElementsByTagName("text");
toastNodeList.Item(0).AppendChild(toastXml.CreateTextNode(title));
toastNodeList.Item(1).AppendChild(toastXml.CreateTextNode(stringContent));
Windows.Data.Xml.Dom.IXmlNode toastNode = toastXml.SelectSingleNode("/toast");
Windows.Data.Xml.Dom.XmlElement audio = toastXml.CreateElement("audio");
audio.SetAttribute("src", "ms-winsoundevent:Notification.SMS");
ToastNotification toast = new ToastNotification(toastXml);
toast.ExpirationTime = DateTime.Now.AddSeconds(4);
ToastNotifier.Show(toast);
}
In this article you can find how to customize it:
https://learn.microsoft.com/en-us/windows/uwp/controls-and-patterns/tiles-and-notifications-adaptive-interactive-toasts
# CSharpToast
Create a toast in c#
This is a Microsoft Visual Studio project that demonstrates showing a toast message to the user.
A toast message is one that appears, then after a delay, disappears without user intervention.
This is needed when either the default language implementation is lacking, see java Android, or when there is no default language implementation.
The steps below illustrate the steps I took to create the toast,
but you can, if desired, just download the app here with all of these steps already completed.
Usage:
Call: Toast.show ("This is a test toast.");
DownloadURL:
git clone https://github.com/pstorli/CSharpToast
Steps To Create:
1) Create a new application in MS Visual Studio.
1.1) File -> New -> Application -> Windows Forms App (.NET Framework)
1.2) Name app as desired, here I used CSharpToast
2) Adjust initial form/screen
2.1) Set Form1.cs name to MainWindow.cs
2.4) Set the StartPosition to CenterScreen
2.5) Add a button1 to the form. Set text to "Make Toast"
2.6) Double click button. A new method should appear:
private void button1_Click(object sender, EventArgs e)
2.7) Add this code to it:
Toast.show ("Toast is done!");
3) Create the toast form.
3.1) In the solution explorer, Add -> New Item -> Windows Form
3.1.1) Set the name to Toast.cs
3.1.2) Set the toast form width and height to toast size, say 6 inches wide by 1/2" tall.
3.1.3) Set the FormBorderStyle to None
3.1.4) Set the background color to white.
3.1.5) Set the start position to CenterScreen
3.2) Add a label to your form
3.2.1) Set the name to Message
3.2.2) Set autosize to false.
3.2.3) Set textalign to MiddleCenter.
3.2.4) Set the background color to white.
3.2.5) Set Dock to fill.
3.3) Add some processing logic to file Toast.cs
3.3.1) Change Toast.cs from this:
using System.Windows.Forms;
namespace CSharpToast
{
public partial class Toast : Form {
public Toast()
{
InitializeComponent();
}
}
}
3.3.2) to this:
3.3.3) Added DEFAULT_MS_DELAY to control how long, by default toast shoould show up.
3.3.4) Added delegate void SafeOnTimedEvent to call Close from differenet thread.
3.3.5) Added constructor with just message and one with message and delay, to override DEFAULT_MS_DELAY
3.3.6) Created toast and added a timer to call, void OnTimedEvent() , when toast is done
which calls Toast.close(); on correct thread.
using System;
using System.Timers;
using System.Windows.Forms;
namespace CSharpToast
{
public partial class Toast : Form {
public static int DEFAULT_MS_DELAY = 2500;
private delegate void SafeOnTimedEvent(Object source, ElapsedEventArgs e);
public Toast (String message)
{
InitializeComponent();
Message.Text = message;
}
public static Toast show (String message)
{
return show(message, DEFAULT_MS_DELAY);
}
public static Toast show (String message, int ms)
{
Toast toast = new Toast(message);
System.Timers.Timer aTimer = new System.Timers.Timer(ms);
aTimer.Elapsed += toast.OnTimedEvent;
aTimer.AutoReset = false;
aTimer.Enabled = true;
toast.ShowDialog();
return toast;
}
private void OnTimedEvent (Object source, ElapsedEventArgs e)
{
if (this.InvokeRequired)
{
var d = new SafeOnTimedEvent(OnTimedEvent);
Invoke(d, new object[] { source, e });
}
else
{
Close();
}
}
}
}
3.4) Run app
3.4.1) The main screen with the "Make Toast" button should appear.
3.4.2) When you press the "Make Toast" button,
3.4.3) a white toast popup should appear that says "Toast is Done!"
3.4.4) which should disappear in 2500 ms.
"I've looked at toast from both sides now, the win and lose and still somehow
it's toast's illusions I recall, I really don't like toast in c# at all."
~Except my CSharpToast version.
Here how to realize simple makeText like android:
private Windows.UI.Xaml.Controls.Frame frame;
private Windows.UI.Xaml.Controls.Page page;
private Ribo.Smart.App.UserControls.Components.Common.Toast toast;
private DispatcherTimer timer = new DispatcherTimer();
void timer_Tick(object sender, object e)
{
if (toast != null)
((Panel)page.FindName("layoutRoot")).Children.Remove(toast);
toast = null;
timer.Stop();
timer.Tick -= timer_Tick;
}
private void Frame_Navigated(object sender, Windows.UI.Xaml.Navigation.NavigationEventArgs e)
{
if (toast != null)
{
object layoutRoot = page.FindName("layoutRoot");
if (layoutRoot != null)
{
((Panel)layoutRoot).Children.Remove(toast);
page = (Windows.UI.Xaml.Controls.Page)e.Content;
layoutRoot = page.FindName("layoutRoot");
((Panel)layoutRoot).VerticalAlignment = VerticalAlignment.Stretch;
((Panel)layoutRoot).Children.Add(toast);
if (layoutRoot is Grid)
{
toast.SetValue(Grid.RowSpanProperty, 100);
}
}
}
}
public void ShowMessage(string message)
{
frame = (Windows.UI.Xaml.Controls.Frame)Windows.UI.Xaml.Window.Current.Content;
page = (Windows.UI.Xaml.Controls.Page)frame.Content;
frame.Navigated -= Frame_Navigated;
frame.Navigated += Frame_Navigated;
toast = new Ribo.Smart.App.UserControls.Components.Common.Toast();
toast.Message = message;
toast.VerticalAlignment = Windows.UI.Xaml.VerticalAlignment.Bottom;
toast.HorizontalAlignment = Windows.UI.Xaml.HorizontalAlignment.Center;
int seconds = message.Length / 30;
if (seconds < 2)
seconds = 2;
timer.Interval = new TimeSpan(0, 0, seconds);
timer.Start();
timer.Tick -= timer_Tick;
timer.Tick += timer_Tick;
object layoutRoot = page.FindName("layoutRoot");
if (layoutRoot != null)
{
if (layoutRoot is Grid)
{
toast.SetValue(Grid.RowSpanProperty, 100);
}
((Panel)layoutRoot).Children.Add(toast);
}
}
Related
i m trying to suppot an app, that uses cefsharp(v79.1.360).
There are list of things I need to implement:
1) ChromiumWebBrowser in WPF (using CefSharp.Wpf minimum example)
2) This browser can go offscreen(with collapsing window or closing it)
3) Work with JavaScriptObjectRepository, and launch some code, that will be do work with web pages(click buttons, change text of elements). Pages may use frameworks, websockets, Http requests and the other stuff
web pages usually do.
After pages work is done, i send results to C# by calling Methods of object, i bounded in jsObjectRepository/
Expectations:
Offscreen prefomance(time delay) should be as well as With opened window/
Reality:
Offscreen perfomance sometimes is really bad, it take time to do work up to 10 seconds(when wpf is only 1-5).
My code:
Initialization
CefSharpSettings.LegacyJavascriptBindingEnabled = true;
CefSharpSettings.WcfEnabled = true;
CefSettings cefSettings = new CefSettings
{
LocalesDirPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "locales"),
Locale = appsettings.CurrentChromeLanguage.ToLocal(),
AcceptLanguageList = appsettings.CurrentChromeLanguage.ToAcceptList(),
};
if (!cefSettings.CefCommandLineArgs.ContainsKey("disable-gpu"))
{
cefSettings.CefCommandLineArgs.Add("disable-gpu", "1");
}
if (cefSettings.CefCommandLineArgs.ContainsKey("enable-system-flash"))
{
cefSettings.CefCommandLineArgs.Remove("enable-system-flash");
}
if (cefSettings.CefCommandLineArgs.ContainsKey("enable-media-stream"))
{
cefSettings.CefCommandLineArgs.Remove("enable-media-stream");
}
cefSettings.CefCommandLineArgs.Add("enable-begin-frame-scheduling", "1");
cefSettings.CefCommandLineArgs.Add("disable-gpu-vsync", "1");
cefSettings.CefCommandLineArgs.Add("mute-audio", "true");
cefSettings.CefCommandLineArgs.Add("enable-media-stream", "0");
cefSettings.CefCommandLineArgs.Add("disable-3d-apis", "1");
cefSettings.CefCommandLineArgs.Add("renderer-process-limit", "10");
cefSettings.CefCommandLineArgs.Add("js-flags", "--lite_mode");
if (!appsettings.IsLoadImage)
{
cefSettings.CefCommandLineArgs.Add("disable-image-loading", "1");
}
cefSettings.LogFile = Path.Combine(ClientConfig.ChromeDataPath, "Log.txt");
cefSettings.LogSeverity = LogSeverity.Error;
cefSettings.IgnoreCertificateErrors = true;
cefSettings.SetOffScreenRenderingBestPerformanceArgs();
Browser creating and usage:
ChromiumWebBrowser browser = new ChromiumWebBrowser();
//xaml window with <ContentControl> with browser
//need hide means when window is closing, we cancel it, and using Hide()
NewBrowserView view = new NewBrowserView(new ChromeTabViewModel(browser));
view.Closing += BrowserView_Closing;
Browser.FrameLoadStart += _browser_FrameLoadStart;
var options = new BindingOptions { CamelCaseJavascriptNames = false };
browser.JavascriptObjectRepository.Register("resultController", this, false, options);
//we can just hide window
void BrowserView_Closing(object sender, CancelEventArgs e)
{
if (_needHide)
{
e.Cancel = true;
Hide();
}
}
//on page load
void _browser_FrameLoadStart(object sender, FrameLoadStartEventArgs e) {
string code = "";
code += "(async function(){ " +
"await CefSharp.BindObjectAsync('resultController'); " +
code += TestJsCode;
code += " })();";//AddWorker
e.Frame.ExecuteJavaScriptAsync(code, $"about:blank/myCode");
Consol.WriteLine(DateTime.Now);
}
public void OnGoodResult()
{
Consol.WriteLine(DateTime.Now);
}
public void OnBadResult()
{
Consol.WriteLine(DateTime.Now);
}
//then i just go by differnet pages and await results
As i mentioned before, when i hide wnd, its taking too long time to print result
I really depended on Layouts and other visuals, so i figured this out. I should just set this code, when window is collapsing:
GetBrowser().GetHost().WasHidden(false);
I have an application that has a lot of modal popup windows. Some are custom windows displayed with .ShowDialog(), other are generic message boxes using a 3rd party tool (DXMessageBox.Show(...)), and others are system dialogs such as an OpenFileDialog. If the user leaves the application running long enough, it should time out and show a "Session Locked" screen and prevent users from seeing or interacting with the application until they login again. This is problematic because of the modal dialogs.
My current solution is to host the Relogin screen in the current modal window if there is one, and hide all other windows. The problem is that if I set Visibility = Hidden on any window I have called using .ShowDialog(), it treats that dialog as having received a result and processes the code that handles the dialog result. They are also no longer modal after they are re-shown.
So my current attempt is to try to hide the window using something other than Visibility, and prevent it from being activated. The closest I've come is by setting Minimized=true and ShowInTaskbar=false, but this results in an undesirable minimized titlebar above my taskbar.
Is there a way to prevent this from happening, or alternatively is there another way to hide a window and prevent it's activation without causing .ShowDialog to return?
Here's some code to re-create a sample application to test this with. Just add a button to launch the ShowLock_Click event handler.
private readonly Dictionary<System.Windows.Window, WindowStyle> _hiddenWindows = new Dictionary<System.Windows.Window, WindowStyle>();
// Create a button to launch this for testing
private void ShowLock_Click(object sender, RoutedEventArgs e)
{
// Will show another window with .ShowDialog, then 2s timeout will trigger lock window
using (new System.Threading.Timer(OnLockTimerElapsed, null, 2000, System.Threading.Timeout.Infinite))
{
ShowTestDialog();
}
}
private void OnLockTimerElapsed(object state)
{
_hiddenWindows.Clear();
Application.Current.Dispatcher.BeginInvoke(
DispatcherPriority.Background,
new Action(() =>
{
var mainWindow = Application.Current.MainWindow;
Window host = null;
foreach (Window win in Application.Current.Windows)
{
if (IsModalDialog(win))
host = win;
_hiddenWindows.Add(win, win.WindowStyle);
// Been testing various ways to hide window without using Visibility
win.ShowInTaskbar = false;
win.WindowStyle = WindowStyle.None;
win.WindowState = WindowState.Minimized;
win.Opacity -= 1;
win.IsHitTestVisible = false;
}
ShowLockScreen(host);
}));
}
private void ShowLockScreen(Window owner = null)
{
var lockScreen = new Window
{
Title = "Relogin Window",
Content = "This is a test Relogin Window. Close Window via X to continue",
WindowStartupLocation = WindowStartupLocation.CenterScreen
};
if (owner != null)
lockScreen.Owner = owner;
lockScreen.ShowDialog();
// Once that window closes, restore other windows
RestoreSession();
}
private void RestoreSession()
{
Application.Current.Dispatcher.BeginInvoke(
DispatcherPriority.Background,
new Action(() =>
{
foreach (var win in _hiddenWindows.Keys)
{
win.ShowInTaskbar = true;
win.WindowStyle = _hiddenWindows[win];
win.WindowState = WindowState.Normal;
win.IsHitTestVisible = true;
win.Opacity += 1;
}
}));
}
private void ShowTestDialog()
{
var test = new Window
{
Title = "Test Modal Dialog",
Content = "This is a test Modal Dialog. Close window via X to continue.",
Height = 100,
Width = 350,
WindowStartupLocation = WindowStartupLocation.CenterOwner,
Owner = this
};
var result = test.ShowDialog();
// This code gets run if I set Visibility=Hidden. I do not want that.
MessageBox.Show($"Test Dialog result returned. Result : {result}. This should ONLY happen when you click X on the dialog window");
}
private static bool IsModalDialog(Window window)
{
return (bool)typeof(System.Windows.Window)
.GetField("_showingAsDialog", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic)
.GetValue(window);
}
I am using slimdx to interpret xbox controller button presses. I poll every 200ms to read the xbox button states and all works for me. I use
JoystickState state = Joystick.GetCurrentState();
// get buttons states
bool[] buttonsPressed = state.GetButtons();
Is there anyway to generate events on the button press instead of polling? To explain imagine if my poll time was 5 seconds. And the user presses a button in the 2nd second and releases it. In the next poll time my application will never know that the button was pressed
No - in DirectX you must poll. To do this efficiently you want to create a polling thread, and have a class which raises cross thread events to your consuming thread.
I know this is 4 years old but the answer is incorrect. The most efficient way may be to poll, but you can raise an event when you poll.
This is a work in progress but it should get someone started. Save this as a new class, it derives from a Timer, so once you add this to your project, build it, and drag it onto the Form you want to use it, you can then subscribe to the buttonPressed event.
public class GamePadController : Timer
{
public delegate void ButtonPressedDelegate(object sender, int ButtonNumber);
public event ButtonPressedDelegate ButtonPressed;
List<DeviceInstance> directInputList = new List<DeviceInstance>();
DirectInput directInput = new DirectInput();
List<SlimDX.DirectInput.Joystick> gamepads = new List<Joystick>();
SlimDX.DirectInput.JoystickState state;
public GamePadController()
{
this.Interval = 10;
this.Enabled = true;
this.Tick += GamePadController_Tick;
RefreshGamePads();
}
private void RefreshGamePads()
{
directInputList.Clear();
directInputList.AddRange(directInput.GetDevices(DeviceClass.GameController, DeviceEnumerationFlags.AttachedOnly));
gamepads.Clear();
foreach (var device in directInputList)
{
gamepads.Add(new SlimDX.DirectInput.Joystick(directInput, directInputList[0].InstanceGuid));
}
}
private void GamePadController_Tick(object sender, EventArgs e)
{
foreach (var gamepad in gamepads)
{
if (gamepad.Acquire().IsFailure)
continue;
if (gamepad.Poll().IsFailure)
continue;
if (SlimDX.Result.Last.IsFailure)
continue;
state = gamepad.GetCurrentState();
bool[] buttons = state.GetButtons();
for (int i = 0; i < buttons.Length; i++)
{
if (buttons[i])
{
if (ButtonPressed != null)
{
ButtonPressed(gamepad, i);
}
}
}
gamepad.Unacquire();
}
}
}
}
Code for creating the CustomMessageBox:
CustomMessageBox is a property, and not a reference to the C# Class in the Toolkit.
CustomMessageBox.Dismissed += (dismissSender, dismissedEvent) =>
{
switch (dismissedEvent.Result)
{
case CustomMessageBoxResult.LeftButton:
PlaceCall(clickedFavorite.Name, clickedFavorite.PhoneNo);
break;
case CustomMessageBoxResult.RightButton:
HERE ---> SendText(clickedFavorite.PhoneNo);
break;
}
};
Code for SendText() method:
private void SendText(String phoneNo)
{
var smsTask = new SmsComposeTask
{
To = phoneNo
};
smsTask.Show();
}
Thing is when the SmsComposeTask has started, the Phone navigates to the SMS application, which is correct.
If the user then decides to go back, with the Hardware Back Button, the SMS application closes and the phone shows my app again - but immediately closes, caused by a NullPointerException:
at Microsoft.Phone.Controls.CustomMessageBox.ClosePopup(Boolean restoreOriginalValues)
at Microsoft.Phone.Controls.CustomMessageBox.<>c__DisplayClass4.<Dismiss>b__1(Object s, EventArgs e)
at Microsoft.Phone.Controls.Transition.OnCompleted(Object sender, EventArgs e)
at MS.Internal.CoreInvokeHandler.InvokeEventHandler(Int32 typeIndex, Delegate handlerDelegate, Object sender, Object args)
at MS.Internal.JoltHelper.FireEvent(IntPtr unmanagedObj, IntPtr unmanagedObjArgs, Int32 argsTypeIndex, Int32 actualArgsTypeIndex, String eventName)
I have also tried to override the OnBackKeyPress event, like this:
protected override void OnBackKeyPress(System.ComponentModel.CancelEventArgs e)
{
if (CustomMessageBox != null && CustomMessageBox.IsEnabled)
{
e.Cancel = true;
}
else
{
base.OnBackKeyPress(e);
}
}
Does anyone know what to do?
I have found a solution to my own problem. Instead of using the faulty CustomMessageBox, I found Coding4Fun Windows Phone Toolkit which provides a by far, more stable message box called MessagePrompt - here's how to use it.
Create buttons
var smsButton = new Button { Content = "SMS" };
smsButton.Click += (o, args) =>
{
// do something
};
var buttonList = new List<Button>
{
smsButton
};
Create the actual message prompt
var msgPrompt = new MessagePrompt
{
Title = "Message Prompt Title",
Body = new TextBlock { Text = "Text for the Body", FontSize = 25, TextWrapping = TextWrapping.Wrap },
ActionPopUpButtons = buttonList
};
Show it
msgPrompt.Show()
No bullocks
The good thing, which I have experienced with this MessagePrompt is that you are not bound to two static Left and Right buttons like with CustomMessageBox.
And if you want, you can set the Body property to a whole new XAML page, which makes this control flexible.
Reference: Coding4Fun WP7 Message Prompt in depth
Doesn't this problem has something to do with Windows Phone Application lifecycle. As can be found here, figure 6. When activiting another program when your program is active you should save all application data so when a reactivating event ,such as navigating with your back button back to your application, starts your program again you can load the user's data again.
I'm not sure what's happening, but you can just delay the SMS task to avoid the issue:
CustomMessageBox.Dismissed += (dismissSender, dismissedEvent) =>
{
switch (dismissedEvent.Result)
{
case CustomMessageBoxResult.LeftButton:
PlaceCall(clickedFavorite.Name, clickedFavorite.PhoneNo);
break;
case CustomMessageBoxResult.RightButton:
Dispatcher.BeginInvoke(new Action(() => SendText(clickedFavorite.PhoneNo)));
break;
}
};
My 0.02$: this is a bug in the CustomMessageBox. They're keeping lots of singletons alive there and a good timing bug doesn't do that a world of good. Agreed with KooKiz that you can't work around with that without either fixing CustomMessageBox or waiting until the CustomMessageBox finishes its thing. From my ad-hoc testing it requires anywhere between 2-6 Dispatcher.BeginInvoke() until those actions finish. Instead, maybe consider using DispatcherTimer and wait 256MS which should be enough time.
private void MainPage_Loaded(object sender, RoutedEventArgs e)
{
var msgBox = new CustomMessageBox()
{
Caption = "foo",
Message = "bar",
LeftButtonContent = "baz",
RightButtonContent = "goo",
IsFullScreen = false,
};
msgBox.Dismissed += (s, args) =>
{
DispatcherTimerHelper.InvokeReallySoon(() =>
{
new SmsComposeTask()
{
Body = "foo",
To = "bar"
}.Show();
});
};
msgBox.Show();
}
public static class DispatcherTimerHelper
{
public static void InvokeReallySoon(Action action)
{
var t = new DispatcherTimer() {Interval = TimeSpan.FromMilliseconds(256)};
t.Tick += (s, args) => action();
t.Start();
}
}
The problem just happen in wp8.
I use the same code in wp7, nothing wrong happens.
Use Code4fun messagebox is a good choice,but is Button Click handler you need to call
MessagePrompt.Hide();
to close the MessagePrompt.
used a boolean on the dismissed event to define which button had been pressed. I then implemented the code I would of implemented in the dismissed event in the Unloaded event instead. This seemed to solve the issue.
i.e
messageBox.Dismissed += (s1, e1) =>
{
switch (e1.Result)
{
case CustomMessageBoxResult.LeftButton:
{
delete = true ;
}
break;
case CustomMessageBoxResult.RightButton:
break;
case CustomMessageBoxResult.None:
break;
default:
break;
}
};
messageBox.Unloaded += (s1, e1) =>
{
if (delete)
DeleteWorkout();
};
This is a known bug.
It was fixed in the latest version.
Remove the reference and install the toolkit again.
I have a Windows App Project to which users can login with their userid and passwords. I want to make it so that when a user logs in, I will get the Login Time, and if the user doesn't use the application for 30 min, the application will send the user to the Login screen again. How can I achieve this?
Edit: Adam is absolutely right, I've misunderstood the question, so I deleted my original answer.
To monitor user activity, you could create a custom Form-based class from which your application forms will inherit. There you can subscribe to the MouseMove and KeyDown events (setting the KeyPreview property to true), either of which will be raised whenever the user is active. You can then create a System.Threading.Timer, with the due time set to 30 minutes, and postpone it using the Change() method whenever user activity is detected.
This is an example implementation below: the ObservedForm is written to be rather general, so that you can more easily see the pattern.
public class ObservedForm : Form
{
public event EventHandler UserActivity;
public ObservedForm()
{
KeyPreview = true;
FormClosed += ObservedForm_FormClosed;
MouseMove += ObservedForm_MouseMove;
KeyDown += ObservedForm_KeyDown;
}
protected virtual void OnUserActivity(EventArgs e)
{
var ua = UserActivity;
if(ua != null)
{
ua(this, e);
}
}
private void ObservedForm_MouseMove(object sender, MouseEventArgs e)
{
OnUserActivity();
}
private void ObservedForm_KeyDown(object sender, KeyEventArgs e)
{
OnUserActivity();
}
private void ObservedForm_FormClosed(object sender, FormClosedEventArgs e)
{
FormClosed -= ObservedForm_FormClosed;
MouseMove -= ObservedForm_MouseMove;
KeyDown -= ObservedForm_KeyDown;
}
}
Now you can subscribe to the UserActivity event, and do the logics you desire, for example:
private System.Threading.Timer timer = new Timer(_TimerTick, null, 1000 * 30 * 60, Timeout.Infinite);
private void _OnUserActivity(object sender, EventArgs e)
{
if(timer != null)
{
// postpone auto-logout by 30 minutes
timer.Change(1000 * 30 * 60, Timeout.Infinite);
}
}
private void _TimerTick(object state)
{
// the user has been inactive for 30 minutes; log him out
}
Hope this helps.
Edit #2: rephrased some parts of the explanation for clarity, and changed the use of the FormClosing event to FormClosed.
This is the simple way to solve this problem. It's working well.
using System;
using System.Windows.Forms;
namespace WindowsApplication1 {
public partial class Form1 : Form, IMessageFilter {
private Timer mTimer;
private int mDialogCount;
public Form1() {
InitializeComponent();
mTimer = new Timer();
mTimer.Interval = 2000;
mTimer.Tick += LogoutUser;
mTimer.Enabled = true;
Application.AddMessageFilter(this);
}
public bool PreFilterMessage(ref Message m) {
// Monitor message for keyboard and mouse messages
bool active = m.Msg == 0x100 || m.Msg == 0x101; // WM_KEYDOWN/UP
active = active || m.Msg == 0xA0 || m.Msg == 0x200; // WM_(NC)MOUSEMOVE
active = active || m.Msg == 0x10; // WM_CLOSE, in case dialog closes
if (active) {
if (!mTimer.Enabled) label1.Text = "Wakeup";
mTimer.Enabled = false;
mTimer.Start();
}
return false;
}
private void LogoutUser(object sender, EventArgs e) {
// No activity, logout user
if (mDialogCount > 0) return;
mTimer.Enabled = false;
label1.Text = "Time'z up";
}
private void button1_Click(object sender, EventArgs e) {
mDialogCount += 1;
Form frm = new Form2();
frm.ShowDialog();
mDialogCount -= 1;
mTimer.Start();
}
}
}
You have to make a base class for all your Forms, that will intercept any user activity and store the last activity time. Each time user clicks sth you would have to check the last activity date and decide whether it was too long ago, or not.
At the moment I have no idea how to intercept, but I'm pretty sure it's possible (maybe using windows messages?)
1.st: User logs in, store the timestamp somewhere (for example this unix timestamp '1294230230' says it's aproximately 5th January 2011, 12:24)
int sess_creation_time = now(); *lets say 'now()' function returns current unix timestamp
2.nd: when user tries to perform any action, catch the timestamp of this attempt.
int temp_time = now();
Now, simply compare these values with your desired auto logout limit.
// compare here
// a, temp_time - sess_creation_time => the difference, time of inactivity
// 60*30 -> 60 seconds * 30 -> 30 minutes
if( (temp_time - sess_creation_time) > (60*30) )
{
// time of inactivity is higher than allowed, logout here
logout();
}
else
{
// session is still valid, do not forget to update its creation time
sess_creation_time = now();
}
Do not forget, this is not written in C/C++ or C#, but the logic remains the same ;-)
Hope, this helps you a bit