Silverlight 1 секунда DispatcherTimer срабатывает только каждые 30 секунд или около того на определенных машинах - PullRequest
0 голосов
/ 11 ноября 2009

У меня есть приложение Silverlight 3, которое отлично работает, за исключением 4 машин. DispatcherTimer и раскадровки не работают последовательно на этих 4 машинах. Я создал очень простое тестовое приложение, чтобы попытаться это выяснить, приведу код ниже.

Обычно тестовое приложение обновляет два блока TextBlock каждую секунду. Один использует DispatcherTimer, другой использует анимацию раскадровки. Это прекрасно работает - текстовые поля обновляют «1, 2, 3 ...» каждую секунду. Но на 4 затронутых машинах TextBlocks обновляются не каждую секунду, они обновляются между 27 и 33 секундами. Обновления DispatcherTimer и Storyboard выполняются в одно и то же время.

CPU, Memory, HD все в порядке. Диспетчер задач и SilverlightSpy показывает, что все в порядке. Это все рабочие станции с частотой 3 ГГц и 3 ГБ ОЗУ, на которых больше ничего не работает.

XAML:

    <TextBlock Text="0" Name="DispatcherTimerText" Grid.Column="0" />
    <TextBlock Text="0" Name="SBLoopTimerText" Grid.Column="1" />

C #:

        Storyboard _sbLoop = new Storyboard();

    public MainPage()
    {
        InitializeComponent();

        Storyboard_Start();
        Timer_Start();

    }

    void Timer_Start()
    {
        System.Windows.Threading.DispatcherTimer dt1 = new System.Windows.Threading.DispatcherTimer();
        dt1.Interval = new TimeSpan(0, 0, 1);  // 1 second
        dt1.Tick += new EventHandler(Timer_Tick);
        dt1.Start();
    }
    void Timer_Tick(object sender, EventArgs e)
    {
        TextBlock txt = ((TextBlock)LayoutRoot.Children.Single(t => ((TextBlock)t).Name == "DispatcherTimerText"));
        txt.Text = (int.Parse(txt.Text) + 1).ToString();
    }

    void Storyboard_Start()
    {
        _sbLoop.Duration = TimeSpan.FromSeconds(1);
        _sbLoop.Completed += new EventHandler(StoryboardLoop);
        _sbLoop.Begin();
    }

    void StoryboardLoop(object sender, EventArgs e)
    {
        TextBlock txt = ((TextBlock)LayoutRoot.Children.Single(t => ((TextBlock)t).Name == "SBLoopTimerText"));
        txt.Text = (int.Parse(txt.Text) + 1).ToString();

        _sbLoop.Begin();    // Restart sb animation

    }

Ответы [ 3 ]

0 голосов
/ 12 ноября 2009

Я не уверен, почему это происходит, но теперь я уверен, что это не проблема кода.

Все отлично работает, если я активно взаимодействую с рабочей станцией. Открытие браузеров, копирование файлов и т. Д. Но если рабочая станция бездействует - просто запустив тестовое приложение Silverlight, он быстро возвращается к 30 секундам на срабатывание таймеров.

Я подтвердил, что это происходит не только с моим приложением и моим тестовым приложением, но также с другими приложениями Silverlight, такими как демонстрации: http://wpierdalaj.pl/SWG/SilverlightCountDown/Run/SilverlightCountDownTimerExampleTestPage.html

В качестве обходного пути я создал командный файл, который копирует файл размером 100 МБ, удаляет его и затем начинает заново. Пока этот пакетный файл работает, все работает отлично. :)

Для долгосрочного решения ИТ-отдел выяснит, почему эти рабочие станции так быстро "спят".

0 голосов
/ 18 декабря 2012

Я написал простой метод расширения, который использует задачу. Мы более чем рады изменить основной метод DelayInvoke на использование DispatcherTimer.

См. Это сообщение для моего решения.

0 голосов
/ 11 ноября 2009

Просто предположение, но это может быть тот факт, что вы пытаетесь обновить пользовательский интерфейс непосредственно в событиях. Мне было бы любопытно посмотреть, будет ли этот код работать лучше для вас и решить проблему на машинах, которые не работают.

public partial class MainPage : UserControl
{
    Storyboard _sbLoop = new Storyboard();
    private int _slCounter = 0;
    private int _tmrCounter = 0;
    private TimeSpan interval = TimeSpan.FromMilliseconds(100);

    public MainPage()   
    {
        InitializeComponent();
        Storyboard_Start();
        Timer_Start();
    }

    void Timer_Start()
    {
        System.Windows.Threading.DispatcherTimer dt1 = new System.Windows.Threading.DispatcherTimer();
        dt1.Interval = interval;
        // 1 second
        dt1.Tick += new EventHandler(Timer_Tick);
        dt1.Start();
    }

    void Timer_Tick(object sender, EventArgs e)
    {
        _tmrCounter++;
        Dispatcher.BeginInvoke(() => DispatcherTimerText.Text = _tmrCounter.ToString());
    }

    void Storyboard_Start()
    {
        _sbLoop.Duration = interval;
        _sbLoop.Completed += new EventHandler(StoryboardLoop);
        _sbLoop.Begin();
    }

    void StoryboardLoop(object sender, EventArgs e)
    {
        _slCounter++;
        Dispatcher.BeginInvoke(() => SBLoopTimerText.Text = _slCounter.ToString());
        _sbLoop.Begin();
        // Restart sb animation
    }
}

Этот код использует BeginInvoke для обновления пользовательского интерфейса вместо непосредственного его обновления. Возможно, вам придется изменить мой интервал, поскольку я выбрал его как 100 мс вместо одной секунды только для тестирования.

...