Question

In ReactiveUI 5.2.0 and F# 3.1, the following F# code causes an InvalidOperationException when constructing the object (from a C# WPF app)

The message is "The initialization of an object or value resulted in an object or value being accessed recursively before it was fully initialized" and it occurs during a read of the property passed into ObservableForProperty (although the default is to skip the initial value).

type MyVM() as this =
inherit ReactiveObject()

let source : obj = obj()

let ofp =            
    this.ObservableForProperty([|"Source"|])
         .Select(fun x -> x.Value)
        .ToProperty(this, (fun y -> y.Result), obj()) // Exception when executing this

member this.Result with get() = ofp.Value
member this.Source with get() = source // Exception here "The initialization of an object or value resulted in an object or value being accessed recursively before it was fully initialized"

Edited to add: The problem seems to be that the ToProperty is causing ObservableForProperty to query the "Source" property on subscribe, and F# has checks that the constructor has completed before properties are queried.

More info: In ReactiveNotifyPropertyChangedMixin.nestedObservedChanges, the combination of kicker and fillInValue cause the value to be queried before any change is notified via PropertyChanged

Was it helpful?

Solution

From ReactiveUI version 5.4.0, there's a new overload to ObservableForProperty that takes a simple non-chained property to monitor.

If you add to that the following extension method:

let toPropName(query : Expr) = 
    match query with
        | PropertyGet(a, b, list) -> b.Name
        | _ -> ""

[<Extension>]
type ReactiveObjectExtender =
    [<Extension>]
    static member ObservableForProperty<'u, 't when 'u :> ReactiveObject>(this: 'u, expr : Expr<'t>, ?beforeChange, ?skipInitial) =
        let propertyName = toPropName expr
        this.ObservableForProperty<'u, 't>(propertyName, defaultArg beforeChange false, defaultArg skipInitial true)

Then you can observe property changes using the syntax:

this.ObservableForProperty(<@ this.MyProperty @>)

OTHER TIPS

Hm, while I'm no F# expert, you might have to eschew ToProperty (it's actually just a helper anyways) and use a read/write property (i.e. one constructed via RaiseAndSetIfChanged) and a simple Subscribe + property assignment. So Mutable and Gross!

ReactiveUI really likes to initialize properties in the constructor, because it sets up the initial state of the app (if you use ObservableForProperty, you'll find that you have to use the .StartWith operator all the time or else things won't work until the first time they're changed)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top