INotifyPropertyChanged и INotifyCollectionChanged в F # с использованием WPF - PullRequest
3 голосов
/ 18 июля 2009

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

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

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

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

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

Ответы [ 2 ]

2 голосов
/ 19 июля 2009

Вы можете использовать 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 будет работать аналогично.

удачи,

Danny

1 голос
/ 19 июля 2009

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

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

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

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

...