簡體   English   中英

Observable.Interval未以預期的頻率更新UI

[英]Observable.Interval not updating UI with expected frequency

我正在嘗試模擬時鍾的行為。 為此,我創建了一個Observable.Interval ,它在指定的時間間隔后,以相等的時間量更新屬性的值。 該值與GUI數據綁定。

問題是:“時鍾”運行得比預期的慢得多,也就是說,時鍾值增加一秒需要花費一秒以上的時間。

所需的時間分辨率越精細(下面的MILLIS_INTERVAL的值),問題MILLIS_INTERVAL嚴重(我使用值MILLIS_INTERVAL和1000的其他約數進行了測試,因為據記錄TimeSpan.FromMilliseconds的最大分辨率為1ms )。

我希望可觀察到的回調能夠異步運行,並且盡管有一定的執行時間,但可以定期觸發,甚至可能並行觸發,但似乎頻率越大,滯后就越多。

視圖模型

using System;
using System.ComponentModel;
using System.Reactive.Linq;

namespace IntervalClock
{
    public class ViewModel : INotifyPropertyChanged
    {

        public double TimeSeconds
        {
            get { return _timeSeconds; }
            set
            {
                _timeSeconds = value;
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("TimeSeconds"));
            }
        }
        double _timeSeconds;


        const double MILLIS_INTERVAL = 10;

        public ViewModel()
        {
            Observable.Interval(TimeSpan.FromMilliseconds(MILLIS_INTERVAL))
                      .Subscribe(token => TimeSeconds += MILLIS_INTERVAL / 1000);
        }


        public event PropertyChangedEventHandler PropertyChanged;
    }
}

主窗口:

<Window x:Class="IntervalClock.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:IntervalClock"
        mc:Ignorable="d">

    <Window.DataContext>
        <local:ViewModel/>
    </Window.DataContext>

    <StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
        <TextBlock Text="{Binding TimeSeconds, StringFormat=N3}" FontSize="30"/>
    </StackPanel>
</Window>

計時器似乎在同一線程上調用OnNext ,因此不會“異步”執行回調。

您可以創建自己的方法來調用線程池線程上的回調。 這是使用System.Timers.Timer類的基本示例:

public static IObservable<long> Interval(TimeSpan interval)
{
    return Observable.Create<long>(observer =>
    {
        long i = 0;
        Timer _timer = new Timer(interval.TotalMilliseconds);
        _timer.Elapsed += (s, e) => observer.OnNext(i++);
        _timer.Start();

        return Disposable.Create(() =>
        {
            _timer.Stop();
            _timer.Dispose();
        });
    });
}

用法(只需調用您自己的Interval方法而不是Observable.Interval ):

Interval(TimeSpan.FromMilliseconds(MILLIS_INTERVAL))
                  .Subscribe(token => TimeSeconds += MILLIS_INTERVAL / 1000);

這應該使“回調異步運行,並且盡管有一定的執行時間,但仍要以規則的時間間隔(可能是並行觸發)觸發”。

Observable.Interval運算符對運行每個.OnNext觸發之間的間隔進行.OnNext 因此,如果.OnNext花費0.1s且間隔為1.0s,則有效期為1.1s。 但是,當然Windows不是實時操作系統,因此它具有漂移性。 您的實際時間可能會更大,尤其是在系統負載時。

這是我的處理方式:

var interval = TimeSpan.FromSeconds(1.0);
Observable
    .Create<long>(o =>
    {
        var sw = Stopwatch.StartNew();
        return
            Observable
                .Timer(TimeSpan.Zero, TimeSpan.FromSeconds(interval.TotalSeconds / 10.0))
                .Select(x => (long)sw.Elapsed.TotalSeconds)
                .DistinctUntilChanged()
                .Subscribe(o);
    })

StopWatch的使用為您提供了出色的經過時間精度。 計時器的觸發頻率比interval觸發的頻率大約高10倍,因此在觸發時會出現+/- 10%的錯誤,但結果是相同的-從此可觀察值返回的是非常准確的“秒”值,只是不返回精確地每秒

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM