F # Отображение окна WPF асинхронно - PullRequest
5 голосов
/ 14 января 2012

Эта проблема сводила меня с ума.Вот общая суть:

У меня есть два проекта в решении: первый - консольное приложение F #, а второй - библиотека C # с классом C # + XAML с именем DisplayWindow, унаследованным от окна WPF.У DisplayWindow есть метод public void SetMessage(string s) {...}, который заставляет окно отображать текст, переданный ему большими блестящими буквами, которые, вероятно, также будут мигать и вращаться вокруг, и делать все остальное, в чем хорош WPF.Из моей программы F # мне нужно сделать функцию let openAWindow text = ???, чтобы она открывала новый DisplayWindow асинхронно каждый раз, когда вызывается с текстом.Каков наилучший способ сделать это?Используя async {} или System.Threading.Thread?Спасибо за помощь:)

Редактировать: Я нашел этот пост в блоге http://deanchalk.com/2010/10/08/f-interacting-with-wpf-dispatcher-via-f-interactive-window/, который работает, но иногда может (?) Вызвать ArgumentException с текстом ошибки «Запись с таким же ключом уже существует."поэтому я понятия не имею, что там происходит: (

1 Ответ

8 голосов
/ 14 января 2012

Я сделал это для нашей библиотеки F # для визуализации , а затем описал метод, который использовал в своей книге Visual F # 2010 для технических вычислений .

Во-первых, янаписал ленивый thunk, который инициализирует WPF (включая поток пользовательского интерфейса STA и Application), когда его оценка принудительно:

> let ui =
    let mk() =
      let wh = new ManualResetEvent(false)
      let application = ref null
      let start() =
        let app = Application()
        application := app
        ignore(wh.Set())
        app.Run() |> ignore
    let thread = Thread start
    thread.IsBackground <- true
    thread.SetApartmentState ApartmentState.STA
    thread.Start()
    ignore(wh.WaitOne())
    !application, thread
  lazy(mk());;
val ui : Lazy<Application * Thread> = <unevaluated>

Затем я написал функцию spawn, которая отправляет приложение функции f к аргументу x, так что он запускается в потоке пользовательского интерфейса:

> let spawn : ('a -> 'b) -> 'a -> 'b =
    fun f x ->
      let app, thread = ui.Force()
      let f _ =
        try
          let f_x = f x
          fun () -> f_x
        with e ->
          fun () -> raise e
      let t = app.Dispatcher.Invoke(DispatcherPriority.Send, System.Func<_, _>(f), null)
      (t :?> unit -> 'b)();;
val spawn : ('a -> 'b) -> 'a -> 'b

Теперь это всего лишь случай вызова функции openAWindow в потоке пользовательского интерфейса с помощью:

let openAWindow text =
  DisplayWindow().SetMessage text

spawn openAWindow text
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...