別スレッドで編集されたコレクションをBindする

2021-03-14

別スレッドでアイテム追加等を行ったコレクションをBindすると、
「System.NotSupportedException: 'この型の CollectionView は、Dispatcher スレッドとは異なるスレッドからその SourceCollection への変更をサポートしません。’」
というエラーが出る。
CollectionSynchronization にて、参加指定する必要がある。

MainWindow.xaml

<Window x:Class="WpfApp18.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApp18"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">

    <ListView ItemsSource="{Binding arrayString}" />

</Window>

MainWindow.xaml.cs

using System;
using System.Collections.ObjectModel;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Data;
using System.Windows.Threading;

namespace WpfApp18
{
    /// <summary>
    /// MainWindow.xaml の相互作用ロジック
    /// </summary>
    public partial class MainWindow : Window
    {
        public ObservableCollection<string> arrayString { get; set; } = new ObservableCollection<string>();

        public MainWindow()
        {
            InitializeComponent();

            this.DataContext = this;

            // 複数スレッドで使用されるコレクションへの参加
            BindingOperations.EnableCollectionSynchronization(arrayString, new object());

            DispatcherTimer objTimer = new DispatcherTimer()
            {
                Interval = new TimeSpan(0, 0, 1)
            };

            objTimer.Tick += async (object sender, EventArgs e)=>
            {
                await Task.Run(() =>
                {
                    // 別スレッドでコレクションにアイテムを追加
                    arrayString.Insert(0, DateTime.Now.ToString());
                });
            };

            objTimer.Start();
        }
    }
}