Ooui-tws-port/Ooui/EventTarget.cs

208 lines
6.4 KiB
C#
Raw Normal View History

2017-06-15 01:24:59 +00:00
using System;
using System.Collections.Generic;
using System.Linq;
namespace Ooui
{
2017-06-15 09:39:19 +00:00
[Newtonsoft.Json.JsonConverter (typeof (EventTargetJsonConverter))]
2017-06-15 01:24:59 +00:00
public abstract class EventTarget
{
2017-06-15 06:10:58 +00:00
readonly List<Message> stateMessages = new List<Message> ();
readonly Dictionary<string, List<EventHandler>> eventListeners =
new Dictionary<string, List<EventHandler>> ();
2017-06-15 01:24:59 +00:00
public string Id { get; private set; } = GenerateId ();
2017-06-15 06:20:51 +00:00
public string TagName { get; private set; }
2017-06-15 01:24:59 +00:00
public event Action<Message> MessageSent;
2017-06-18 06:21:49 +00:00
public IReadOnlyList<Message> StateMessages {
2017-06-16 00:28:49 +00:00
get {
lock (stateMessages) {
2017-06-18 06:21:49 +00:00
return new List<Message> (stateMessages).AsReadOnly ();
2017-06-16 00:28:49 +00:00
}
}
}
2017-06-15 01:24:59 +00:00
2017-06-15 06:20:51 +00:00
protected EventTarget (string tagName)
2017-06-15 01:24:59 +00:00
{
2017-06-15 06:20:51 +00:00
TagName = tagName;
2017-06-15 06:30:48 +00:00
2017-06-15 06:27:28 +00:00
Send (new Message {
MessageType = MessageType.Create,
TargetId = Id,
Key = TagName,
});
2017-06-15 01:24:59 +00:00
}
2017-06-18 06:21:49 +00:00
public override string ToString() => $"<{TagName} id=\"{Id}\" />";
2017-06-15 09:39:19 +00:00
public virtual EventTarget GetElementById (string id)
{
if (id == Id) return this;
return null;
}
2017-06-15 06:10:58 +00:00
public void AddEventListener (string eventType, EventHandler handler)
{
if (eventType == null) return;
if (handler == null) return;
var sendListen = false;
List<EventHandler> handlers;
2017-06-16 00:50:57 +00:00
lock (eventListeners) {
if (!eventListeners.TryGetValue (eventType, out handlers)) {
handlers = new List<EventHandler> ();
eventListeners[eventType] = handlers;
sendListen = true;
}
handlers.Add (handler);
2017-06-15 06:10:58 +00:00
}
if (sendListen)
2017-06-15 06:30:48 +00:00
Send (new Message {
MessageType = MessageType.Listen,
TargetId = Id,
Key = eventType,
});
2017-06-15 06:10:58 +00:00
}
public void RemoveEventListener (string eventType, EventHandler handler)
{
if (eventType == null) return;
if (handler == null) return;
List<EventHandler> handlers;
2017-06-16 00:50:57 +00:00
lock (eventListeners) {
if (eventListeners.TryGetValue (eventType, out handlers)) {
handlers.Remove (handler);
}
2017-06-15 06:10:58 +00:00
}
}
2017-06-15 01:24:59 +00:00
protected bool SetProperty<T> (ref T backingStore, T newValue, string attributeName, [System.Runtime.CompilerServices.CallerMemberName] string propertyName = "")
{
2017-06-18 19:52:51 +00:00
if (EqualityComparer<T>.Default.Equals (backingStore, newValue))
return false;
backingStore = newValue;
SendSet (attributeName, newValue);
2017-06-20 04:55:20 +00:00
OnPropertyChanged (propertyName);
2017-06-18 19:52:51 +00:00
return true;
2017-06-15 01:24:59 +00:00
}
2017-06-20 04:55:20 +00:00
protected virtual void OnPropertyChanged (string propertyName)
{
}
2017-06-15 09:39:19 +00:00
public const char IdPrefix = '\u2999';
2017-06-15 01:24:59 +00:00
static long idCounter = 0;
static string GenerateId ()
{
var id = System.Threading.Interlocked.Increment (ref idCounter);
2017-06-15 09:39:19 +00:00
return $"{IdPrefix}{id}";
2017-06-15 01:24:59 +00:00
}
2017-06-17 00:07:30 +00:00
public void Send (Message message)
2017-06-15 01:24:59 +00:00
{
2017-06-17 00:07:30 +00:00
if (message == null)
return;
if (message.TargetId == Id)
SaveStateMessageIfNeeded (message);
2017-06-15 01:24:59 +00:00
MessageSent?.Invoke (message);
}
protected void SendCall (string methodName, params object[] args)
{
2017-06-16 04:27:15 +00:00
Send (Message.Call (Id, methodName, args));
2017-06-15 01:24:59 +00:00
}
protected void SendSet (string attributeName, object value)
{
Send (new Message {
MessageType = MessageType.Set,
TargetId = Id,
Key = attributeName,
Value = value,
});
}
2017-06-17 00:07:30 +00:00
public void Receive (Message message)
2017-06-15 01:24:59 +00:00
{
if (message == null)
return;
if (message.TargetId != Id)
return;
SaveStateMessageIfNeeded (message);
TriggerEventFromMessage (message);
}
2017-06-18 06:21:49 +00:00
protected void AddStateMessage (Message message)
2017-06-15 01:24:59 +00:00
{
2017-06-16 00:28:49 +00:00
lock (stateMessages) stateMessages.Add (message);
2017-06-15 01:24:59 +00:00
}
2017-06-18 06:21:49 +00:00
protected void UpdateStateMessages (Action<List<Message>> updater)
2017-06-15 01:24:59 +00:00
{
2017-06-18 06:21:49 +00:00
lock (stateMessages) updater (stateMessages);
2017-06-15 01:24:59 +00:00
}
protected virtual void SaveStateMessageIfNeeded (Message message)
{
switch (message.MessageType) {
case MessageType.Create:
2017-06-18 06:21:49 +00:00
AddStateMessage (message);
2017-06-15 01:24:59 +00:00
break;
case MessageType.Set:
2017-06-18 06:21:49 +00:00
UpdateStateMessages (state => {
state.RemoveAll (x => x.MessageType == MessageType.Set && x.Key == message.Key);
state.Add (message);
});
2017-06-15 01:24:59 +00:00
break;
2017-06-15 06:10:58 +00:00
case MessageType.Listen:
2017-06-18 06:21:49 +00:00
AddStateMessage (message);
2017-06-15 06:10:58 +00:00
break;
2017-06-15 01:24:59 +00:00
}
}
protected virtual void TriggerEventFromMessage (Message message)
{
2017-06-16 00:50:57 +00:00
List<EventHandler> handlers = null;
lock (eventListeners) {
List<EventHandler> hs;
if (eventListeners.TryGetValue (message.Key, out hs)) {
handlers = new List<EventHandler> (hs);
2017-06-15 06:10:58 +00:00
}
}
2017-06-16 00:50:57 +00:00
if (handlers == null) return;
var args = EventArgs.Empty;
foreach (var h in handlers) {
h.Invoke (this, args);
}
2017-06-15 01:24:59 +00:00
}
}
2017-06-15 09:39:19 +00:00
class EventTargetJsonConverter : Newtonsoft.Json.JsonConverter
{
public override bool CanRead => false;
public override void WriteJson (Newtonsoft.Json.JsonWriter writer, object value, Newtonsoft.Json.JsonSerializer serializer)
{
writer.WriteValue (((EventTarget)value).Id);
}
public override object ReadJson (Newtonsoft.Json.JsonReader reader, Type objectType, object existingValue, Newtonsoft.Json.JsonSerializer serializer)
{
2017-06-17 00:07:30 +00:00
throw new NotSupportedException ();
2017-06-15 09:39:19 +00:00
}
public override bool CanConvert (Type objectType)
{
return typeof (EventTarget).IsAssignableFrom (objectType);
}
}
2017-06-15 01:24:59 +00:00
}