2009-04-12 4 views
1

Предположим, у меня есть программа C# с графическим интерфейсом, а обновление/обновление/отображение GUI занимает 0,2 секунды.Как остановить устаревшие обновления пользовательского интерфейса?

Говорите, пока он все еще вычисляет процесс отображения (в течение этих 0.2 секунд), дается новый запрос на обновление, поэтому текущий является устаревшим. Как я могу заставить его перестать делать эту бессмысленную устаревшую работу, чтобы начать вычислять новый запрос?

Это может быть не только обновление UI. Возможно, для любого вызова функции, как я могу это сделать, это станет «Если выдается другой из того же звонка, откажитесь от текущей работы и перейдите с новыми данными/ситуацией»?

Спасибо.

+0

Вам нужно сказать, какой пользовательский интерфейс. Windows Forms? Веб-формы? WPF? SilverLight? Также какая версия .NET? –

ответ

0

Вы говорите о некоторых довольно сложных проблемах с потоками. Используя встроенную структуру управления системой, нет возможности предотвратить завершение цикла сообщений, чем есть способ прерывания (изящно) другого метода.

Теперь, если эта возможность очень важна для вас, вы МОЖЕТЕ собрать все пользовательские элементы управления и внутри кода рисования вашего элемента управления, который вы можете проверить (в потокобезопасном виде, конечно) логическое значение, указывающее, должна ли картина Продолжать.

Но если я могу взять удар в темноте, я собираюсь предположить, что вы на самом деле не выполняете многопоточность. Если это так, то сценарий, который вы описываете, никогда не может произойти, поскольку процесс обновления GUI будет завершен до того, как начнется другой (а именно, этот анонимный процесс, который вы описываете, который требует другого обновления или считает, что текущий застой). Поскольку код в том же потоке выполняется последовательно, нет никакой возможности для не связанного фрагмента кода вызвать обновление.

Семантика того, как и когда происходят репликации (различие между Invalidate() и Refresh() и их соответствующими воздействиями на эту логику, например) - это тема, которая, вероятно, не представляет для вас интереса. Просто знайте, что если вы ...

  • Doing многопоточность, то вы будете должны реализовать свой собственный код для проверки, следует ли текущая операция продолжения (для UI, это означает, пользовательские элементы управления с эта логика в лакокрасочной логике)
  • Не Выполнение многопоточности, то то, что вы описать не может быть.

Надеюсь, это полезно!

+0

Спасибо за нижний план без комментариев. Это полезно. –

0

Одним из возможных путей является начало потока, который обновляет графический интерфейс пользователя и отменяет его, и запускает другой. Как правило, это не рекомендуемая практика из-за ужасного состояния управления потоками на C#, но вы должны быть в состоянии обойти это, не беспокоясь.

public static class ControlExtensions 
{ 
    public static TResult InvokeEx<TControl, TResult>(this TControl control, 
              Func<TControl, TResult> func) 
    where TControl : Control 
    { 
    if (control.InvokeRequired) 
     return (TResult)control.Invoke(func, control); 
    else 
     return func(control); 
    } 
} 

public partial class Form1 : Form 
{ 
    public Form1() 
    { 
    InitializeComponent(); 
    } 

    Thread guiUpdateThread = null; 
    public void BeginLongGuiUpdate(MyState state) 
    { 
    if (guiUpdateThread != null && guiUpdateThread.ThreadState != ThreadState.Stopped) 
    { 
     guiUpdateThread.Abort(); 
     guiUpdateThread.Join(); // wait for thread to abort 
    } 

    guiUpdateThread = new Thread(LongGuiUpdate); 
    guiUpdateThread.Start(state); 
    } 

    private void LongGuiUpdate(object state) 
    { 
    MyState myState = state as MyState; 
    // ... 
    Thread.Sleep(200); 
    this.InvokeEx(f => f.Text = myState.NewTitle); 
    // ... 
    } 
} 
+0

Это не повлияет на обновление GUI. Вызов Invoke (который требуется) выполняет вызов в основном потоке пользовательского интерфейса и просто блокирует выполнение этого потока до его завершения. Прекращение ожидающего потока не повлияет на поток пользовательского интерфейса. –

+0

Да, это будет, прерывание остановит любые дальнейшие обновления из этого потока и начнет новый цикл обновления. – Samuel

+0

Нет, это не так. Обновление не происходит в этом потоке (в противном случае вы увидите исключение для доступа к управляющему дескриптору из другого потока). Обновление происходит в потоке пользовательского интерфейса, и этот поток блокируется до завершения. Остановка заблокированной нити ничего не делает. –

1

Возможно, для любого вызова функции, как я могу сделать так, что станет «Если еще один такой же вызов выдается, отказаться от текущей работы и идти с новыми данными/ситуации вместо»?

Зачем вам это нужно? Вы потеряете всю доказуемость в своем коде. Вы никогда не сможете обеспечить согласованное состояние в своей системе. Если вы хотите имитировать его, просто возитесь с ПК.Создайте программу, которая произвольно подталкивает ПК к вершине любого метода, в котором он находится. Вы бы быстро увидели, что система передана.

0

Я не знаю, если это сопоставимо с тем, что вам нужно, но здесь идет. Одним из способов достижения такого поведения является устранение проблемы и отсрочка фактического рендеринга.

Каждый раз, когда вы получаете запрос или меняете, сжигайте таймер. Каждый входящий запрос запускает или перезапускает время. Когда таймер действительно истекает, выполните рендеринг. Он не делает то, что вы описываете, но в конце концов он может сделать то, что вам нужно, что не нужно отображать для каждого запроса, потому что рендеринг занимает слишком много времени.

Если у вас нет постоянных запросов, это работает достаточно хорошо. Очевидно, что если вы это сделаете, вы никогда не получите ничего отображаемого ...

+0

В Windows Forms есть встроенный механизм. Вместо вызова Refresh() вызов Invalidate() приведет к тому, что форма будет обновляться на следующей итерации цикла сообщений (чтобы она не прерывала остальную часть кода), но это не то, что он описывает. –

Смежные вопросы