tags:

views:

53

answers:

2

After a hiatus from my Silverlight / F# application, i am starting back into it and am running into an issue I cannot seem to get my head around. I have a member variable of my usercontrol that is a list ref, on button clicks I want to add records to it - but it never updates. I am pretty sure it has to do with being a member but I havent figured it out.

Thanks in advance to those who take the time to view and reply.

the problem lines:

.
.
.
member this.brokers = ref List.empty
.
.
.
// this line doesn't seem to work
this.brokers := candidate :: (!this.brokers)
.
.
.

the class:

type Page() as this =    
    inherit UriUserControl("/xyz;component/page.xaml", "page")
    do
        this.firm.ItemsSource <- RpcXYZ.getFirms()
        this.email.Background <- SolidColorBrush(Colors.Red)
        this.addBtn.IsEnabled <- false
        ()

    // instance data
    member this.brokers = ref List.empty

    // bound controls for add candidate
    member this.FE : FrameworkElement = (this.Content :?> FrameworkElement)
    member this.fname : TextBox = this.FE ? fname
    member this.lname : TextBox = this.FE ? lname
    member this.email : TextBox = this.FE ? email
    member this.firm : RadComboBox = this.FE ? firms
    member this.addBtn : RadButton = this.FE ? addBtn

    member this.addCadidate_Click (sender : obj) (args : RoutedEventArgs)  = 
        let inline findFirm (f : RpcXYZ.firm) =
            f.id = Int32.Parse(this.firm.SelectedValue.ToString())

        let candidate : SalesRep = {
            id = -1 ; 
            fname =  this.fname.Text ;
            lname = this.lname.Text ;
            email = this.email.Text ;
            phone = "" ;
            firm = List.find findFirm <| RpcXYZ.getFirms();
            score = None ;
        }

        // this line is fine t is a list of 1 item after 1 click
        let t = candidate :: (!this.brokers)

        // this line doesn't seem to work
        this.brokers := candidate :: (!this.brokers)

        ChildWindow().Show()  |> ignore ;

    member this.email_Changed (o : obj) (arg : TextChangedEventArgs) = 
        let txtBox = (o :?> TextBox)
        let emailRegex = Regex("(\w[-._\w]*\w@\w[-._\w]*\w\.\w{2,3})")
        if emailRegex.IsMatch(txtBox.Text) = false then
            txtBox.Background <- SolidColorBrush(Colors.Red)
            this.addBtn.IsEnabled <- false
        else
            txtBox.Background <- new SolidColorBrush(Colors.White)
            this.addBtn.IsEnabled <- true
+3  A: 

This

member this.brokers = ref List.Empty

defines a property getter. Every time you touch .brokers, it re-runs the code on the right hand side. That's the issue.

The fix would be to define an instance variable, and return that:

let brokers = ref List.Empty
member this.Brokers = brokers

Then a single ref is allocated when an instance of the class is constructed, and you keep accessing that same ref object via the member property.

Brian
Well hats not what I want! Already made the change, thank you
akaphenom
+3  A: 

Brian already explained the problem. However, is there any reason why you're not using a mutable member (with getter and setter) and instead use a readonly member that returns a reference cell?

Using a get/set member would be more idiomatic solution:

let mutable brokers = List.Empty 

member this.Brokers 
  with get() = brokers
  and set(value) = brokers <- value

The declaration is a bit longer (unfortunately, there are no automatic properties in F#!), but the member will look like a standard property (from both F# and C#). You could then use it like this:

x.Brokers <- candidate :: x.Brokers

Although, you need the property only for public members that should be accessed from outside of the type. For private fields, you can just use the mutable value brokers directly...

Tomas Petricek
I really got overzealous with the member modifier. I dont actually need these to be public members, just private instances. Probably should be mutable instead of ref though.
akaphenom