Skip to content

Commit

Permalink
fix #435
Browse files Browse the repository at this point in the history
  • Loading branch information
JaggerJo committed Sep 5, 2024
1 parent db90664 commit 78e8f28
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@

<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.10.0" />
<PackageReference Include="System.Reactive" Version="6.0.1" />
<PackageReference Include="xunit" Version="2.9.0" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.2">
<PrivateAssets>all</PrivateAssets>
Expand Down
24 changes: 22 additions & 2 deletions src/Avalonia.FuncUI.UnitTests/LibTests.fs
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
namespace Avalonia.FuncUI.UnitTests

open System.Reactive.Subjects
open Avalonia.FuncUI.Library
open Xunit

module Library =

[<Fact>]
let ``function equality`` () =

let view () =
let add = fun (count: int) -> count + 1
let sub = fun (count: int) -> count - 1
Expand All @@ -19,4 +20,23 @@ module Library =
Assert.Equal(add'.GetType(), add''.GetType())
Assert.Equal(sub'.GetType(), sub''.GetType())
Assert.NotEqual(add'.GetType(), sub'.GetType())
Assert.NotEqual(add''.GetType(), sub''.GetType())
Assert.NotEqual(add''.GetType(), sub''.GetType())


[<Fact>]
let ``IObservable<T>.SkipFirst`` () =
let observable = new Subject<int>()
let seenItems = ResizeArray<int>()

let _ =
observable
.SkipFirst()
.Subscribe(fun n -> seenItems.Add(n))

observable.OnNext(1)
observable.OnNext(2)
observable.OnNext(3)

Assert.Equal(2, seenItems.Count)
Assert.Equal(2, seenItems.[0])
Assert.Equal(3, seenItems.[1])
4 changes: 4 additions & 0 deletions src/Avalonia.FuncUI/DSL/AttrBuilder.fs
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,8 @@ type AttrBuilder<'view>() =
let cts = new CancellationTokenSource()
control
.GetObservable(property)
// GetObservable immediately emits the current value. We're not interested in that, so we skip the first value.
.SkipFirst()
.Subscribe(func, cts.Token)
cts

Expand All @@ -261,6 +263,8 @@ type AttrBuilder<'view>() =
let cts = new CancellationTokenSource()
control
.GetObservable(property)
// GetObservable immediately emits the current value. We're not interested in that, so we skip the first value.
.SkipFirst()
.Subscribe(func, cts.Token)
cts

Expand Down
27 changes: 25 additions & 2 deletions src/Avalonia.FuncUI/Library.fs
Original file line number Diff line number Diff line change
Expand Up @@ -37,17 +37,40 @@ module internal Extensions =
let disposable = Observable.subscribe callback this
token.Register(fun () -> disposable.Dispose()) |> ignore

member this.SkipFirst() =
{ new IObservable<'a> with
member __.Subscribe(observer: IObserver<'a>) =
let skipFirstObserver =
let mutable isFirst = true

{ new IObserver<'a> with
member __.OnNext(value) =
if isFirst then
isFirst <- false
else
observer.OnNext(value)

member __.OnError(error) =
observer.OnError(error)

member __.OnCompleted() =
observer.OnCompleted()
}

this.Subscribe(skipFirstObserver)
}

type Interactive with
member this.GetObservable<'args when 'args :> RoutedEventArgs>(routedEvent: RoutedEvent<'args>) : IObservable<'args> =
let sub = Func<IObserver<'args>, IDisposable>(fun observer ->
// push new update to subscribers
let handler = EventHandler<'args>(fun _ e ->
observer.OnNext e
)

// subscribe to event changes so they can be pushed to subscribers
this.AddDisposableHandler(routedEvent, handler, routedEvent.RoutingStrategies)
)

{ new IObservable<'args>
with member this.Subscribe(observer: IObserver<'args>) = sub.Invoke(observer) }

0 comments on commit 78e8f28

Please sign in to comment.