У меня есть массив выборочной информации, которая постоянно обновляется в фоновом потоке.

В настоящее время я постоянно назначаю этот массив свойству ItemsSource сетки данных, используя DispatcherTimer. Это работает, но сбрасывает любые визуальные местоположения, например, если пользователь поместит свой курсор в середину сетки данных, таймер выполнения отменит эту позицию.

Можно ли вместо этого использовать событие INotifyPropertyChanged или INotifyCollectionChanged, чтобы предотвратить возникновение таких ситуаций? Если да, то как это работает с F#?

Я полагаю, что мне нужно выполнять некоторую функцию, уведомляющую сетку данных каждый раз, когда происходит обновление массива. Обновление массива не в разделе STAThread.

Я использую VS2010 с последним набором инструментов WPF, содержащим сетку данных WPF.

3
Cay 18 Июл 2009 в 20:00

2 ответа

Вы можете использовать ObservableCollection, который реализует INotifyCollectionChanged для вас. F# выглядит примерно так:

open System
open System.Collections.ObjectModel
open System.Windows
open System.Windows.Controls
open System.Windows.Threading

[<EntryPoint; STAThread>]
let Main args =

    let data    = ObservableCollection [0 .. 9]
    let list    = ListBox(ItemsSource = data)    
    let win     = Window(Content = list, Visibility = Visibility.Visible)    
    let rnd     = Random()

    let callback = 
        EventHandler(fun sender args -> 
            let idx = rnd.Next(0, 10)
            data.[idx] <- rnd.Next(0, 10) 
            )

    let ts  = TimeSpan(1000000L)
    let dp  = DispatcherPriority.Send
    let cd  = Dispatcher.CurrentDispatcher   

    let timer   = DispatcherTimer(ts, dp, callback, cd) in timer.Start()    
    let app     = Application() in app.Run(win)

К сожалению, Reflector показывает, что метод System.Windows.Controls.ItemsControl.OnItemCollectionChanged удаляет выделение при его вызове, поэтому вам может потребоваться обойти это поведение по умолчанию.

Вы также можете реализовать INotifyPropertyChanged следующим образом:

open System.ComponentModel

type MyObservable() =

    let mutable propval = 0.0
    let evt             = Event<_,_>()   

    interface INotifyPropertyChanged with

        [<CLIEvent>]
        member this.PropertyChanged = evt.Publish

    member this.MyProperty

        with get()  = propval
        and  set(v) = propval <- v
                      evt.Trigger(this, PropertyChangedEventArgs("MyProperty"))

Реализация INotifyCollectionChanged будет работать аналогично.

Удачи,

Дэнни

2
3 revs 19 Июл 2009 в 03:39

ObservableCollection работает, но, к сожалению, с проблемами.

Поскольку ObservableColection работает только при изменении в STAThread, мне приходится использовать диспетчер и в основном переписывать или, по крайней мере, проверять весь массив, поскольку я не могу сказать, какие записи изменены или нет.

Одной из возможных возможностей является использование почтового ящика F#. Фоновый поток может размещать сообщения об изменениях, которые могут быть получены диспетчером в STAThread. Это решение также устранит необходимость синхронизации.

Это похоже на излишество? Кто-нибудь делал это раньше? Любые альтернативные решения?

1
Moonlight 19 Июл 2009 в 19:15