Code:
/ Net / Net / 3.5.50727.3053 / DEVDIV / depot / DevDiv / releases / whidbey / netfxsp / ndp / fx / src / WinForms / Managed / System / WinForms / Timer.cs / 1 / Timer.cs
//------------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//-----------------------------------------------------------------------------
/*
*/
namespace System.Windows.Forms {
using System.Threading;
using System.Runtime.InteropServices;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Diagnostics;
using System.Windows.Forms.Design;
using System;
using System.Globalization;
///
///
/// Implements a Windows-based timer that raises an event at user-defined intervals. This timer is optimized for
/// use in Win Forms
/// applications and must be used in a window.
///
[
DefaultProperty("Interval"),
DefaultEvent("Tick"),
ToolboxItemFilter("System.Windows.Forms"),
SRDescription(SR.DescriptionTimer)
]
public class Timer : Component {
///
///
///
private int interval;
///
///
///
private bool enabled;
///
///
///
private EventHandler onTimer;
///
///
///
private GCHandle timerRoot;
// our holder for the HWND that handles our Timer messages.
//
private TimerNativeWindow timerWindow;
///
///
///
private object userData;
private object syncObj = new object();
///
///
/// Initializes a new instance of the
/// class.
///
public Timer()
: base() {
interval = 100;
}
///
///
/// Initializes a new instance of the class with the specified container.
///
public Timer(IContainer container) : this() {
container.Add(this);
}
///
[
SRCategory(SR.CatData),
Localizable(false),
Bindable(true),
SRDescription(SR.ControlTagDescr),
DefaultValue(null),
TypeConverter(typeof(StringConverter)),
]
public object Tag {
get {
return userData;
}
set {
userData = value;
}
}
///
///
/// Occurs when the specified timer
/// interval has elapsed and the timer is enabled.
///
[SRCategory(SR.CatBehavior), SRDescription(SR.TimerTimerDescr)]
public event EventHandler Tick {
add {
onTimer += value;
}
remove {
onTimer -= value;
}
}
///
///
///
/// Disposes of the resources (other than memory) used by the timer.
///
///
protected override void Dispose(bool disposing) {
if (disposing) {
if (timerWindow != null) {
timerWindow.StopTimer();
}
Enabled = false;
}
timerWindow = null;
base.Dispose(disposing);
}
///
///
/// Indicates whether the timer is
/// running.
///
[
SRCategory(SR.CatBehavior),
DefaultValue(false),
SRDescription(SR.TimerEnabledDescr)
]
public virtual bool Enabled {
get {
if (timerWindow == null) {
return enabled;
}
return timerWindow.IsTimerRunning;
}
set {
lock(syncObj) {
if (enabled != value) {
enabled = value;
// At runtime, enable or disable the corresponding Windows timer
//
if (!DesignMode) {
if (value) {
// create the timer window if needed.
//
if (timerWindow == null) {
timerWindow = new TimerNativeWindow(this);
}
timerRoot = GCHandle.Alloc(this);
timerWindow.StartTimer(interval);
}
else{
if (timerWindow != null){
timerWindow.StopTimer();
}
if (timerRoot.IsAllocated) {
timerRoot.Free();
}
}
}
}
}
}
}
///
///
///
/// Indicates the time, in milliseconds, between timer ticks.
///
[
SRCategory(SR.CatBehavior),
DefaultValue(100),
SRDescription(SR.TimerIntervalDescr)
]
public int Interval {
get {
return interval;
}
set {
lock(syncObj) {
if (value < 1)
throw new ArgumentOutOfRangeException("Interval", SR.GetString(SR.TimerInvalidInterval, value, (0).ToString(CultureInfo.CurrentCulture)));
if (interval != value) {
interval = value;
if (Enabled) {
Debug.Assert(DesignMode || timerWindow != null, "Why don't we have a timer HWND?");
// just change the timer value, don't tear down the timer
// itself.
//
if (!DesignMode && timerWindow != null) {
timerWindow.RestartTimer(value);
}
}
}
}
}
}
///
///
/// Raises the
/// event.
///
protected virtual void OnTick(EventArgs e) {
if (onTimer != null) onTimer(this, e);
}
///
///
/// Starts the
/// timer.
///
public void Start() {
Enabled = true;
}
///
///
/// Stops the
/// timer.
///
public void Stop() {
Enabled = false;
}
///
///
/// returns us as a string.
///
///
public override string ToString() {
string s = base.ToString();
return s + ", Interval: " + Interval.ToString(CultureInfo.CurrentCulture);
}
private class TimerNativeWindow : NativeWindow {
// the timer that owns us
//
private Timer _owner;
// our current id -- this is usally the same as TimerID but we also
// use it as a flag of when our timer is running.
//
private int _timerID;
// arbitrary timer ID.
//
private static int TimerID = 1;
// setting this when we are stopping the timer so someone can't restart it in the process.
//
private bool _stoppingTimer;
internal TimerNativeWindow(Timer owner) {
this._owner = owner;
}
~TimerNativeWindow() {
// note this call will work form the finalizer thread.
//
StopTimer();
}
public bool IsTimerRunning {
get {
return _timerID != 0 && Handle != IntPtr.Zero;
}
}
// Ensures that our HWND has been created.
//
private bool EnsureHandle() {
if (Handle == IntPtr.Zero) {
// we create a totally vanilla invisible window just for WM_TIMER messages.
//
CreateParams cp = new CreateParams();
cp.Style = 0;
cp.ExStyle = 0;
cp.ClassStyle = 0;
cp.Caption = GetType().Name;
// Message only windows are cheaper and have fewer issues than
// full blown invisible windows. But, they are only supported
// on NT.
if (Environment.OSVersion.Platform == PlatformID.Win32NT) {
cp.Parent = (IntPtr)NativeMethods.HWND_MESSAGE;
}
CreateHandle(cp);
}
Debug.Assert(Handle != IntPtr.Zero, "Timer HWND creation failed!");
return Handle != IntPtr.Zero;
}
// Returns true if we need to marshal across threads to access this timer's HWND.
//
private bool GetInvokeRequired(IntPtr hWnd) {
if (hWnd != IntPtr.Zero) {
int pid;
int hwndThread = SafeNativeMethods.GetWindowThreadProcessId(new HandleRef(this, hWnd), out pid);
int currentThread = SafeNativeMethods.GetCurrentThreadId();
return(hwndThread != currentThread);
}
return false;
}
// change the interval of the timer without destroying the HWND.
//
public void RestartTimer(int newInterval) {
StopTimer(false, IntPtr.Zero);
StartTimer(newInterval);
}
// Start the timer with the specified interval.
//
public void StartTimer(int interval) {
if (_timerID == 0 && !_stoppingTimer) {
if (EnsureHandle()) {
_timerID = (int) SafeNativeMethods.SetTimer(new HandleRef(this, Handle), TimerID++, interval, IntPtr.Zero);
}
}
}
// stop the timer.
//
public void StopTimer() {
StopTimer(true, IntPtr.Zero);
}
// stop the timer and optionally destroy the HWND.
//
public void StopTimer(bool destroyHwnd, IntPtr hWnd) {
if (hWnd == IntPtr.Zero) {
hWnd = Handle;
}
// Fire a message across threads to destroy the timer and HWND on the thread that created it.
//
if (GetInvokeRequired(hWnd)) {
UnsafeNativeMethods.PostMessage(new HandleRef(this, hWnd), NativeMethods.WM_CLOSE, 0, 0);
return;
}
// Locking 'this' here is ok since this is an internal class. See VSW#464499.
lock(this) {
if (_stoppingTimer || hWnd == IntPtr.Zero || !UnsafeNativeMethods.IsWindow(new HandleRef(this, hWnd))) {
return;
}
if (_timerID != 0) {
try {
_stoppingTimer = true;
SafeNativeMethods.KillTimer(new HandleRef(this, hWnd), _timerID);
}
finally {
_timerID = 0;
_stoppingTimer = false;
}
}
if (destroyHwnd) {
base.DestroyHandle();
}
}
}
// Destroy the handle, stopping the timer first.
//
public override void DestroyHandle() {
// don't recurse!
//
StopTimer(false, IntPtr.Zero);
Debug.Assert(_timerID == 0, "Destroying handle with timerID still set.");
base.DestroyHandle();
}
protected override void OnThreadException(Exception e) {
Application.OnThreadException(e);
}
public override void ReleaseHandle() {
// don't recurse!
//
StopTimer(false, IntPtr.Zero);
Debug.Assert(_timerID == 0, "Destroying handle with timerID still set.");
base.ReleaseHandle();
}
protected override void WndProc(ref Message m) {
Debug.Assert(m.HWnd == Handle && Handle != IntPtr.Zero, "Timer getting messages for other windows?");
// for timer messages, make sure they're ours (it'll be wierd if they aren't)
// and call the timer event.
//
if (m.Msg == NativeMethods.WM_TIMER) {
//Debug.Assert((int)m.WParam == _timerID, "Why are we getting a timer message that isn't ours?");
if ((int)m.WParam == _timerID) {
_owner.OnTick(EventArgs.Empty);
return;
}
}
else if (m.Msg == NativeMethods.WM_CLOSE) {
// this is a posted method from another thread that tells us we need
// to kill the timer. The handle may already be gone, so we specify it here.
//
StopTimer(true, m.HWnd);
return;
}
base.WndProc(ref m);
}
}
}
}
// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//------------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//-----------------------------------------------------------------------------
/*
*/
namespace System.Windows.Forms {
using System.Threading;
using System.Runtime.InteropServices;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Diagnostics;
using System.Windows.Forms.Design;
using System;
using System.Globalization;
///
///
/// Implements a Windows-based timer that raises an event at user-defined intervals. This timer is optimized for
/// use in Win Forms
/// applications and must be used in a window.
///
[
DefaultProperty("Interval"),
DefaultEvent("Tick"),
ToolboxItemFilter("System.Windows.Forms"),
SRDescription(SR.DescriptionTimer)
]
public class Timer : Component {
///
///
///
private int interval;
///
///
///
private bool enabled;
///
///
///
private EventHandler onTimer;
///
///
///
private GCHandle timerRoot;
// our holder for the HWND that handles our Timer messages.
//
private TimerNativeWindow timerWindow;
///
///
///
private object userData;
private object syncObj = new object();
///
///
/// Initializes a new instance of the
/// class.
///
public Timer()
: base() {
interval = 100;
}
///
///
/// Initializes a new instance of the class with the specified container.
///
public Timer(IContainer container) : this() {
container.Add(this);
}
///
[
SRCategory(SR.CatData),
Localizable(false),
Bindable(true),
SRDescription(SR.ControlTagDescr),
DefaultValue(null),
TypeConverter(typeof(StringConverter)),
]
public object Tag {
get {
return userData;
}
set {
userData = value;
}
}
///
///
/// Occurs when the specified timer
/// interval has elapsed and the timer is enabled.
///
[SRCategory(SR.CatBehavior), SRDescription(SR.TimerTimerDescr)]
public event EventHandler Tick {
add {
onTimer += value;
}
remove {
onTimer -= value;
}
}
///
///
///
/// Disposes of the resources (other than memory) used by the timer.
///
///
protected override void Dispose(bool disposing) {
if (disposing) {
if (timerWindow != null) {
timerWindow.StopTimer();
}
Enabled = false;
}
timerWindow = null;
base.Dispose(disposing);
}
///
///
/// Indicates whether the timer is
/// running.
///
[
SRCategory(SR.CatBehavior),
DefaultValue(false),
SRDescription(SR.TimerEnabledDescr)
]
public virtual bool Enabled {
get {
if (timerWindow == null) {
return enabled;
}
return timerWindow.IsTimerRunning;
}
set {
lock(syncObj) {
if (enabled != value) {
enabled = value;
// At runtime, enable or disable the corresponding Windows timer
//
if (!DesignMode) {
if (value) {
// create the timer window if needed.
//
if (timerWindow == null) {
timerWindow = new TimerNativeWindow(this);
}
timerRoot = GCHandle.Alloc(this);
timerWindow.StartTimer(interval);
}
else{
if (timerWindow != null){
timerWindow.StopTimer();
}
if (timerRoot.IsAllocated) {
timerRoot.Free();
}
}
}
}
}
}
}
///
///
///
/// Indicates the time, in milliseconds, between timer ticks.
///
[
SRCategory(SR.CatBehavior),
DefaultValue(100),
SRDescription(SR.TimerIntervalDescr)
]
public int Interval {
get {
return interval;
}
set {
lock(syncObj) {
if (value < 1)
throw new ArgumentOutOfRangeException("Interval", SR.GetString(SR.TimerInvalidInterval, value, (0).ToString(CultureInfo.CurrentCulture)));
if (interval != value) {
interval = value;
if (Enabled) {
Debug.Assert(DesignMode || timerWindow != null, "Why don't we have a timer HWND?");
// just change the timer value, don't tear down the timer
// itself.
//
if (!DesignMode && timerWindow != null) {
timerWindow.RestartTimer(value);
}
}
}
}
}
}
///
///
/// Raises the
/// event.
///
protected virtual void OnTick(EventArgs e) {
if (onTimer != null) onTimer(this, e);
}
///
///
/// Starts the
/// timer.
///
public void Start() {
Enabled = true;
}
///
///
/// Stops the
/// timer.
///
public void Stop() {
Enabled = false;
}
///
///
/// returns us as a string.
///
///
public override string ToString() {
string s = base.ToString();
return s + ", Interval: " + Interval.ToString(CultureInfo.CurrentCulture);
}
private class TimerNativeWindow : NativeWindow {
// the timer that owns us
//
private Timer _owner;
// our current id -- this is usally the same as TimerID but we also
// use it as a flag of when our timer is running.
//
private int _timerID;
// arbitrary timer ID.
//
private static int TimerID = 1;
// setting this when we are stopping the timer so someone can't restart it in the process.
//
private bool _stoppingTimer;
internal TimerNativeWindow(Timer owner) {
this._owner = owner;
}
~TimerNativeWindow() {
// note this call will work form the finalizer thread.
//
StopTimer();
}
public bool IsTimerRunning {
get {
return _timerID != 0 && Handle != IntPtr.Zero;
}
}
// Ensures that our HWND has been created.
//
private bool EnsureHandle() {
if (Handle == IntPtr.Zero) {
// we create a totally vanilla invisible window just for WM_TIMER messages.
//
CreateParams cp = new CreateParams();
cp.Style = 0;
cp.ExStyle = 0;
cp.ClassStyle = 0;
cp.Caption = GetType().Name;
// Message only windows are cheaper and have fewer issues than
// full blown invisible windows. But, they are only supported
// on NT.
if (Environment.OSVersion.Platform == PlatformID.Win32NT) {
cp.Parent = (IntPtr)NativeMethods.HWND_MESSAGE;
}
CreateHandle(cp);
}
Debug.Assert(Handle != IntPtr.Zero, "Timer HWND creation failed!");
return Handle != IntPtr.Zero;
}
// Returns true if we need to marshal across threads to access this timer's HWND.
//
private bool GetInvokeRequired(IntPtr hWnd) {
if (hWnd != IntPtr.Zero) {
int pid;
int hwndThread = SafeNativeMethods.GetWindowThreadProcessId(new HandleRef(this, hWnd), out pid);
int currentThread = SafeNativeMethods.GetCurrentThreadId();
return(hwndThread != currentThread);
}
return false;
}
// change the interval of the timer without destroying the HWND.
//
public void RestartTimer(int newInterval) {
StopTimer(false, IntPtr.Zero);
StartTimer(newInterval);
}
// Start the timer with the specified interval.
//
public void StartTimer(int interval) {
if (_timerID == 0 && !_stoppingTimer) {
if (EnsureHandle()) {
_timerID = (int) SafeNativeMethods.SetTimer(new HandleRef(this, Handle), TimerID++, interval, IntPtr.Zero);
}
}
}
// stop the timer.
//
public void StopTimer() {
StopTimer(true, IntPtr.Zero);
}
// stop the timer and optionally destroy the HWND.
//
public void StopTimer(bool destroyHwnd, IntPtr hWnd) {
if (hWnd == IntPtr.Zero) {
hWnd = Handle;
}
// Fire a message across threads to destroy the timer and HWND on the thread that created it.
//
if (GetInvokeRequired(hWnd)) {
UnsafeNativeMethods.PostMessage(new HandleRef(this, hWnd), NativeMethods.WM_CLOSE, 0, 0);
return;
}
// Locking 'this' here is ok since this is an internal class. See VSW#464499.
lock(this) {
if (_stoppingTimer || hWnd == IntPtr.Zero || !UnsafeNativeMethods.IsWindow(new HandleRef(this, hWnd))) {
return;
}
if (_timerID != 0) {
try {
_stoppingTimer = true;
SafeNativeMethods.KillTimer(new HandleRef(this, hWnd), _timerID);
}
finally {
_timerID = 0;
_stoppingTimer = false;
}
}
if (destroyHwnd) {
base.DestroyHandle();
}
}
}
// Destroy the handle, stopping the timer first.
//
public override void DestroyHandle() {
// don't recurse!
//
StopTimer(false, IntPtr.Zero);
Debug.Assert(_timerID == 0, "Destroying handle with timerID still set.");
base.DestroyHandle();
}
protected override void OnThreadException(Exception e) {
Application.OnThreadException(e);
}
public override void ReleaseHandle() {
// don't recurse!
//
StopTimer(false, IntPtr.Zero);
Debug.Assert(_timerID == 0, "Destroying handle with timerID still set.");
base.ReleaseHandle();
}
protected override void WndProc(ref Message m) {
Debug.Assert(m.HWnd == Handle && Handle != IntPtr.Zero, "Timer getting messages for other windows?");
// for timer messages, make sure they're ours (it'll be wierd if they aren't)
// and call the timer event.
//
if (m.Msg == NativeMethods.WM_TIMER) {
//Debug.Assert((int)m.WParam == _timerID, "Why are we getting a timer message that isn't ours?");
if ((int)m.WParam == _timerID) {
_owner.OnTick(EventArgs.Empty);
return;
}
}
else if (m.Msg == NativeMethods.WM_CLOSE) {
// this is a posted method from another thread that tells us we need
// to kill the timer. The handle may already be gone, so we specify it here.
//
StopTimer(true, m.HWnd);
return;
}
base.WndProc(ref m);
}
}
}
}
// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
Link Menu

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- XmlBinaryWriter.cs
- DriveInfo.cs
- ParserHooks.cs
- DrawingAttributeSerializer.cs
- Overlapped.cs
- ConsumerConnectionPointCollection.cs
- ThemeableAttribute.cs
- DependencyPropertyKind.cs
- XmlRootAttribute.cs
- SqlRecordBuffer.cs
- SqlDataSourceDesigner.cs
- RSACryptoServiceProvider.cs
- AutomationElementIdentifiers.cs
- newitemfactory.cs
- OleDbConnectionInternal.cs
- HttpApplicationStateBase.cs
- NumericUpDown.cs
- RowBinding.cs
- PublisherMembershipCondition.cs
- Oid.cs
- SecurityResources.cs
- CacheChildrenQuery.cs
- ComponentResourceKeyConverter.cs
- WebControlsSection.cs
- EntityDesignerUtils.cs
- AutomationAttributeInfo.cs
- HtmlUtf8RawTextWriter.cs
- SmtpFailedRecipientsException.cs
- QilLoop.cs
- CryptoApi.cs
- TdsParserHelperClasses.cs
- HostingPreferredMapPath.cs
- StringReader.cs
- BamlRecords.cs
- HttpPostedFile.cs
- SafePEFileHandle.cs
- StringValidatorAttribute.cs
- Viewport2DVisual3D.cs
- DataGridViewCellToolTipTextNeededEventArgs.cs
- CustomTypeDescriptor.cs
- CrossAppDomainChannel.cs
- ObjectStateFormatter.cs
- ListViewUpdateEventArgs.cs
- RemoteWebConfigurationHostServer.cs
- QilChoice.cs
- ApplicationId.cs
- CapabilitiesPattern.cs
- BorderSidesEditor.cs
- HttpsTransportBindingElement.cs
- ConnectionOrientedTransportElement.cs
- StatementContext.cs
- SqlConnectionPoolProviderInfo.cs
- DataGridViewRowEventArgs.cs
- PropertyEmitter.cs
- GridViewRow.cs
- SecurityRuntime.cs
- ComPlusInstanceContextInitializer.cs
- SerializationEventsCache.cs
- InputProcessorProfilesLoader.cs
- ControlIdConverter.cs
- HttpApplicationStateWrapper.cs
- DecimalKeyFrameCollection.cs
- Argument.cs
- Matrix.cs
- HtmlTableCellCollection.cs
- DbProviderServices.cs
- ISAPIWorkerRequest.cs
- ProjectedSlot.cs
- AddInServer.cs
- ByeOperationCD1AsyncResult.cs
- ScrollContentPresenter.cs
- GenericPrincipal.cs
- SqlProviderServices.cs
- DataGridCheckBoxColumn.cs
- ImageSourceConverter.cs
- DataRecordObjectView.cs
- SQLUtility.cs
- CheckedPointers.cs
- SignatureDescription.cs
- ClientEventManager.cs
- ListCollectionView.cs
- CurrentChangingEventArgs.cs
- ImmutableObjectAttribute.cs
- SoapDocumentMethodAttribute.cs
- SkipStoryboardToFill.cs
- OptimizedTemplateContent.cs
- Message.cs
- ContextConfiguration.cs
- UnsafeNativeMethods.cs
- DefaultValueTypeConverter.cs
- NamespaceDisplay.xaml.cs
- SqlMethodCallConverter.cs
- Wildcard.cs
- CultureTable.cs
- SafeEventLogReadHandle.cs
- MiniMapControl.xaml.cs
- SessionSwitchEventArgs.cs
- HtmlDocument.cs
- PathBox.cs
- DataBoundLiteralControl.cs