0

say i have a dictionary with 3 value/key pairs.

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;
}

i want iterate through this dictionary, i want a dispatchertimer(or timer) to call displayText with the dictionary values every 3 seconds. how do i do that?

UPDATE:

i can't use Thread.Sleep(XXX), i can't block the thread. i have other stuff going in the background, and i can't spin this out to have threads all over the place.

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

darthwillard
  • 809
  • 2
  • 14
  • 28

5 Answers5

2
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;
}

If you need enumerate dictionary only once you may use following code:

new Task(() =>
    {
        d.All(kvp =>
        {
            DisplayText(kvp.Key, kvp.Value);
            Thread.Sleep(3000);
            return true;
        });
    }
).Start();
Yuriy Rozhovetskiy
  • 22,270
  • 4
  • 37
  • 68
1

You could use any of the timers provided by the framework such as

System.Threading.Timers.Timer

Set the interval to whatever you want and then in the Tick event call a foreach loop that iterates over your collection. Per your example

foreach(var pair in d)
{ 
   DisplayText(pair.key, pair.value);
}
msarchet
  • 15,104
  • 2
  • 43
  • 66
  • You might save a few milliseconds by doing `foreach (var kvp in d) { DisplayText(kvp.Key, kvp.Value); }`, to avoid looking up the values each time. – Joe Enos Oct 27 '11 at 19:54
  • @JoeEnos and it's actually more correct if there are multiple values for a key, changing my answer. – msarchet Oct 27 '11 at 19:55
  • not, this doesn't work for me. the foreach loop will go over every single one at once, not one at a specified time. – darthwillard Oct 27 '11 at 23:23
0

Create a form with a label named labell on it and try this code:

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);
            }
        }
    }
}
Miguel Angelo
  • 23,796
  • 16
  • 59
  • 82
0

This should get you going in the right direction. I assume you are creating a Win Forms application. If not, this won't work for you.

    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();
    }
arb
  • 7,753
  • 7
  • 31
  • 66
0

The Reactive Extensions (Rx) (from the Microsoft Cloud Team) has a very nice way to do what you want.

After adding references to Rx (which you can do via NuGet) you just drop this into your someMethod method:

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

It sets up the timer - which fires on a background thread - and then marshals the call to the dispatcher (i.e. UI thread) to prevent cross-thread issues.

If you're using Windows Forms then the .ObserveOnDispatcher() becomes .ObserveOn(label1) or .ObserveOn(form) and you're good to go.

No need to muck about with explicitly creating threads, timers or background workers.

Here are the links for Rx:

Enigmativity
  • 113,464
  • 11
  • 89
  • 172