System.NotSupportedException 在 System.Reactive.dll
System.NotSupportedException in System.Reactive.dll
我是 Rx.Net 和动态数据的新手,目前使用这些响应式 UI 扩展程序时遇到以下问题。
我努力实现的目标:
- 在
TaskpoolScheduler
上应用 Dynamic 的数据 Filter
操作(或通常异步过滤传入数据)
- 从后台线程向
SourceList
添加数据
但是,当 SourceList
被来自不同任务的数据填充时,我收到 'System.NotSupportedException' in System.Reactive.dll
错误。所以我必须使用 Dispatcher Thread。
如何解决这个问题?
一个最小的工作示例:
using DynamicData;
using ReactiveUI;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Reactive.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace ReactiveExtensionsTest
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private readonly ReadOnlyObservableCollection<DataModel> _items;
public ReadOnlyObservableCollection<DataModel> Items => _items;
public MainWindow()
{
InitializeComponent();
DataContext = this;
var bgDataService = new BackroundDataService();
bgDataService
.Connect()
.ObserveOn(RxApp.TaskpoolScheduler)
.Filter(x => x.IntA % 2 == 0)
.ObserveOn(RxApp.MainThreadScheduler)
.Bind(out _items)
.Subscribe();
}
}
class BackroundDataService : IBackgroundDataService
{
private readonly SourceList<DataModel> _data = new SourceList<DataModel>();
public IObservable<IChangeSet<DataModel>> Connect() => _data.Connect();
public BackroundDataService()
{
Task.Factory.StartNew(async () =>
{
int length = 100_000;
for (int i = 0; i < length; i++)
{
_data.Add(new DataModel { IntA = i, StringB = "B {i}" });
await Task.Delay(200);
}
});
}
}
internal interface IBackgroundDataService
{
IObservable<IChangeSet<DataModel>> Connect();
}
public class DataModel
{
public int IntA { get; set; }
public string StringB { get; set; }
}
}
Items
属性 绑定到 ListBox
如下 <ListBox ItemsSource="{Binding Items}"/>
你试过了吗
var bgDataService = new BackroundDataService();
bgDataService
.Connect()
.ObserveOn(RxApp.TaskpoolScheduler)
.Filter(x => x.IntA % 2 == 0)
.Bind(out _items)
.SubscribeOn(RxApp.MainThreadScheduler);
可能值得一试。
另一种可能的解决方案如下:
var bgDataService = new BackroundDataService();
bgDataService
.Connect()
.ObserveOn(RxApp.TaskpoolScheduler)
.Filter(x =>
{
Thread currentThread = Thread.CurrentThread;
Console.WriteLine($"Applied filter on thread: {currentThread.GetApartmentState()} with Id: "
+ $"{currentThread.ManagedThreadId} and is background: {currentThread.IsBackground} and from thread pool: {currentThread.IsThreadPoolThread}");
return x.IntA % 2 == 0;
})
.ObserveOnDispatcher()
.Bind(out _items)
.Subscribe(x =>
{
Thread currentThread = Thread.CurrentThread;
Console.WriteLine($"Subscribption runs on thread: {currentThread.GetApartmentState()} with Id: "
+ $"{currentThread.ManagedThreadId} and is background: {currentThread.IsBackground} and from thread pool: {currentThread.IsThreadPoolThread}");
});
我是 Rx.Net 和动态数据的新手,目前使用这些响应式 UI 扩展程序时遇到以下问题。
我努力实现的目标:
- 在
TaskpoolScheduler
上应用 Dynamic 的数据Filter
操作(或通常异步过滤传入数据) - 从后台线程向
SourceList
添加数据
但是,当 SourceList
被来自不同任务的数据填充时,我收到 'System.NotSupportedException' in System.Reactive.dll
错误。所以我必须使用 Dispatcher Thread。
如何解决这个问题?
一个最小的工作示例:
using DynamicData;
using ReactiveUI;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Reactive.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace ReactiveExtensionsTest
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private readonly ReadOnlyObservableCollection<DataModel> _items;
public ReadOnlyObservableCollection<DataModel> Items => _items;
public MainWindow()
{
InitializeComponent();
DataContext = this;
var bgDataService = new BackroundDataService();
bgDataService
.Connect()
.ObserveOn(RxApp.TaskpoolScheduler)
.Filter(x => x.IntA % 2 == 0)
.ObserveOn(RxApp.MainThreadScheduler)
.Bind(out _items)
.Subscribe();
}
}
class BackroundDataService : IBackgroundDataService
{
private readonly SourceList<DataModel> _data = new SourceList<DataModel>();
public IObservable<IChangeSet<DataModel>> Connect() => _data.Connect();
public BackroundDataService()
{
Task.Factory.StartNew(async () =>
{
int length = 100_000;
for (int i = 0; i < length; i++)
{
_data.Add(new DataModel { IntA = i, StringB = "B {i}" });
await Task.Delay(200);
}
});
}
}
internal interface IBackgroundDataService
{
IObservable<IChangeSet<DataModel>> Connect();
}
public class DataModel
{
public int IntA { get; set; }
public string StringB { get; set; }
}
}
Items
属性 绑定到 ListBox
如下 <ListBox ItemsSource="{Binding Items}"/>
你试过了吗
var bgDataService = new BackroundDataService();
bgDataService
.Connect()
.ObserveOn(RxApp.TaskpoolScheduler)
.Filter(x => x.IntA % 2 == 0)
.Bind(out _items)
.SubscribeOn(RxApp.MainThreadScheduler);
可能值得一试。
另一种可能的解决方案如下:
var bgDataService = new BackroundDataService();
bgDataService
.Connect()
.ObserveOn(RxApp.TaskpoolScheduler)
.Filter(x =>
{
Thread currentThread = Thread.CurrentThread;
Console.WriteLine($"Applied filter on thread: {currentThread.GetApartmentState()} with Id: "
+ $"{currentThread.ManagedThreadId} and is background: {currentThread.IsBackground} and from thread pool: {currentThread.IsThreadPoolThread}");
return x.IntA % 2 == 0;
})
.ObserveOnDispatcher()
.Bind(out _items)
.Subscribe(x =>
{
Thread currentThread = Thread.CurrentThread;
Console.WriteLine($"Subscribption runs on thread: {currentThread.GetApartmentState()} with Id: "
+ $"{currentThread.ManagedThreadId} and is background: {currentThread.IsBackground} and from thread pool: {currentThread.IsThreadPoolThread}");
});