/// <summary> /// Registers a new event handler. /// Any other event handlers that the <paramref name="eventHandler"/> instance might implement, will be ignored. /// </summary> /// <typeparam name="TEvent">The type of event to add a handler for.</typeparam> /// <param name="eventHandler">The event handler to add.</param> /// <param name="weakRef"><c>true</c> to store a weak reference; <c>false</c> to store a strong reference.</param> /// <returns><c>true</c> if this specific event handler was not yet registered; otherwise, <c>false</c>.</returns> public bool Add <TEvent>(IEventHandler <TEvent> eventHandler, bool weakRef = true) where TEvent : EventBase { if (eventHandler.NullReference()) { throw Exc.Null(nameof(eventHandler)); } lock (this.subscribers) { if (this.isClosed) { return(false); } // do nothing if this handler is already registered if (this.IndexOfSpecificEventHandler <TEvent>(eventHandler) != -1) { return(false); } // wrap handler var newWrapper = EventHandlerWrapper.Create <TEvent>(eventHandler, weakRef); // register wrapper this.subscribers.Add(newWrapper); return(true); } }
/// <summary> /// Executes the specified <see cref="Action"/> asynchronously on the UI thread. /// </summary> /// <param name="func">The delegate to invoke.</param> /// <returns>The <see cref="Task"/> representing the operation.</returns> public static Task <T> InvokeAsync <T>(Func <T> func) { if (func.NullReference()) { throw Exc.Null(nameof(func)); } ThrowIfNoThread(); var tsc = new TaskCompletionSource <T>(); uiThread.BeginInvoke( () => { try { var result = func(); tsc.SetResult(result); } catch (Exception ex) { ex.StoreFileLine(); tsc.SetException(ex); } }); return(tsc.Task); }
/// <summary> /// Parses a string produced using <see cref="Compact"/>. /// </summary> /// <param name="str">The string to parse.</param> /// <param name="file">The file name in <paramref name="str"/>.</param> /// <param name="member">The member name in <paramref name="str"/>.</param> /// <param name="line">The line number in <paramref name="str"/>.</param> public static void ParseCompact(string str, out string file, out string member, out int line) { if (str.NullReference()) { throw Exc.Null(nameof(str)); } int memberAt = str.IndexOf(','); if (memberAt == -1) { throw new FormatException().Store(nameof(str), str); } else { member = str.Substring(startIndex: 0, length: memberAt).Trim(); } int lineAt = str.LastIndexOf(':'); if (lineAt == -1) { throw new FormatException().Store(nameof(str), str); } else if (!int.TryParse(str.Substring(startIndex: lineAt + 1), NumberStyles.Integer, CultureInfo.InvariantCulture, out line)) { throw new FormatException().Store(nameof(str), str); } file = str.Substring(startIndex: memberAt + 1, length: lineAt - memberAt - 1).Trim(); }
/// <summary> /// Converts the specified object to a <see cref="string"/>. /// Does not return <c>null</c>. /// </summary> /// <param name="obj">The object to convert to a string.</param> /// <returns>The string representation of the specified object. Never <c>null</c>.</returns> public string ToString(string obj) { if (obj.NullReference()) { throw Exc.Null(nameof(obj)); } return(obj); }
/// <summary> /// Adds a weak reference to the specified object, to this collection. /// </summary> /// <param name="obj">The object to store a weak reference of.</param> public void Add(T obj) { if (obj.NullReference()) { throw Exc.Null(nameof(obj)); } this.Add(new WeakReference <T>(obj)); }
internal WeakEventHandlerWrapper(IEventHandler <TEvent> subscriber) { if (subscriber.NullReference()) { throw Exc.Null(nameof(subscriber)); } this.weakRef = new WeakReference <IEventHandler <TEvent> >(subscriber); }
/// <summary> /// Initializes a new instance of the <see cref="DispatcherUIThread"/> class. /// </summary> /// <param name="uiDispatcher">The UI <see cref="Dispatcher"/>.</param> /// <param name="priority">The priority, relative to the other pending operations in the <see cref="T:System.Windows.Threading.Dispatcher" /> event queue, to invoke delegates with.</param> public DispatcherUIThread(Dispatcher uiDispatcher, DispatcherPriority priority = DispatcherPriority.Normal) // the priority used by Dispatcher.BeginInvoke(method, args) { if (!Enum.IsDefined(typeof(DispatcherPriority), priority)) { throw new ArgumentException($"Unknown dispatcher priority: {priority}!"); } this.dispatcher = uiDispatcher ?? throw Exc.Null(nameof(uiDispatcher)); this.dispatcherPriority = priority; }
private EventSubscriberTypeInfo(Type subscriberType) { this.Type = subscriberType ?? throw Exc.Null(nameof(subscriberType)); this.TypeInfo = this.Type.GetTypeInfo(); var types = GetEventHandlerTypes(this.Type); this.EventHandlerTypes = new ReadOnlyCollection <Type>(types); this.HandledEventTypes = new ReadOnlyCollection <Type>(GetHandledEventTypes(types)); }
/// <summary> /// Searches the subscriber for event handlers it implements, and removes any that can be found. /// </summary> /// <param name="subscriber">The subscriber to remove the event handlers of.</param> /// <returns><c>true</c> if at least one event handler was removed; <c>false</c> if none could be found.</returns> public bool RemoveAll(object subscriber) { if (subscriber.NullReference()) { throw Exc.Null(nameof(subscriber)); } var subscriberTypeInfo = EventSubscriberTypeInfo.AddOrGet(subscriber.GetType()); return(subscriberTypeInfo.RemoveAll(this, subscriber)); }
/// <summary> /// Searches the subscriber for event handlers it implements, /// and adds those that were not yet registered. /// </summary> /// <param name="subscriber">The subscriber to add the event handlers of.</param> /// <param name="weakRef"><c>true</c> to store weak references; <c>false</c> to store strong references.</param> /// <returns><c>true</c> if at least one event handler was added; otherwise, <c>false</c>.</returns> public bool AddAll(object subscriber, bool weakRef = true) { if (subscriber.NullReference()) { throw Exc.Null(nameof(subscriber)); } var subscriberTypeInfo = EventSubscriberTypeInfo.AddOrGet(subscriber.GetType()); return(subscriberTypeInfo.AddAll(this, subscriber, weakRef)); }
/// <summary> /// The window will not be closed while the main event queue is running, /// and shutting down the main event queue will shut down the window as well. /// </summary> /// <param name="window">The <see cref="Window"/> to bind to the main event queue.</param> public static void BindWindowToAppLifeCycle(Window window) { if (window.NullReference()) { throw Exc.Null(nameof(window)); } var windowCloseHandler = new WindowCloseHandler(window); MainEventQueue.Subscribers.Add <ShutDownEvent>(windowCloseHandler, weakRef: false); // a strong ref. for the handler, but a weak ref. for the window }
/// <summary> /// Invoked before the event is added to the <see cref="IEventQueueStorage"/>. /// Can optionally cancel the the adding. /// </summary> /// <param name="evnt">The event about to be added to the queue.</param> /// <param name="file">The source file of the caller.</param> /// <param name="member">The method or property name of the caller to this method.</param> /// <param name="line">The line number in <paramref name="file"/>.</param> /// <param name="canAdd">Determines whether the event can be added to the queue.</param> protected virtual void BeforeAdding( EventBase evnt, string file, string member, int line, out bool canAdd) { if (evnt.NullReference()) { throw Exc.Null(nameof(evnt)); } lock (this.syncLock) { // already enqueued? if (this.Storage.Contains(evnt)) { canAdd = false; return; } // shutdown request event? if (evnt is ShutdownRequestEvent) { if (this.shutdownRequestEnqueued || // another request is already enqueued or being handled (this.eventsState >= State.ShuttingDownEnqueued)) // we are already shutting down, there is no question about it { canAdd = false; return; } else { this.shutdownRequestEnqueued = true; } } else if (evnt is ShuttingDownEvent) // shutting down event? { if (this.eventsState >= State.ShuttingDownEnqueued) { // another shutting down event already enqueued canAdd = false; return; } else { this.eventsState = State.ShuttingDownEnqueued; } } evnt.EventEnqueuePos = FileLine.Compact(file, member, line); canAdd = true; } }
public static void Null() { Assert.NotNull(Exc.Null("test")); Assert.NotNull(Exc.Null(string.Empty)); Assert.NotNull(Exc.Null(null)); const string guid = "d5b5b296e9dd4f60a164e92deceeb530"; var exception = Exc.Null(guid); Assert.IsInstanceOf <ArgumentNullException>(exception); Assert.True(exception.Message.Contains(guid)); }
/// <summary> /// Adds the specified <see cref="WeakReference{T}"/> to this collection. /// The <see cref="WeakReference{T}"/> itself is stored using a strong reference. /// </summary> /// <param name="weakRef">The <see cref="WeakReference{T}"/> to add.</param> public void Add(WeakReference <T> weakRef) { if (weakRef.NullReference()) { throw Exc.Null(nameof(weakRef)); } //// NOTE: we are not checking whether the weak reference is still alive, //// since the assumption is that it was recently created (e.g. by one of our other members). this.list.Add(weakRef); }
/// <summary> /// Initializes a new instance of the <see cref="UnhandledExceptionEvent"/> class. /// </summary> /// <param name="exception">The exception to report.</param> public UnhandledExceptionEvent(Exception exception) { if (exception.NullReference()) { throw Exc.Null(nameof(exception)); } this.Initialize( type: exception.GetType().ToString(), message: exception.Message, full: ToString(exception)); }
/// <summary> /// Initializes a new instance of the <see cref="DispatcherEventQueue"/> class. /// </summary> /// <param name="uiDispatcher">The <see cref="Dispatcher"/> to use for event handling.</param> /// <param name="priority">The <see cref="DispatcherPriority"/> to use. Background priority is the default, to keep the UI snappy.</param> public DispatcherEventQueue(Dispatcher uiDispatcher, DispatcherPriority priority = DispatcherPriority.Background) { if (!Enum.IsDefined(typeof(DispatcherPriority), priority)) { throw new ArgumentException("Invalid priority!"); } this.dispatcher = uiDispatcher ?? throw Exc.Null(nameof(uiDispatcher)); this.dispatcherPriority = priority; this.isEventHandlerScheduled = new ThreadSafeBoolean(false); this.manualQueue = new ManualEventQueue(); this.scheduledDelegate = new Action(this.OnScheduled); }
/// <summary> /// Tries to add the specified event to the storage. /// The storage may refuse to store certain events /// (e.g. multiple <see cref="ShuttingDownEvent"/>s). /// </summary> /// <param name="evnt">The event to enqueue.</param> /// <returns><c>true</c> if the event was added to the storage; otherwise, <c>false</c>.</returns> public bool TryPush(EventBase evnt) { if (evnt.NullReference()) { throw Exc.Null(nameof(evnt)); } lock (this.syncLock) { this.events.Add(evnt); return(true); } }
/// <summary> /// Executes the specified <see cref="Action"/> asynchronously on the UI thread. /// </summary> /// <param name="action">The delegate to invoke.</param> public static void BeginInvoke(Action action) { if (action.NullReference()) { throw Exc.Null(nameof(action)); } ThrowIfNoThread(); // NOTE: we're not checking whether we're already on the UI thread! // even if we are, this method is supposed to be asynchronous. uiThread.BeginInvoke(action); }
/// <summary> /// Specifies the UI thread to use. /// May only set once at most. /// </summary> /// <param name="thread">The <see cref="IUIThread"/> to use.</param> public static void Set(IUIThread thread) { if (thread.NullReference()) { throw Exc.Null(nameof(thread)); } var previousValue = Interlocked.CompareExchange(ref uiThread, thread, comparand: null); if (previousValue.NotNullReference()) { throw new InvalidOperationException("UI already initialized!").StoreFileLine(); } }
/// <summary> /// Finds applicable subscribers, and has them handle the specified event, on the current thread. /// </summary> /// <param name="evnt">The event to handle.</param> /// <param name="exceptions">Stores exceptions throws by event handlers.</param> protected internal void Handle(EventBase evnt, List <Exception> exceptions) { if (evnt.NullReference()) { throw Exc.Null(nameof(evnt)); } if (exceptions.NullReference()) { throw Exc.Null(nameof(exceptions)); } lock (this.syncLock) { var eventTypeInfo = evnt.GetType().GetTypeInfo(); for (int i = 0; i < this.subscribers.Count;) { var wrapper = this.subscribers[i]; if (EventBase.CanHandle(wrapper.EventHandlerEventTypeInfo, eventTypeInfo)) { bool referenceFound = true; try { wrapper.Handle(evnt, out referenceFound); } catch (Exception ex) { exceptions.Add(ex); } if (referenceFound) { // event handled: continue ++i; } else { // GC already collected the event handler: remove wrapper and continue this.subscribers.RemoveAt(i); } } else { // event handler not compatible with event: continue ++i; } } } }
/// <summary> /// Executes the specified <see cref="Action"/> asynchronously on the UI thread. /// </summary> /// <param name="action">The delegate to invoke.</param> /// <returns>The <see cref="Task"/> representing the operation.</returns> public static Task InvokeAsync(Action action) { if (action.NullReference()) { throw Exc.Null(nameof(action)); } object Wrapper() { action(); return(null); } return(InvokeAsync <object>((Func <object>)Wrapper)); }
internal MainEventQueue(EventQueueBase eventQueue) { if (eventQueue.NullReference()) { throw Exc.Null(nameof(eventQueue)); } if (eventQueue.IsShutDown) { throw new ArgumentException("Event queue specified may not be shut down!"); } this.regularEventQueue = eventQueue; this.regularEventQueue.Subscribers.Add <ShuttingDownEvent>(this, weakRef: false); this.currentAppState = new ThreadSafeEnum <AppState>(AppState.Shutdown); }
/// <summary> /// Creates a new, stateless event handler. /// </summary> /// <typeparam name="TEvent">The type of events to handle instances of. The actual type of those instances may be a subclass of <typeparamref name="TEvent"/>.</typeparam> /// <param name="handler">The event handler delegate to use.</param> /// <returns>A new event handler instance.</returns> public static IEventHandler <TEvent> On <TEvent>(Action <TEvent> handler) where TEvent : EventBase { if (handler.NullReference()) { throw Exc.Null(nameof(handler)); } return(On <TEvent, object>( (currentState, evnt) => { handler(evnt); return null; }, initialState: null)); }
internal static EventSubscriberTypeInfo AddOrGet(Type subscriberType) { if (subscriberType.NullReference()) { throw Exc.Null(nameof(subscriberType)); } lock ( syncLock ) { if (!subscriberInfos.TryGetValue(subscriberType, out var info)) { info = new EventSubscriberTypeInfo(subscriberType); subscriberInfos.Add(subscriberType, info); } return(info); } }
internal DirectPropertyChangedListener( string property, Func <TSource, TProperty> getProperty, IEqualityComparer <TProperty> propertyComparer) { if (property.NullReference()) { throw Exc.Null("Invalid property name: null!"); } if (string.IsNullOrWhiteSpace(property) || char.IsWhiteSpace(property[0]) || char.IsWhiteSpace(property[property.Length - 1])) { throw new ArgumentException($"Invalid property name: \"{property}\"!"); } this.propertyName = property; this.getPropertyValue = getProperty ?? throw Exc.Null(nameof(getProperty)); this.comparer = propertyComparer; // may be null! this.source = default; this.lastValue = default; }
/// <summary> /// Removes the specified event handler. /// Any other event handlers that the <paramref name="eventHandler"/> instance might implement, /// which may or may not be registered as well, will be ignored. /// </summary> /// <typeparam name="TEvent">The type of event to remove a handler of.</typeparam> /// <param name="eventHandler">The event handler to remove.</param> /// <returns><c>true</c> if the event handler was removed; <c>false</c> if it could not be found.</returns> public bool Remove <TEvent>(IEventHandler <TEvent> eventHandler) where TEvent : EventBase { if (eventHandler.NullReference()) { throw Exc.Null(nameof(eventHandler)); } lock (this.subscribers) { if (this.isClosed) { return(false); } int index = this.IndexOfSpecificEventHandler <TEvent>(eventHandler); if (index != -1) { this.subscribers.RemoveAt(index); return(true); } return(false); } }
internal ChainChangeNotifier(Action <T, T> action) { this.notify = action ?? throw Exc.Null(nameof(action)); }
/// <summary> /// Initializes a new instance of the <see cref="DelegateCommand"/> class. /// </summary> /// <param name="execute">The delegate invoked by Execute.</param> /// <param name="canExecute">The delegate invoked by CanExecute.</param> public DelegateCommand(Action execute, Func <bool> canExecute = null) { this.execute = execute ?? throw Exc.Null(nameof(execute)); this.canExecute = canExecute; }
internal StrongEventHandlerWrapper(IEventHandler <TEvent> subscriber) { this.strongRef = subscriber ?? throw Exc.Null(nameof(subscriber)); }
public FinishedEventHandler(IEventQueue eventQueue, int eventIndex, EventHandledDelegate onHandled) { this.queue = eventQueue ?? throw Exc.Null(nameof(eventQueue)); this.index = eventIndex; this.handler = onHandled ?? throw Exc.Null(nameof(onHandled)); }