我如何使用Rx迭代一系列字符串与暂停和淡出

本文关键字:暂停 淡出 字符串 一系列 何使用 Rx 迭代 | 更新日期: 2023-09-27 18:15:05

我的要求是从数组中取出一系列字符串,从第一个开始,5秒后移动到下一个,同时在Xamarin中使用Rx和XAML淡出下一个字符串。你可以假设这发生在一个视图模型上,它有一个'Message'属性和一个'MessageOpacity'属性,它接受文本和一个0到1之间的小数。你也可以假设我有一个后台调度程序和uisscheduler设置。

我对Rx相当陌生,这将变得明显,到目前为止,我已经做到了:

var messages = new[] { 
                       "Welcome", 
                       "We are settings things up for you", 
                       "This may take a little while first time" };
Observable.Interval(TimeSpan.FromSeconds(5), Scheduler.BackgroundScheduler)
                  .SelectMany((long arg) => messages)
                  .Buffer(1, 1)
                  .SubscribeOn(Scheduler.UiScheduler)
                  .Subscribe((obj) => 
        {
            Message = obj[0];
        });    

以上不起作用,因为缓冲区没有按我预期的方式工作。相反,它每5秒快速连续发射4个字符串,而不是逐个串。

我不明白的是如何以正确的"Rx"方式按顺序每"x秒"遍历每个字符串,以及(作为对我的奖励!)如何随后触发另一个可观察到的每个新消息在每次更改时从0到1的不透明度上升和下降。

目的是实现"windows 10"风格的屏幕,当一个大的更新发生或当用户正在等待一个长时间的操作完成

我如何使用Rx迭代一系列字符串与暂停和淡出

你可以将Zip操作符与Observable结合使用。给出所需迭代字符串输出的间隔:

[Fact]
public void ShouldIterateThroughStringsEveryFiveSeconds()
{
    TestScheduler scheduler = new TestScheduler();
    string[] messages = new[]
    {
                "Welcome",
                "We are settings things up for you",
                "This may take a little while first time"
    };
    var expected = new[]
    {
        ReactiveTest.OnNext(ReactiveTest.Subscribed + TimeSpan.FromSeconds(0).Ticks, "Welcome"),
        ReactiveTest.OnNext(ReactiveTest.Subscribed + TimeSpan.FromSeconds(5).Ticks, "We are settings things up for you"),
        ReactiveTest.OnNext(ReactiveTest.Subscribed + TimeSpan.FromSeconds(10).Ticks, "This may take a little while first time"),
        ReactiveTest.OnCompleted<string>(ReactiveTest.Subscribed + TimeSpan.FromSeconds(15).Ticks)
    };
    var actual = scheduler.Start(
        // Solution
        () => Observable.Zip(
            messages.ToObservable(),
            Observable.Interval(TimeSpan.FromSeconds(5), scheduler).StartWith(0),
            (text, time) => text),
        TimeSpan.FromSeconds(20).Ticks
    );
    Assert.Equal(expected, actual.Messages.ToArray());
}

编辑:与其为不透明度添加第二个可观察对象,不如这样组合它们:

[Fact]
public void ShouldIterateThroughStringsEveryFiveSecondsProvidingStringAndOpacity()
{
    TestScheduler scheduler = new TestScheduler();
    string[] messages = new[]
    {
                "Welcome",
                "We are settings things up for you",
                "This may take a little while first time"
    };
    var expected = new[]
    {
        ReactiveTest.OnNext(ReactiveTest.Subscribed + TimeSpan.FromSeconds(0).Ticks, Tuple.Create("Welcome", 0.0)),
        ReactiveTest.OnNext(ReactiveTest.Subscribed + TimeSpan.FromSeconds(5).Ticks, Tuple.Create("We are settings things up for you", 0.5)),
        ReactiveTest.OnNext(ReactiveTest.Subscribed + TimeSpan.FromSeconds(10).Ticks, Tuple.Create("This may take a little while first time", 1.0)),
        ReactiveTest.OnCompleted<Tuple<string, double>>(ReactiveTest.Subscribed + TimeSpan.FromSeconds(15).Ticks)
    };
    var actual = scheduler.Start(
        // Solution
        () => Observable
            .Zip(
                messages.ToObservable(), 
                Observable.Interval(TimeSpan.FromSeconds(5), scheduler).StartWith(0),
                (text, time) => text)
            .Select((text, index) => Tuple.Create(text, Convert.ToDouble(index) / Convert.ToDouble(messages.Length - 1))),
        TimeSpan.FromSeconds(20).Ticks
    );
    Assert.Equal(expected, actual.Messages.ToArray());
}

请注意,第一个元素的不透明度将为零,因此您将看不到它。你可能想稍微改变数学(提供一个偏移量),将不透明度从非零值缩放到1。

希望有帮助:0)

我将使用Observable.Generate:

Observable
    .Generate(
        1,
        x => x < messages.Length,
        x => x + 1,
        x => x,
        x => TimeSpan.FromSeconds(5.0))
    .StartWith(0)
    .Select(x => messages[x])
    .Subscribe((obj) => 
    {
        Message = obj[0];
    });   

你可以尝试这个版本,它确保在处理开始之前对源数组进行复制-这避免了可能的副作用。

Observable
    .Create<string>(o =>
    {
        var ms = messages.ToArray();
        return Observable
            .Generate(
                1,
                x => x < ms.Length,
                x => x + 1,
                x => x,
                x => TimeSpan.FromSeconds(5.0))
            .StartWith(0)
            .Select(x => ms[x])
            .Subscribe(o);
    })
    .Subscribe((obj) =>
    {
        Message = obj[0];
    });