我的要求是从一个数组开始,从第一个开始,然后在5秒之后移动到下一个字符串,同时淡出并在Xamarin中使用Rx和XAML淡入下一个字符串。您可以假设这是在具有“消息”的视图模型上进行的。财产和消息容量'适用于文本和0到1之间的小数的属性。您还可以假设我有一个后台调度程序和UiScheduler设置。
我对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个字符串,而不是逐步遍历每个字符串。
我不明白的是如何按照每个' x秒来顺序浏览每个字符串。在一个正确的' Rx'时尚和(作为我的奖励!)如何随后触发另一个可观察的每条新消息,以便在每次更改时将不透明度从0增加到1。
目的是实现“窗户10”和“窗户10”。样式屏幕,用于发生大更新或用户等待长时间操作完成时。
答案 0 :(得分:3)
你可以使用Zip运算符和Observable.Interval来提供你想要的迭代字符串输出:
[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)
答案 1 :(得分:2)
我会使用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];
});