diff --git a/src/Avalonia.Interactivity/Avalonia.Interactivity.csproj b/src/Avalonia.Interactivity/Avalonia.Interactivity.csproj
index 66f1e8cc26..730ca2bd6e 100644
--- a/src/Avalonia.Interactivity/Avalonia.Interactivity.csproj
+++ b/src/Avalonia.Interactivity/Avalonia.Interactivity.csproj
@@ -1,6 +1,8 @@
netstandard2.0
+ Enable
+ CS8600;CS8602;CS8603
@@ -9,6 +11,4 @@
-
-
-
+
\ No newline at end of file
diff --git a/src/Avalonia.Interactivity/EventSubscription.cs b/src/Avalonia.Interactivity/EventSubscription.cs
index e8fb1bfaf1..d363e3f6fa 100644
--- a/src/Avalonia.Interactivity/EventSubscription.cs
+++ b/src/Avalonia.Interactivity/EventSubscription.cs
@@ -9,12 +9,24 @@ namespace Avalonia.Interactivity
internal class EventSubscription
{
- public HandlerInvokeSignature InvokeAdapter { get; set; }
+ public EventSubscription(
+ Delegate handler,
+ RoutingStrategies routes,
+ bool handledEventsToo,
+ HandlerInvokeSignature? invokeAdapter = null)
+ {
+ Handler = handler;
+ Routes = routes;
+ HandledEventsToo = handledEventsToo;
+ InvokeAdapter = invokeAdapter;
+ }
- public Delegate Handler { get; set; }
+ public HandlerInvokeSignature? InvokeAdapter { get; }
- public RoutingStrategies Routes { get; set; }
+ public Delegate Handler { get; }
- public bool AlsoIfHandled { get; set; }
+ public RoutingStrategies Routes { get; }
+
+ public bool HandledEventsToo { get; }
}
}
diff --git a/src/Avalonia.Interactivity/IInteractive.cs b/src/Avalonia.Interactivity/IInteractive.cs
index 47046b58e2..6524794733 100644
--- a/src/Avalonia.Interactivity/IInteractive.cs
+++ b/src/Avalonia.Interactivity/IInteractive.cs
@@ -13,7 +13,7 @@ namespace Avalonia.Interactivity
///
/// Gets the interactive parent of the object for bubbling and tunneling events.
///
- IInteractive InteractiveParent { get; }
+ IInteractive? InteractiveParent { get; }
///
/// Adds a handler for the specified routed event.
diff --git a/src/Avalonia.Interactivity/Interactive.cs b/src/Avalonia.Interactivity/Interactive.cs
index 27ece25183..0c4649a1ca 100644
--- a/src/Avalonia.Interactivity/Interactive.cs
+++ b/src/Avalonia.Interactivity/Interactive.cs
@@ -15,16 +15,16 @@ namespace Avalonia.Interactivity
///
public class Interactive : Layoutable, IInteractive
{
- private Dictionary> _eventHandlers;
+ private Dictionary>? _eventHandlers;
private static readonly Dictionary s_invokeHandlerCache = new Dictionary();
///
/// Gets the interactive parent of the object for bubbling and tunneling events.
///
- IInteractive IInteractive.InteractiveParent => ((IVisual)this).VisualParent as IInteractive;
+ IInteractive? IInteractive.InteractiveParent => ((IVisual)this).VisualParent as IInteractive;
- private Dictionary> EventHandlers => _eventHandlers ?? (_eventHandlers = new Dictionary>());
+ private Dictionary> EventHandlers => _eventHandlers ??= new Dictionary>();
///
/// Adds a handler for the specified routed event.
@@ -40,16 +40,10 @@ namespace Avalonia.Interactivity
RoutingStrategies routes = RoutingStrategies.Direct | RoutingStrategies.Bubble,
bool handledEventsToo = false)
{
- Contract.Requires(routedEvent != null);
- Contract.Requires(handler != null);
-
- var subscription = new EventSubscription
- {
- Handler = handler,
- Routes = routes,
- AlsoIfHandled = handledEventsToo,
- };
+ routedEvent = routedEvent ?? throw new ArgumentNullException(nameof(routedEvent));
+ handler = handler ?? throw new ArgumentNullException(nameof(handler));
+ var subscription = new EventSubscription(handler, routes, handledEventsToo);
return AddEventSubscription(routedEvent, subscription);
}
@@ -68,12 +62,12 @@ namespace Avalonia.Interactivity
RoutingStrategies routes = RoutingStrategies.Direct | RoutingStrategies.Bubble,
bool handledEventsToo = false) where TEventArgs : RoutedEventArgs
{
- Contract.Requires(routedEvent != null);
- Contract.Requires(handler != null);
+ routedEvent = routedEvent ?? throw new ArgumentNullException(nameof(routedEvent));
+ handler = handler ?? throw new ArgumentNullException(nameof(handler));
// EventHandler delegate is not covariant, this forces us to create small wrapper
// that will cast our type erased instance and invoke it.
- Type eventArgsType = routedEvent.EventArgsType;
+ var eventArgsType = routedEvent.EventArgsType;
if (!s_invokeHandlerCache.TryGetValue(eventArgsType, out var invokeAdapter))
{
@@ -90,14 +84,7 @@ namespace Avalonia.Interactivity
s_invokeHandlerCache.Add(eventArgsType, invokeAdapter);
}
- var subscription = new EventSubscription
- {
- InvokeAdapter = invokeAdapter,
- Handler = handler,
- Routes = routes,
- AlsoIfHandled = handledEventsToo,
- };
-
+ var subscription = new EventSubscription(handler, routes, handledEventsToo, invokeAdapter);
return AddEventSubscription(routedEvent, subscription);
}
@@ -108,12 +95,11 @@ namespace Avalonia.Interactivity
/// The handler.
public void RemoveHandler(RoutedEvent routedEvent, Delegate handler)
{
- Contract.Requires(routedEvent != null);
- Contract.Requires(handler != null);
-
- List subscriptions = null;
+ routedEvent = routedEvent ?? throw new ArgumentNullException(nameof(routedEvent));
+ handler = handler ?? throw new ArgumentNullException(nameof(handler));
- if (_eventHandlers?.TryGetValue(routedEvent, out subscriptions) == true)
+ if (_eventHandlers is object &&
+ _eventHandlers.TryGetValue(routedEvent, out var subscriptions) == true)
{
subscriptions.RemoveAll(x => x.Handler == handler);
}
@@ -137,9 +123,14 @@ namespace Avalonia.Interactivity
/// The event args.
public void RaiseEvent(RoutedEventArgs e)
{
- Contract.Requires(e != null);
+ e = e ?? throw new ArgumentNullException(nameof(e));
- e.Source = e.Source ?? this;
+ if (e.RoutedEvent == null)
+ {
+ throw new ArgumentException("Cannot raise an event whose RoutedEvent is null.");
+ }
+
+ e.Source ??= this;
if (e.RoutedEvent.RoutingStrategies == RoutingStrategies.Direct)
{
@@ -167,7 +158,7 @@ namespace Avalonia.Interactivity
/// The event args.
private void BubbleEvent(RoutedEventArgs e)
{
- Contract.Requires(e != null);
+ e = e ?? throw new ArgumentNullException(nameof(e));
e.Route = RoutingStrategies.Bubble;
@@ -182,7 +173,7 @@ namespace Avalonia.Interactivity
/// The event args.
private void TunnelEvent(RoutedEventArgs e)
{
- Contract.Requires(e != null);
+ e = e ?? throw new ArgumentNullException(nameof(e));
e.Route = RoutingStrategies.Tunnel;
@@ -197,18 +188,17 @@ namespace Avalonia.Interactivity
/// The event args.
private void RaiseEventImpl(RoutedEventArgs e)
{
- Contract.Requires(e != null);
-
- e.RoutedEvent.InvokeRaised(this, e);
+ e = e ?? throw new ArgumentNullException(nameof(e));
- List subscriptions = null;
+ e.RoutedEvent!.InvokeRaised(this, e);
- if (_eventHandlers?.TryGetValue(e.RoutedEvent, out subscriptions) == true)
+ if (_eventHandlers is object &&
+ _eventHandlers.TryGetValue(e.RoutedEvent, out var subscriptions) == true)
{
foreach (var sub in subscriptions.ToList())
{
bool correctRoute = (e.Route & sub.Routes) != 0;
- bool notFinished = !e.Handled || sub.AlsoIfHandled;
+ bool notFinished = !e.Handled || sub.HandledEventsToo;
if (correctRoute && notFinished)
{
@@ -313,7 +303,7 @@ namespace Avalonia.Interactivity
{
_preTraverse.Execute(target, _args);
- IInteractive parent = target.InteractiveParent;
+ var parent = target.InteractiveParent;
if (parent != null)
{
diff --git a/src/Avalonia.Interactivity/InteractiveExtensions.cs b/src/Avalonia.Interactivity/InteractiveExtensions.cs
index 07e4029240..414c408080 100644
--- a/src/Avalonia.Interactivity/InteractiveExtensions.cs
+++ b/src/Avalonia.Interactivity/InteractiveExtensions.cs
@@ -2,8 +2,6 @@
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
-using System.Collections.Generic;
-using System.Linq;
using System.Reactive.Linq;
namespace Avalonia.Interactivity
@@ -30,6 +28,9 @@ namespace Avalonia.Interactivity
bool handledEventsToo = false)
where TEventArgs : RoutedEventArgs
{
+ o = o ?? throw new ArgumentNullException(nameof(o));
+ routedEvent = routedEvent ?? throw new ArgumentNullException(nameof(routedEvent));
+
return Observable.Create(x => o.AddHandler(
routedEvent,
(_, e) => x.OnNext(e),
diff --git a/src/Avalonia.Interactivity/RoutedEvent.cs b/src/Avalonia.Interactivity/RoutedEvent.cs
index 55d9e61d87..164a86fab7 100644
--- a/src/Avalonia.Interactivity/RoutedEvent.cs
+++ b/src/Avalonia.Interactivity/RoutedEvent.cs
@@ -25,10 +25,14 @@ namespace Avalonia.Interactivity
Type eventArgsType,
Type ownerType)
{
- Contract.Requires(name != null);
- Contract.Requires(eventArgsType != null);
- Contract.Requires(ownerType != null);
- Contract.Requires(typeof(RoutedEventArgs).IsAssignableFrom(eventArgsType));
+ name = name ?? throw new ArgumentNullException(nameof(name));
+ eventArgsType = eventArgsType ?? throw new ArgumentNullException(nameof(name));
+ ownerType = ownerType ?? throw new ArgumentNullException(nameof(name));
+
+ if (!typeof(RoutedEventArgs).IsAssignableFrom(eventArgsType))
+ {
+ throw new InvalidCastException("eventArgsType must be derived from RoutedEventArgs.");
+ }
EventArgsType = eventArgsType;
Name = name;
@@ -52,7 +56,7 @@ namespace Avalonia.Interactivity
RoutingStrategies routingStrategy)
where TEventArgs : RoutedEventArgs
{
- Contract.Requires(name != null);
+ name = name ?? throw new ArgumentNullException(nameof(name));
var routedEvent = new RoutedEvent(name, routingStrategy, typeof(TOwner));
RoutedEventRegistry.Instance.Register(typeof(TOwner), routedEvent);
@@ -65,7 +69,7 @@ namespace Avalonia.Interactivity
Type ownerType)
where TEventArgs : RoutedEventArgs
{
- Contract.Requires(name != null);
+ name = name ?? throw new ArgumentNullException(nameof(name));
var routedEvent = new RoutedEvent(name, routingStrategy, ownerType);
RoutedEventRegistry.Instance.Register(ownerType, routedEvent);
@@ -108,8 +112,6 @@ namespace Avalonia.Interactivity
public RoutedEvent(string name, RoutingStrategies routingStrategies, Type ownerType)
: base(name, routingStrategies, typeof(TEventArgs), ownerType)
{
- Contract.Requires(name != null);
- Contract.Requires(ownerType != null);
}
[Obsolete("Use overload taking Action.")]
diff --git a/src/Avalonia.Interactivity/RoutedEventArgs.cs b/src/Avalonia.Interactivity/RoutedEventArgs.cs
index 05bbf7b6a3..e00393322d 100644
--- a/src/Avalonia.Interactivity/RoutedEventArgs.cs
+++ b/src/Avalonia.Interactivity/RoutedEventArgs.cs
@@ -11,12 +11,12 @@ namespace Avalonia.Interactivity
{
}
- public RoutedEventArgs(RoutedEvent routedEvent)
+ public RoutedEventArgs(RoutedEvent? routedEvent)
{
RoutedEvent = routedEvent;
}
- public RoutedEventArgs(RoutedEvent routedEvent, IInteractive source)
+ public RoutedEventArgs(RoutedEvent? routedEvent, IInteractive? source)
{
RoutedEvent = routedEvent;
Source = source;
@@ -24,10 +24,10 @@ namespace Avalonia.Interactivity
public bool Handled { get; set; }
- public RoutedEvent RoutedEvent { get; set; }
+ public RoutedEvent? RoutedEvent { get; set; }
public RoutingStrategies Route { get; set; }
- public IInteractive Source { get; set; }
+ public IInteractive? Source { get; set; }
}
}
diff --git a/src/Avalonia.Interactivity/RoutedEventRegistry.cs b/src/Avalonia.Interactivity/RoutedEventRegistry.cs
index 34c970a806..0111b115e6 100644
--- a/src/Avalonia.Interactivity/RoutedEventRegistry.cs
+++ b/src/Avalonia.Interactivity/RoutedEventRegistry.cs
@@ -32,8 +32,8 @@ namespace Avalonia.Interactivity
///
public void Register(Type type, RoutedEvent @event)
{
- Contract.Requires(type != null);
- Contract.Requires(@event != null);
+ type = type ?? throw new ArgumentNullException(nameof(type));
+ @event = @event ?? throw new ArgumentNullException(nameof(@event));
if (!_registeredRoutedEvents.TryGetValue(type, out var list))
{
@@ -66,7 +66,7 @@ namespace Avalonia.Interactivity
/// All routed events registered with the provided type.
public IReadOnlyList GetRegistered(Type type)
{
- Contract.Requires(type != null);
+ type = type ?? throw new ArgumentNullException(nameof(type));
if (_registeredRoutedEvents.TryGetValue(type, out var events))
{