перечислять по списку или dict каждые x секунд с помощью timer или dispatchertimer в C#

#c# #timer #dispatchertimer

#c# #таймер #dispatchertimer

Вопрос:

допустим, у меня есть словарь с 3 парами значений / ключей.

 private void someMethod()
{
    Dictionary<string, int> d = new Dictionary<string, int>();
    d.Add("cat", 22);
    d.Add("dog", 14);
    d.Add("llama", 2);
    d.Add("iguana", 6);

    somesortoftimercode
}

private void DisplayText(string x, int y)
{
    label1.Text = x;
    int someValue= 3 y;
}
  

я хочу выполнить итерацию по этому словарю, я хочу, чтобы dispatchertimer (или timer) вызывал DisplayText со значениями словаря каждые 3 секунды. как мне это сделать?

Обновить:

я не могу использовать Thread .Sleep (XXX), я не могу заблокировать поток. у меня есть другие вещи, которые работают в фоновом режиме, и я не могу развернуть это, чтобы потоки были повсюду.

плюс: http://msmvps.com/blogs/peterritchie/archive/2007/04/26/thread-sleep-is-a-sign-of-a-poorly-designed-program.aspx

Комментарии:

1. Какую версию C # вы используете?

Ответ №1:

 private Timer timer;

private void someMethod()
{
    var d = new Dictionary<string, int>
                {
                    {"cat", 22}, 
                    {"dog", 14}, 
                    {"llama", 2}, 
                    {"iguana", 6}
                };

    int index = 0;
    TimerCallback timerCallBack = state =>
                                        {
                                            DisplayText(d.ElementAt(index).Key, d.ElementAt(index).Value);
                                            if(  index == d.Count)
                                            {
                                                index = 0;
                                            }
                                        };
    timer = new Timer(timerCallBack, null, TimeSpan.Zero, TimeSpan.FromSeconds(3));
}

private void DisplayText(string x, int y)
{
    label1.Text = x;
    int someValue= 3 y;
}
  

Если вам нужно перечислить словарь только один раз, вы можете использовать следующий код:

 new Task(() =>
    {
        d.All(kvp =>
        {
            DisplayText(kvp.Key, kvp.Value);
            Thread.Sleep(3000);
            return true;
        });
    }
).Start();
  

Комментарии:

1. Вы можете заблокировать другой поток, не основной. Я обновил ответ.

Ответ №2:

Вы можете использовать любой из таймеров, предоставляемых фреймворком, например

 System.Threading.Timers.Timer
  

Установите интервал на любой, который вы хотите, а затем в событии Tick вызовите foreach цикл, который повторяет вашу коллекцию. Согласно вашему примеру

 foreach(var pair in d)
{ 
   DisplayText(pair.key, pair.value);
}
  

Комментарии:

1. Вы можете сэкономить несколько миллисекунд, выполнив foreach (var kvp in d) { DisplayText(kvp.Key, kvp.Value); } это, чтобы избежать поиска значений каждый раз.

2. @JoeEnos и на самом деле правильнее, если для ключа есть несколько значений, что меняет мой ответ.

3. нет, это не работает для меня. цикл foreach будет проходить по каждому из них одновременно, а не по одному в указанное время.

Ответ №3:

Создайте форму с именем label labell и попробуйте этот код:

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

    private void Form1_Load(object sender, EventArgs e)
    {
        someMethod();
    }

    Thread thread;
    private void someMethod()
    {
        Dictionary<string, int> d = new Dictionary<string, int>();
        d.Add("cat", 22);
        d.Add("dog", 14);
        d.Add("llama", 2);
        d.Add("iguana", 6);

        thread = new Thread(new ParameterizedThreadStart(Do));
        thread.Start(d);
    }

    delegate void _DisplayText(string x, int y);
    private void DisplayText(string x, int y)
    {
        if (this.InvokeRequired)
        {
            this.Invoke(new _DisplayText(DisplayText), x, y);
            return;
        }
        label1.Text = x;
        int someValue = 3   y;
    }

    public void Do(object dic)
    {
        Dictionary<string, int> d = (Dictionary<string, int>)dic;
        while (true)
        {
            foreach (var item in d)
            {
                DisplayText(item.Key, item.Value);
                Thread.Sleep(3000);
            }
        }
    }
}
  

Комментарии:

1. нет, это невозможно сделать с помощью thread.sleep . я не могу заблокировать его, пока он ждет

2. Обратите внимание, что он не блокируется во время ожидания, потому что я создал другой поток.

3. Если вы попробуете этот пример кода, вы увидите, что вы все еще можете взаимодействовать с графическим интерфейсом программы, в то время как другой поток вызывает изменение метки каждые 3 секунды.

Ответ №4:

Это должно помочь вам двигаться в правильном направлении. Я предполагаю, что вы создаете приложение Win Forms. Если нет, это не сработает для вас.

     private System.Windows.Forms.Timer t = new System.Windows.Forms.Timer();
    private Dictionary<string, int> d = new Dictionary<string, int>()
    {
        {"cat", 22},
        {"dog", 14},
        {"llama", 2},
        {"iguana", 6}
    };
    public Form1()
    {
        InitializeComponent();
        t.Tick  = new EventHandler(t_Tick);
        t.Start();
    }

    void t_Tick(object sender, EventArgs e)
    {
        t.Stop();
        foreach (var item in d)
        {
            label1.Text = item.Key;
            int someValue = 3   item.Value;
        }
        t.Start();
    }
  

Ответ №5:

В Reactive Extensions (Rx) (от Microsoft Cloud Team) есть очень хороший способ делать то, что вы хотите.

После добавления ссылок на Rx (что вы можете сделать через NuGet) вы просто добавляете это в свой someMethod метод:

 Observable
    .Interval(TimeSpan.FromSeconds(3.0))
    .ObserveOnDispatcher()
    .Subscribe(x =>
    {
        d.ToArray() // Helps to prevent race conditions
            .ForEach(kvp => DisplayText(kvp.Key, kvp.Value));
    });
  

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

Если вы используете Windows Forms, тогда .ObserveOnDispatcher() становится .ObserveOn(label1) или .ObserveOn(form) , и все готово.

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

Вот ссылки для Rx: