struggleendlessly
@struggleendlessly
.net Senior developer

Асинхронный запуск множества таймеров?

Нужно сделать так, что б символы сыпались. Как в фильме «Матрица».

На JS я сделал такое. Особых проблем не возникало. Теперь нужно сделать тоже самое под WP на C#.

Начал делать и столкнулся с проблемой: при запуске таймера и навешивании на него нужной функции в цикле цикл е перебирает, так как ждет, пока отработает таймер.


Вот то, что я сделал:


Создаю сетку из элементов. Которые потом будут меняться. Все работает.
public partial class MainPage : PhoneApplicationPage
    {
//координаты для изменения координат клеточки, в которой меняется символ
        int x;
        int y;
        // Конструктор
        public MainPage()
        {
            InitializeComponent();
            double ScreenWidth = System.Windows.Application.Current.Host.Content.ActualWidth;
            double ScreenHeight = System.Windows.Application.Current.Host.Content.ActualHeight;

            int i, j, countWidth, countHeight, count = 0;
            bool flag = false;
//Количество ячеек
            countWidth = (int)Math.Round(ScreenWidth / 50);
            countHeight = (int)Math.Round(ScreenHeight / 50);

            Random random = new Random();

            if (flag == false)
            {
                for (i = 0; i < countWidth; i++)
                {
                    for (j = 0; j < countHeight; j++)
                    {
                        TextBlock asd = new TextBlock();
                        asd.Name = "TB_" + i + "_" + j;  //имя, по которому буду находить элемент для изменения его содержимого
                        asd.Text = char.ConvertFromUtf32(random.Next(0x4E00, 0x4FFF));
                        int wx = i * 50;
                        int wy = j * 50;
                        asd.Foreground = new SolidColorBrush(Colors.Green);
                        asd.Margin = new Thickness(wx, wy, 0, 0);
                        asd.FontSize = 36;
                        LayoutRoot.Children.Add(asd);
                    }
                }
                flag = true;
            }

            // Пример кода для локализации ApplicationBar
            //BuildLocalizedApplicationBar();
        }



При нажатии на экран запускается «Матрица». Точнее должна запускаться.Пока работает только 1 символ, который даже двигаться не хочет.
private void TapMainGrid(object sender, System.Windows.Input.GestureEventArgs e)
        {
            double ScreenWidth = System.Windows.Application.Current.Host.Content.ActualWidth;
            double ScreenHeight = System.Windows.Application.Current.Host.Content.ActualHeight;

            int i, j, countWidth, countHeight, count = 0;

            countWidth = (int)Math.Round(ScreenWidth / 50);
            countHeight = (int)Math.Round(ScreenHeight / 50);

            Random random = new Random();

            

            this.x = 0;
            for (i = 0; i < countWidth; i++)
            {
//Так же не понял, как передать аргумент в событие, поэтому меняю глобальную переменную.
//Теоретически должен падать 1 меняющийся символ.
                this.y = i;

                var stopHandle = EasyTimer.SetInterval(() =>
                {
                    TimerCallback1();                                                             /!!!!!!!!!!!!!!!!Тут проблема. Цикл не отрабатывает, пока работает счетчик. А мне нужно, тоб паралельно куча таких работала.
                    // --- You code here ---
                    // This piece of code will run after every 1000 ms
                    // To stop the timer, just dispose off the stop handle

                }, 100);

               
                
            }/*
            DispatcherTimer newTimer = new DispatcherTimer();
            newTimer.Interval = TimeSpan.FromSeconds(0.1);
            newTimer.Tick += TimerCallback;
            newTimer.Start();*/
        }


Функция изменения клетки и символа в ней
public void  TimerCallback1()
        {

            Random random = new Random();
            string asdf = "TB_" + this.x + "_" + this.y;
            object wantedNode = LayoutRoot.FindName(asdf);
            TextBlock txt = (TextBlock)wantedNode;
            txt.Text = char.ConvertFromUtf32(random.Next(0x4E00, 0x4FFF));
        }



Класс таймера. Нашел в интернете. Пришлось переделать, что б работал на WP.
public static class EasyTimer
    {
        public static IDisposable SetInterval(Action method, int delayInMilliseconds)
        {
            DispatcherTimer timer = new DispatcherTimer();
            timer.Interval = TimeSpan.FromSeconds(delayInMilliseconds/1000);
            timer.Tick += (source, e) =>
            {
                method();
            };

            //timer.Enabled = true;
            timer.Start();

            // Returns a stop handle which can be used for stopping
            // the timer, if required
            return timer as IDisposable;
        }
        /*
        public static IDisposable SetTimeout(Action method, int delayInMilliseconds)
        {
            System.Timers.Timer timer = new System.Timers.Timer(delayInMilliseconds);
            timer.Elapsed += (source, e) =>
            {
                method();
            };

            timer.AutoReset = false;
            timer.Enabled = true;
            timer.Start();

            // Returns a stop handle which can be used for stopping
            // the timer, if required
            return timer as IDisposable;
        }*/
    }



Пробовал добавить async в метод SetInterval Класса EasyTimer. Пишет что нельзя использовать с IDisposable.

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


Возможно подскажите как сделать для этой реализации или возможно ошибки в моей логике.
  • Вопрос задан
  • 5119 просмотров
Решения вопроса 1
struggleendlessly
@struggleendlessly Автор вопроса
.net Senior developer
С одним из решений, которое я нашел можно ознакомиться тут.
Ответ написан
Комментировать
Пригласить эксперта
Ответы на вопрос 1
@gleb_kudr
Стоит начать с того, что есть как минимум два класса таймера для работы в .net — System.Timers.Timer
и System.Threading.Timer. Нужно указать, какой используете вы.

По дизайну я бы завел один таймер на все объекты. Заставил бы его крутиться в фоновом потоке. Каждые N миллисекунд он бы вызывал процедуру обработки массива точек.
На каждом тике проход по всем элементам и проверка, не подошло ли время обработки. Если время обработки подошло — апдейт элемента в UI треде и назначение следующего времени обработки.
Назначение по таймеру на каждый элемент мне не нравится — можно задолбаться потом с тредами и их взаимодействием.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы