Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>This is a very interesting problem :-). Sadly, I don't think there is any F# library that allows you to solve that easily. As far as I can tell, <a href="http://bindablelinq.codeplex.com/" rel="nofollow">Bindable LINQ</a> was one attempt to implement LINQ query pattern (i.e. <code>Select</code>, <code>SelectMany</code> and <code>Where</code> methods) for <code>ObservableCollection&lt;T&gt;</code>, which is essentially what you need. To use it from F#, you could wrap LINQ operations in functions like <code>map</code> etc.</p> <p>As you say, functions like <code>Seq.map</code> work by on <code>IEnumerable</code> and so they are not incremental. What you'd need here are functions like <code>map</code>, <code>filter</code> and <code>collect</code>, but implemented over <code>ObservableCollection&lt;'T&gt;</code> in such a way that they do the changes incrementally - when new element is added to the source collection, the <code>map</code> function would process it and add a new element to the resulting collection. </p> <p>I experimented with that a bit and here is an implementation of <code>map</code> that is incremental:</p> <pre class="lang-ml prettyprint-override"><code>open System.Collections.Specialized open System.Collections.ObjectModel module ObservableCollection = /// Initialize observable collection let init n f = ObservableCollection&lt;_&gt;(List.init n f) /// Incremental map for observable collections let map f (oc:ObservableCollection&lt;'T&gt;) = // Create a resulting collection based on current elements let res = ObservableCollection&lt;_&gt;(Seq.map f oc) // Watch for changes in the source collection oc.CollectionChanged.Add(fun change -&gt; printfn "%A" change.Action match change.Action with | NotifyCollectionChangedAction.Add -&gt; // Apply 'f' to all new elements and add them to the result change.NewItems |&gt; Seq.cast&lt;'T&gt; |&gt; Seq.iteri (fun index item -&gt; res.Insert(change.NewStartingIndex + index, f item)) | NotifyCollectionChangedAction.Move -&gt; // Move element in the resulting collection res.Move(change.OldStartingIndex, change.NewStartingIndex) | NotifyCollectionChangedAction.Remove -&gt; // Remove element in the result res.RemoveAt(change.OldStartingIndex) | NotifyCollectionChangedAction.Replace -&gt; // Replace element with a new one (processed using 'f') change.NewItems |&gt; Seq.cast&lt;'T&gt; |&gt; Seq.iteri (fun index item -&gt; res.[change.NewStartingIndex + index] &lt;- f item) | NotifyCollectionChangedAction.Reset -&gt; // Clear everything res.Clear() | _ -&gt; failwith "Unexpected action!" ) res </code></pre> <p>Implementing <code>map</code> was quite easy, but I'm afraid that functions like <code>collect</code> and <code>groupBy</code> will be quite tricky. Anyway, here is a sample showing how you can use it:</p> <pre class="lang-ml prettyprint-override"><code>let src = ObservableCollection.init 5 (fun n -&gt; n) let res = ObservableCollection.map (fun x -&gt; printfn "processing %d" x; x * 10) src src.Move(0, 1) src.Remove(0) src.Clear() src.Add(5) src.Insert(0, 3) src.[0] &lt;- 1 // Compare the original and the result printfn "%A" (Seq.zip src res |&gt; List.ofSeq) </code></pre>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload