I was telling Warrior about a new code snippet I made recently for use in JinxBot:
<?xml version="1.0" encoding="utf-8" ?>
<CodeSnippets xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
<CodeSnippet Format="1.0.0">
<Header>
<Title>JinxBot Event</Title>
<Shortcut>jbevent</Shortcut>
<Description>Code snippet for declaring a JinxBot event.</Description>
<Author>MyndFyre</Author>
<SnippetTypes>
<SnippetType>Expansion</SnippetType>
</SnippetTypes>
</Header>
<Snippet>
<Declarations>
<Literal>
<ID>eventName</ID>
<ToolTip>The name of the event.</ToolTip>
<Default>EventName</Default>
</Literal>
<Literal>
<ID>eventtype</ID>
<ToolTip>The type name component for the delegate and event arguments used by this event. For example,
you might enter "EnteredChat" for EnteredChatEventHandler and EnteredChatEventArgs.</ToolTip>
<Default>EventType</Default>
</Literal>
<Literal>
<ID>eventdesc</ID>
<ToolTip>The comment to include.</ToolTip>
<Default>CommentText</Default>
</Literal>
</Declarations>
<Code Language="csharp">
<![CDATA[#region $eventName$ event
[NonSerialized]
private Dictionary<Priority, List<$eventtype$EventHandler>> __$eventName$ = new Dictionary<Priority, List<$eventtype$EventHandler>>(3);
/// <summary>
/// Informs listeners $eventdesc$
/// </summary>
/// <remarks>
/// <para>Registering for this event with this member will register with <see cref="Priority">Normal priority</see>. To register for
/// <see cref="Priority">High</see> or <see cref="Priority">Low</see> priority, use the <see>Register$eventName$Notification</see> and
/// <see>Unregister$eventName$Notification</see> methods.</para>
/// <para>Events in the JinxBot API are never guaranteed to be executed on the UI thread. Events that affect the user interface should
/// be marshaled back to the UI thread by the event handling code. Generally, high-priority event handlers are
/// raised on the thread that is parsing data from Battle.net, and lower-priority event handler are executed from the thread pool.</para>
/// <para>JinxBot guarantees that all event handlers will be fired regardless of exceptions raised in previous event handlers. However,
/// if a plugin repeatedly raises an exception, it may be forcefully unregistered from events.</para>
/// </remarks>
public event $eventtype$EventHandler $eventName$
{
add
{
lock (__$eventName$)
{
if (!__$eventName$.ContainsKey(Priority.Normal))
{
__$rvrntName$.Add(Priority.Normal, new List<$eventtype$EventHandler>());
}
}
__$eventName$[Priority.Normal].Add(value);
}
remove
{
if (__$eventName$.ContainsKey(Priority.Normal))
{
__$eventName$[Priority.Normal].Remove(value);
}
}
}
/// <summary>
/// Registers for notification of the <see>$eventName$</see> event at the specified priority.
/// </summary>
/// <remarks>
/// <para>The event system in the JinxBot API supports normal event registration and prioritized event registration. You can use
/// normal syntax to register for events at <see cref="Priority">Normal priority</see>, so no special registration is needed; this is
/// accessed through normal event handling syntax (the += syntax in C#, or the <see langword="Handles" lang="VB" /> in Visual Basic.</para>
/// <para>Events in the JinxBot API are never guaranteed to be executed on the UI thread. Events that affect the user interface should
/// be marshaled back to the UI thread by the event handling code. Generally, high-priority event handlers are
/// raised on the thread that is parsing data from Battle.net, and lower-priority event handler are executed from the thread pool.</para>
/// <para>JinxBot guarantees that all event handlers will be fired regardless of exceptions raised in previous event handlers. However,
/// if a plugin repeatedly raises an exception, it may be forcefully unregistered from events.</para>
/// <para>To be well-behaved within JinxBot, plugins should always unregister themselves when they are being unloaded or when they
/// otherwise need to do so. Plugins may opt-in to a Reflection-based event handling registration system which uses attributes to
/// mark methods that should be used as event handlers.</para>
/// </remarks>
/// <seealso cref="$eventName$" />
/// <seealso cref="Unregister$eventName$Notification" />
public void Register$eventName$Notification(Priority p, $eventtype$EventHandler callback)
{
lock (__$eventName$)
{
if (!__$eventName$.ContainsKey(p))
{
__$rvrntName$.Add(p, new List<$eventtype$EventHandler>());
}
}
__$eventName$[p].Add(value);
}
/// <summary>
/// Unregisters for notification of the <see>$eventName$</see> event at the specified priority.
/// </summary>
/// <remarks>
/// <para>The event system in the JinxBot API supports normal event registration and prioritized event registration. You can use
/// normal syntax to register for events at <see cref="Priority">Normal priority</see>, so no special registration is needed; this is
/// accessed through normal event handling syntax (the += syntax in C#, or the <see langword="Handles" lang="VB" /> in Visual Basic.</para>
/// <para>Events in the JinxBot API are never guaranteed to be executed on the UI thread. Events that affect the user interface should
/// be marshaled back to the UI thread by the event handling code. Generally, high-priority event handlers are
/// raised on the thread that is parsing data from Battle.net, and lower-priority event handler are executed from the thread pool.</para>
/// <para>JinxBot guarantees that all event handlers will be fired regardless of exceptions raised in previous event handlers. However,
/// if a plugin repeatedly raises an exception, it may be forcefully unregistered from events.</para>
/// <para>To be well-behaved within JinxBot, plugins should always unregister themselves when they are being unloaded or when they
/// otherwise need to do so. Plugins may opt-in to a Reflection-based event handling registration system which uses attributes to
/// mark methods that should be used as event handlers.</para>
/// </remarks>
/// <seealso cref="$eventName$" />
/// <seealso cref="Register$eventName$Notification" />
public void Unregister$eventName$Notification(Priority p, $eventtype$EventHandler callback)
{
if (__$eventName$.ContainsKey(Priority.Normal))
{
__$eventName$[Priority.Normal].Remove(value);
}
}
/// <summary>
/// Raises the $eventName$ event.
/// </summary>
/// <remarks>
/// <para>Only high-priority events are invoked immediately; others are deferred. For more information, see <see>$eventName$</see>.</para>
/// </remarks>
/// <seealso cref="$eventName$" />
protected virtual void On$eventName$($eventtype$EventArgs e)
{
foreach ($eventtype$EventHandler eh in __$eventName$[Priority.High])
{
try
{
eh(this, e);
}
catch (Exception ex)
{
ReportException(
ex,
new KeyValuePair<string, object>("delegate", eh),
new KeyValuePair<string, object>("Event", "$eventName$"),
new KeyValuePair<string, object>("param: priority", Priority.High),
new KeyValuePair<string, object>("param: this", this),
new KeyValuePair<string, object>("param: e", e)
);
}
}
ThreadPool.QueueUserWorkItem((WaitCallback)delegate
{
foreach ($eventtype$EventHandler eh in __$eventName$[Priority.Normal])
{
try
{
eh(this, e);
}
catch (Exception ex)
{
ReportException(
ex,
new KeyValuePair<string, object>("delegate", eh),
new KeyValuePair<string, object>("Event", "$eventName$"),
new KeyValuePair<string, object>("param: priority", Priority.Normal),
new KeyValuePair<string, object>("param: this", this),
new KeyValuePair<string, object>("param: e", e)
);
}
}
ThreadPool.QueueUserWorkItem((WaitCallback)delegate
{
foreach ($eventtype$EventHandler eh in __$eventName$[Priority.Low])
{
try
{
eh(this, e);
}
catch (Exception ex)
{
ReportException(
ex,
new KeyValuePair<string, object>("delegate", eh),
new KeyValuePair<string, object>("Event", "$eventName$"),
new KeyValuePair<string, object>("param: priority", Priority.Low),
new KeyValuePair<string, object>("param: this", this),
new KeyValuePair<string, object>("param: e", e)
);
}
}
});
});
}
#endregion
]]>
</Code>
</Snippet>
</CodeSnippet>
</CodeSnippets>
Pretty slick, it supports my prioritized event subsystem. To access it, I type "jbevent" and press tab. This is what I got after filling in only three fields:
#region UserSpoke event
[NonSerialized]
private Dictionary<Priority, List<ChatEventHandler>> __UserSpoke = new Dictionary<Priority, List<ChatEventHandler>>(3);
/// <summary>
/// Informs listeners that a user in the channel has said something.
/// </summary>
/// <remarks>
/// <para>Registering for this event with this member will register with <see cref="Priority">Normal priority</see>. To register for
/// <see cref="Priority">High</see> or <see cref="Priority">Low</see> priority, use the <see>RegisterUserSpokeNotification</see> and
/// <see>UnregisterUserSpokeNotification</see> methods.</para>
/// <para>Events in the JinxBot API are never guaranteed to be executed on the UI thread. Events that affect the user interface should
/// be marshaled back to the UI thread by the event handling code. Generally, high-priority event handlers are
/// raised on the thread that is parsing data from Battle.net, and lower-priority event handler are executed from the thread pool.</para>
/// <para>JinxBot guarantees that all event handlers will be fired regardless of exceptions raised in previous event handlers. However,
/// if a plugin repeatedly raises an exception, it may be forcefully unregistered from events.</para>
/// </remarks>
public event ChatEventHandler UserSpoke
{
add
{
lock (__UserSpoke)
{
if (!__UserSpoke.ContainsKey(Priority.Normal))
{
__.Add(Priority.Normal, new List<ChatEventHandler>());
}
}
__UserSpoke[Priority.Normal].Add(value);
}
remove
{
if (__UserSpoke.ContainsKey(Priority.Normal))
{
__UserSpoke[Priority.Normal].Remove(value);
}
}
}
/// <summary>
/// Registers for notification of the <see>UserSpoke</see> event at the specified priority.
/// </summary>
/// <remarks>
/// <para>The event system in the JinxBot API supports normal event registration and prioritized event registration. You can use
/// normal syntax to register for events at <see cref="Priority">Normal priority</see>, so no special registration is needed; this is
/// accessed through normal event handling syntax (the += syntax in C#, or the <see langword="Handles" lang="VB" /> in Visual Basic.</para>
/// <para>Events in the JinxBot API are never guaranteed to be executed on the UI thread. Events that affect the user interface should
/// be marshaled back to the UI thread by the event handling code. Generally, high-priority event handlers are
/// raised on the thread that is parsing data from Battle.net, and lower-priority event handler are executed from the thread pool.</para>
/// <para>JinxBot guarantees that all event handlers will be fired regardless of exceptions raised in previous event handlers. However,
/// if a plugin repeatedly raises an exception, it may be forcefully unregistered from events.</para>
/// <para>To be well-behaved within JinxBot, plugins should always unregister themselves when they are being unloaded or when they
/// otherwise need to do so. Plugins may opt-in to a Reflection-based event handling registration system which uses attributes to
/// mark methods that should be used as event handlers.</para>
/// </remarks>
/// <seealso cref="UserSpoke" />
/// <seealso cref="UnregisterUserSpokeNotification" />
public void RegisterUserSpokeNotification(Priority p, ChatEventHandler callback)
{
lock (__UserSpoke)
{
if (!__UserSpoke.ContainsKey(p))
{
__.Add(p, new List<ChatEventHandler>());
}
}
__UserSpoke[p].Add(value);
}
/// <summary>
/// Unregisters for notification of the <see>UserSpoke</see> event at the specified priority.
/// </summary>
/// <remarks>
/// <para>The event system in the JinxBot API supports normal event registration and prioritized event registration. You can use
/// normal syntax to register for events at <see cref="Priority">Normal priority</see>, so no special registration is needed; this is
/// accessed through normal event handling syntax (the += syntax in C#, or the <see langword="Handles" lang="VB" /> in Visual Basic.</para>
/// <para>Events in the JinxBot API are never guaranteed to be executed on the UI thread. Events that affect the user interface should
/// be marshaled back to the UI thread by the event handling code. Generally, high-priority event handlers are
/// raised on the thread that is parsing data from Battle.net, and lower-priority event handler are executed from the thread pool.</para>
/// <para>JinxBot guarantees that all event handlers will be fired regardless of exceptions raised in previous event handlers. However,
/// if a plugin repeatedly raises an exception, it may be forcefully unregistered from events.</para>
/// <para>To be well-behaved within JinxBot, plugins should always unregister themselves when they are being unloaded or when they
/// otherwise need to do so. Plugins may opt-in to a Reflection-based event handling registration system which uses attributes to
/// mark methods that should be used as event handlers.</para>
/// </remarks>
/// <seealso cref="UserSpoke" />
/// <seealso cref="RegisterUserSpokeNotification" />
public void UnregisterUserSpokeNotification(Priority p, ChatEventHandler callback)
{
if (__UserSpoke.ContainsKey(Priority.Normal))
{
__UserSpoke[Priority.Normal].Remove(value);
}
}
/// <summary>
/// Raises the UserSpoke event.
/// </summary>
/// <remarks>
/// <para>Only high-priority events are invoked immediately; others are deferred. For more information, see <see>UserSpoke</see>.</para>
/// </remarks>
/// <seealso cref="UserSpoke" />
protected virtual void OnUserSpoke(ChatEventArgs e)
{
foreach (ChatEventHandler eh in __UserSpoke[Priority.High])
{
try
{
eh(this, e);
}
catch (Exception ex)
{
ReportException(
ex,
new KeyValuePair<string, object>("delegate", eh),
new KeyValuePair<string, object>("Event", "UserSpoke"),
new KeyValuePair<string, object>("param: priority", Priority.High),
new KeyValuePair<string, object>("param: this", this),
new KeyValuePair<string, object>("param: e", e)
);
}
}
ThreadPool.QueueUserWorkItem((WaitCallback)delegate
{
foreach (ChatEventHandler eh in __UserSpoke[Priority.Normal])
{
try
{
eh(this, e);
}
catch (Exception ex)
{
ReportException(
ex,
new KeyValuePair<string, object>("delegate", eh),
new KeyValuePair<string, object>("Event", "UserSpoke"),
new KeyValuePair<string, object>("param: priority", Priority.Normal),
new KeyValuePair<string, object>("param: this", this),
new KeyValuePair<string, object>("param: e", e)
);
}
}
ThreadPool.QueueUserWorkItem((WaitCallback)delegate
{
foreach (ChatEventHandler eh in __UserSpoke[Priority.Low])
{
try
{
eh(this, e);
}
catch (Exception ex)
{
ReportException(
ex,
new KeyValuePair<string, object>("delegate", eh),
new KeyValuePair<string, object>("Event", "UserSpoke"),
new KeyValuePair<string, object>("param: priority", Priority.Low),
new KeyValuePair<string, object>("param: this", this),
new KeyValuePair<string, object>("param: e", e)
);
}
}
});
});
}
#endregion
Primary drawback is that they don't work like macros. I have to re-create all my events if this changes. Sad day.