|
//------------------------------------------------------------------------------
// <copyright file="HtmlShim.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
namespace System.Windows.Forms {
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;
/// This is essentially a proxy object between the native
/// html objects and our managed ones. We want the managed
/// HtmlDocument, HtmlWindow and HtmlElement to be super-lightweight,
/// which means that we shouldnt have things that tie up their lifetimes
/// contained within them. The "Shim" is essentially the object that
/// manages events coming out of the HtmlDocument, HtmlElement and HtmlWindow
/// and serves them back up to the user.
internal abstract class HtmlShim : IDisposable {
private EventHandlerList events;
private int eventCount = 0;
private Dictionary<EventHandler, HtmlToClrEventProxy> attachedEventList;
protected HtmlShim() {
}
~HtmlShim() {
Dispose(false);
}
private EventHandlerList Events {
get {
if (events == null) {
events = new EventHandlerList();
}
return events;
}
}
/// Support IHtml*3.AttachHandler
public abstract void AttachEventHandler(string eventName, EventHandler eventHandler);
public void AddHandler(object key, Delegate value) {
eventCount++;
Events.AddHandler(key, value);
OnEventHandlerAdded();
}
protected HtmlToClrEventProxy AddEventProxy(string eventName, EventHandler eventHandler) {
if (attachedEventList == null) {
attachedEventList = new Dictionary<EventHandler, HtmlToClrEventProxy>();
}
HtmlToClrEventProxy proxy = new HtmlToClrEventProxy(this, eventName, eventHandler);
attachedEventList[eventHandler] = proxy;
return proxy;
}
public abstract UnsafeNativeMethods.IHTMLWindow2 AssociatedWindow {
get;
}
/// create connectionpoint cookie
public abstract void ConnectToEvents();
/// Support IHtml*3.DetachEventHandler
public abstract void DetachEventHandler(string eventName, EventHandler eventHandler);
/// disconnect from connectionpoint cookie
/// inheriting classes should override to disconnect from ConnectionPoint and call base.
public virtual void DisconnectFromEvents() {
if (attachedEventList != null) {
EventHandler[] events = new EventHandler[attachedEventList.Count];
attachedEventList.Keys.CopyTo(events,0);
foreach (EventHandler eh in events) {
HtmlToClrEventProxy proxy = attachedEventList[eh];
DetachEventHandler(proxy.EventName, eh);
}
}
}
/// return the sender for events, usually the HtmlWindow, HtmlElement, HtmlDocument
protected abstract object GetEventSender();
public void Dispose() {
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing) {
if (disposing) {
DisconnectFromEvents();
if (this.events != null) {
this.events.Dispose();
this.events = null;
}
}
}
public void FireEvent(object key, EventArgs e)
{
System.Delegate delegateToInvoke = (System.Delegate)Events[key];
if (delegateToInvoke != null) {
try {
delegateToInvoke.DynamicInvoke(GetEventSender(), e);
}
catch (Exception ex) {
// Note: this check is for the debugger, so we can catch exceptions in the debugger instead of
// throwing a thread exception.
if (NativeWindow.WndProcShouldBeDebuggable)
{
throw;
}
else {
Application.OnThreadException(ex);
}
}
}
}
protected virtual void OnEventHandlerAdded() {
ConnectToEvents();
}
protected virtual void OnEventHandlerRemoved() {
if (eventCount <=0) {
DisconnectFromEvents();
eventCount = 0;
}
}
public void RemoveHandler(object key, Delegate value) {
eventCount--;
Events.RemoveHandler(key, value);
OnEventHandlerRemoved();
}
protected HtmlToClrEventProxy RemoveEventProxy(EventHandler eventHandler) {
if (attachedEventList == null) {
return null;
}
if (attachedEventList.ContainsKey(eventHandler)) {
HtmlToClrEventProxy proxy = attachedEventList[eventHandler] as HtmlToClrEventProxy;
attachedEventList.Remove(eventHandler);
return proxy;
}
return null;
}
}
}
|