Code:
/ DotNET / DotNET / 8.0 / untmp / whidbey / REDBITS / 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.
Link Menu

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- Visual3D.cs
- RenderOptions.cs
- ProviderUtil.cs
- SoapTypeAttribute.cs
- Literal.cs
- InputLangChangeRequestEvent.cs
- ParameterElement.cs
- ExtendedProtectionPolicyTypeConverter.cs
- IsolatedStorageFileStream.cs
- CachedPathData.cs
- CompModSwitches.cs
- DataColumnMappingCollection.cs
- OleDbException.cs
- LogicalTreeHelper.cs
- ActivityFunc.cs
- BinaryNode.cs
- PropertyChangedEventManager.cs
- IOException.cs
- _ReceiveMessageOverlappedAsyncResult.cs
- CopyCodeAction.cs
- IFlowDocumentViewer.cs
- PointCollectionValueSerializer.cs
- KnowledgeBase.cs
- RowToParametersTransformer.cs
- InternalTypeHelper.cs
- unitconverter.cs
- PolicyManager.cs
- FixUpCollection.cs
- DataColumn.cs
- DynamicValidatorEventArgs.cs
- DockPanel.cs
- Form.cs
- Native.cs
- HttpFileCollection.cs
- BamlResourceSerializer.cs
- SByte.cs
- Encoder.cs
- PermissionAttributes.cs
- HttpHandlersSection.cs
- HttpWebRequestElement.cs
- ClipboardData.cs
- WindowsAuthenticationEventArgs.cs
- ParserContext.cs
- StringFreezingAttribute.cs
- ConnectionPoint.cs
- DataGridViewAutoSizeColumnModeEventArgs.cs
- TextRangeEditLists.cs
- XmlExpressionDumper.cs
- IApplicationTrustManager.cs
- HtmlInputRadioButton.cs
- EncoderBestFitFallback.cs
- StatusBarDrawItemEvent.cs
- QueryStringParameter.cs
- TextDecorations.cs
- RegularExpressionValidator.cs
- Condition.cs
- DbException.cs
- DataGridCell.cs
- AsymmetricKeyExchangeFormatter.cs
- WebPartConnectionsConnectVerb.cs
- WSTrustFeb2005.cs
- WizardSideBarListControlItemEventArgs.cs
- WsatTransactionInfo.cs
- EditorPartChrome.cs
- ReadOnlyHierarchicalDataSourceView.cs
- FlowPosition.cs
- ExistsInCollection.cs
- AppSettingsReader.cs
- ToolStripContentPanel.cs
- ExpressionPrefixAttribute.cs
- AsymmetricSecurityBindingElement.cs
- FontWeightConverter.cs
- ListControlActionList.cs
- EntityTransaction.cs
- XPathSingletonIterator.cs
- PtsHelper.cs
- XmlNavigatorStack.cs
- RefreshPropertiesAttribute.cs
- ControlEvent.cs
- initElementDictionary.cs
- FacetEnabledSchemaElement.cs
- XmlIncludeAttribute.cs
- Completion.cs
- CellLabel.cs
- TagElement.cs
- cookiecontainer.cs
- SymbolDocumentInfo.cs
- SqlError.cs
- TemplateControl.cs
- XmlSchemaObjectTable.cs
- HandlerBase.cs
- VScrollProperties.cs
- AtomPub10CategoriesDocumentFormatter.cs
- FeatureSupport.cs
- WindowsToolbar.cs
- ReadOnlyDictionary.cs
- XmlDataFileEditor.cs
- GridItemProviderWrapper.cs
- CodeParameterDeclarationExpression.cs
- ClientSettings.cs