1

是否有一种将项目添加到 ReactiveAsyncCommand 中的 ObservableCollection 的方法,或者我是否必须使用 Dispather?处理这种情况的 RxUI 方式是什么?

编辑:在 LoadData 运行时,应将项目一一加载到集合中。

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        MaxRows = 100;
        Translations = new ReactiveCollection<string>();

        LoadDataCommand = new ReactiveAsyncCommand();

        LoadDataCommand.RegisterAsyncAction(_ => LoadData());

        InitializeComponent();

        this.DataContext = this;
    }

    private void LoadData()
    {
        for (int i = 1; i < MaxRows; ++i)
        {
            Thread.Sleep(100);
            // What's the RxUI Way for this?
            this.Dispatcher.Invoke(() => Translations.Add(i.ToString()));
        }
    }

    public int MaxRows { get; set; }
    public ReactiveCollection<string> Translations { get; set; }
    public ReactiveAsyncCommand LoadDataCommand { get; set; }
}
4

1 回答 1

2

试一试:

public MainWindow()
{
    InitializeComponent();
    MaxRows = 100;
    Translations = new ReactiveCollection<string>();

    LoadDataCommand = new ReactiveAsyncCommand();

    LoadDataCommand.RegisterAsyncFunction(_ => LoadData())
        .Subscribe(items => 
        {
            foreach(var i in items) Translations.Add(i);
        })

    LoadDataCommand.ThrownExceptions.Subscribe(ex => 
    {
        Console.WriteLine("Oh crap: {0}", ex);
    })

    InitializeComponent();

    this.DataContext = this;
}

private List<int> LoadData()
{
    // TODO: Return the list of stuff you want to add
    return Enumerable.Range(0, maxRows).ToList();
}

这个想法是,LoadData 将在后台线程上被调用,你可以在那里做任何你想做的事情,阻止网络调用,读取文件等。但是,RegisterAsync* 的订阅保证在 UI 线程上运行。方便的!

请注意,我还添加了一个 ThrownExceptions 订阅 - 这很重要,否则如果 LoadData 失败,您的 RegisterAsync* 调用将停止工作。

编辑:好的,现在你有点花哨了。虽然我在讨论这样的结果流式 UI 的实用性(尝试在不断移动的 ListBox 中选择内容令人沮丧),但无论如何,让我们这样做 - 首先,更改LoadData为流式传输结果:

private IObservable<int> LoadData()
{
    var ret = new Subject<int>();

    // Run something in the background
    Observable.Start(() => 
    {
        try 
        {
            for(int i=0; i < 100; i++) 
            {
                // TODO: Replace with streaming items
                ret.OnNext(10);
                Thread.Sleep(100);
            }

            ret.OnCompleted();
        }
        catch (Exception ex) 
        {
            ret.OnError(ex);
        }
    }, RxApp.TaskpoolScheduler)

    return ret;
}

然后,您所做的就是更改命令中的几行:

// Now it's RegisterAsyncObservable instead
LoadDataCommand.RegisterAsyncObservable(_ => LoadData())
    .Subscribe(item => 
    {
        Translations.Add(item);
    })

请注意,这不是非常实用的™,但我想为您提供一些易于理解的内容。

于 2013-06-18T00:29:04.333 回答