【发布时间】:2014-08-09 19:37:23
【问题描述】:
在下面的代码中,我无法从异步调用中更新 WPF Window。所有显示的是“第一项”行。问题是 Window 不是从 WPF 应用程序启动的,而是从类模块启动的。由于我们的主 UI 应用程序是一个 VB6 应用程序,它通过调用 Com 可见的 Net dll 来启动 som WPF 元素。这很好用,但在下面的情况下却不行。
主控制台应用程序
Imports Window
Imports System.Windows
Imports System.Threading
Module Module1
Sub Main()
Dim launcher As New WindowLauncher
launcher.LaunchWindow()
Console.WriteLine("Press a key to continue...")
Console.ReadLine()
End Sub
End Module
WPF 窗口启动器
Imports Window
Public Class WindowLauncher
Public Sub LaunchWindow()
Dim model As New ViewModel
Dim window As New DisplayWindow
model.Dispatcher = window.Dispatcher
window.DataContext = model
window.Show()
model.Collection.Add("Second item.")
model.StartAddingItems()
'window.Close()
End Sub
End Class
WPF 用户控制库项目中的 WPF 窗口及其视图模型
<Window x:Class="DisplayWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="DisplayWindow" Height="300" Width="300">
<Grid>
<ListBox ItemsSource="{Binding Collection}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</Window>
Imports System.Collections.ObjectModel
Imports System.Threading
Imports System.Windows.Threading
Public Class ViewModel
Public Sub New()
Collection = New ObservableCollection(Of String)
Collection.Add("First item")
End Sub
Public Property Collection As ObservableCollection(Of String)
Public Property Dispatcher As Dispatcher
Public Sub StartAddingItems()
Dim progress As New Progress(Of String)
AddHandler progress.ProgressChanged, AddressOf ProgressChanged
For i = 1 To 10
DoSomething(progress).Wait()
Next
End Sub
Private _counter As Integer
Private Async Function DoSomething(progress As IProgress(Of String)) As Task
Await Task.Delay(10 * _counter)
_counter += 1
progress.Report(CStr(_counter))
End Function
Private Sub ProgressChanged(sender As Object, e As Object)
Dim text = CStr(e)
Me.Dispatcher.BeginInvoke(Sub() AddToCollection(text), DispatcherPriority.Background)
'The challenge seems to be to find the correct Dispatcher. Now the property is set from the WPF Window, but the code never reaches the AddToCollection method. `
AddToCollection(text)
`This call throws the well known "This type of CollectionView does not support changes..." exception.`
End Sub
Private Sub AddToCollection(text As String)
Collection.Add(String.Format("item {0}", text))
End Sub
End Class
【问题讨论】:
-
Dispatcher.BeginInvoke() 返回一个 DispatcherOperation 对象。你能检查一下它的 Status 和 Result 属性吗?另外,您是否尝试过使用另一个 DispatcherPriority,例如 DispatcherPriority.Send?
-
@Tanis83 问题是 Dispatcher.BeginInvoke 调用之后的一行永远不会到达。 ProgressChanged 方法被调用了十次,但代码永远不会通过调度程序调用。所以我无法检查它的返回类型。将优先级更改为发送不会改变此行为。
-
您说 ProgressChanged() 被调用了 10 次,但这意味着代码必须通过调度程序调用,因为您等待 for 循环中的每个任务完成。如果代码在 BeginInvoke() 处“停止”,您甚至永远不会进入循环的第二次迭代。我错过了什么?
-
@Tanis83 那时也许调试器正在欺骗我。当我在那里设置断点时,Dispatcher.Invoke 调用中的代码永远不会被命中。
标签: wpf multithreading asynchronous