Browse Source

Merge pull request #906 from AvaloniaUI/issue/905-event-getobservable

Added GetObservable for routed events.
Steven Kirk 8 years ago
parent
commit
b953d3f9ed

+ 28 - 2
src/Avalonia.Interactivity/InteractiveExtensions.cs

@@ -1,8 +1,10 @@
 // Copyright (c) The Avalonia Project. All rights reserved.
 // 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
 {
@@ -11,12 +13,36 @@ namespace Avalonia.Interactivity
     /// </summary>
     public static class InteractiveExtensions
     {
+        /// <summary>
+        /// Gets an observable for a <see cref="RoutedEvent{TEventArgs}"/>.
+        /// </summary>
+        /// <param name="o">The object to listen for events on.</param>
+        /// <param name="routedEvent">The routed event.</param>
+        /// <param name="routes">The routing strategies to listen to.</param>
+        /// <param name="handledEventsToo">Whether handled events should also be listened for.</param>
+        /// <returns>
+        /// An observable which fires each time the event is raised.
+        /// </returns>
+        public static IObservable<TEventArgs> GetObservable<TEventArgs>(
+            this IInteractive o,
+            RoutedEvent<TEventArgs> routedEvent,
+            RoutingStrategies routes = RoutingStrategies.Direct | RoutingStrategies.Bubble,
+            bool handledEventsToo = false)
+                where TEventArgs : RoutedEventArgs
+        {
+            return Observable.Create<TEventArgs>(x => o.AddHandler(
+                routedEvent, 
+                (_, e) => x.OnNext(e), 
+                routes,
+                handledEventsToo));
+        }
+
         /// <summary>
         /// Gets the route for bubbling events from the specified interactive.
         /// </summary>
         /// <param name="interactive">The interactive.</param>
         /// <returns>The event route.</returns>
-        public static IEnumerable<IInteractive> GetBubbleEventRoute(this IInteractive interactive)
+        internal static IEnumerable<IInteractive> GetBubbleEventRoute(this IInteractive interactive)
         {
             while (interactive != null)
             {
@@ -30,7 +56,7 @@ namespace Avalonia.Interactivity
         /// </summary>
         /// <param name="interactive">The interactive.</param>
         /// <returns>The event route.</returns>
-        public static IEnumerable<IInteractive> GetTunnelEventRoute(this IInteractive interactive)
+        internal static IEnumerable<IInteractive> GetTunnelEventRoute(this IInteractive interactive)
         {
             return interactive.GetBubbleEventRoute().Reverse();
         }

+ 21 - 0
tests/Avalonia.Interactivity.UnitTests/Avalonia.Interactivity.UnitTests.csproj

@@ -37,11 +37,32 @@
   <ItemGroup>
     <Reference Include="System" />
     <Reference Include="System.Core" />
+    <Reference Include="System.Reactive.Core, Version=3.0.0.0, Culture=neutral, PublicKeyToken=94bc3704cddfc263, processorArchitecture=MSIL">
+      <HintPath>..\..\packages\System.Reactive.Core.3.0.0\lib\net45\System.Reactive.Core.dll</HintPath>
+      <Private>True</Private>
+    </Reference>
+    <Reference Include="System.Reactive.Interfaces, Version=3.0.0.0, Culture=neutral, PublicKeyToken=94bc3704cddfc263, processorArchitecture=MSIL">
+      <HintPath>..\..\packages\System.Reactive.Interfaces.3.0.0\lib\net45\System.Reactive.Interfaces.dll</HintPath>
+      <Private>True</Private>
+    </Reference>
+    <Reference Include="System.Reactive.Linq, Version=3.0.0.0, Culture=neutral, PublicKeyToken=94bc3704cddfc263, processorArchitecture=MSIL">
+      <HintPath>..\..\packages\System.Reactive.Linq.3.0.0\lib\net45\System.Reactive.Linq.dll</HintPath>
+      <Private>True</Private>
+    </Reference>
+    <Reference Include="System.Reactive.PlatformServices, Version=3.0.0.0, Culture=neutral, PublicKeyToken=94bc3704cddfc263, processorArchitecture=MSIL">
+      <HintPath>..\..\packages\System.Reactive.PlatformServices.3.0.0\lib\net45\System.Reactive.PlatformServices.dll</HintPath>
+      <Private>True</Private>
+    </Reference>
+    <Reference Include="System.Reactive.Windows.Threading, Version=3.0.0.0, Culture=neutral, PublicKeyToken=94bc3704cddfc263, processorArchitecture=MSIL">
+      <HintPath>..\..\packages\System.Reactive.Windows.Threading.3.0.0\lib\net45\System.Reactive.Windows.Threading.dll</HintPath>
+      <Private>True</Private>
+    </Reference>
     <Reference Include="System.Xml.Linq" />
     <Reference Include="System.Data.DataSetExtensions" />
     <Reference Include="Microsoft.CSharp" />
     <Reference Include="System.Data" />
     <Reference Include="System.Xml" />
+    <Reference Include="WindowsBase" />
     <Reference Include="xunit.abstractions, Version=2.0.0.0, Culture=neutral, PublicKeyToken=8d05b1bb7a6fdb6c">
       <HintPath>..\..\packages\xunit.abstractions.2.0.0\lib\net35\xunit.abstractions.dll</HintPath>
     </Reference>

+ 18 - 0
tests/Avalonia.Interactivity.UnitTests/InteractiveTests.cs

@@ -340,6 +340,24 @@ namespace Avalonia.Interactivity.UnitTests
             Assert.True(target.GetVisualParent<TestInteractive>().ClassHandlerInvoked);
         }
 
+        [Fact]
+        public void GetObservable_Should_Listen_To_Event()
+        {
+            var ev = new RoutedEvent<RoutedEventArgs>("test", RoutingStrategies.Direct, typeof(TestInteractive));
+            var target = new TestInteractive();
+            var called = 0;
+            var subscription = target.GetObservable(ev).Subscribe(_ => ++called);
+
+            var args = new RoutedEventArgs(ev, target);
+            target.RaiseEvent(args);
+
+            subscription.Dispose();
+
+            target.RaiseEvent(args);
+
+            Assert.Equal(1, called);
+        }
+
         private TestInteractive CreateTree(
             RoutedEvent ev,
             EventHandler<RoutedEventArgs> handler,

+ 6 - 0
tests/Avalonia.Interactivity.UnitTests/packages.config

@@ -1,5 +1,11 @@
 <?xml version="1.0" encoding="utf-8"?>
 <packages>
+  <package id="System.Reactive" version="3.0.0" targetFramework="net45" />
+  <package id="System.Reactive.Core" version="3.0.0" targetFramework="net45" />
+  <package id="System.Reactive.Interfaces" version="3.0.0" targetFramework="net45" />
+  <package id="System.Reactive.Linq" version="3.0.0" targetFramework="net45" />
+  <package id="System.Reactive.PlatformServices" version="3.0.0" targetFramework="net45" />
+  <package id="System.Reactive.Windows.Threading" version="3.0.0" targetFramework="net45" />
   <package id="xunit" version="2.1.0" targetFramework="net45" />
   <package id="xunit.abstractions" version="2.0.0" targetFramework="net45" />
   <package id="xunit.assert" version="2.1.0" targetFramework="net45" />