【问题标题】:Unable to find the correct Dispatcher to prevent the "This type of CollectionView does not support changes to from a thread..." Exception无法找到正确的 Dispatcher 以防止“此类 CollectionView 不支持从线程更改...”异常
【发布时间】: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


【解决方案1】:

问题在于以下调用:

model.Collection.Add("Second item.")
model.StartAddingItems()

这似乎阻止了对用户界面的更新。

我将这些调用移至 WPF.Form 的 window.Loaded 事件(表单包含对视图模型的引用),并将视图模型的 Dispatcher 设置为那里的窗口。

【讨论】:

    【解决方案2】:

    如果要显示 WPF 窗口,则确实需要一个单独的 WPF 线程(带有 STA 主循环):

    var thread = new Thread(() =>
    {
      var application = new Application();
      application.Run();
    });
    thread.SetApartmentState(ApartmentState.STA);
    thread.Start();
    

    【讨论】:

    • 是的,我读到过,但是实现这个,代码仍然被阻塞。
    猜你喜欢
    • 1970-01-01
    • 2022-01-01
    • 2021-08-21
    • 2016-03-11
    • 2019-06-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多