-1

I'm attempting to generate 16 unique DispatcherTimers, without having to recreate the code for each. However, I cannot figure out how to dynamically name them based on the content converted to string of the button pressed.

Originally, I was setting each timer up individually, but this wound up being far too much code to maintain. Now, I've got a method that triggers when one of the 16 buttons is clicked that sets a string to the button's content & passes it to a second method to set up the Dispatcher Timer.

I can't just name the timer in the button click method & pass it, as it tells me it's already used in an enclosing scope to define a local or parameter. I tried naming the timer by concatenating the string "timer" to the end of the variable name, but it didn't like that.

Upon button click

        public void StartBtnClicked(object sender, RoutedEventArgs e)
        {
            string btn = (sender as Button).Content.ToString();
            string timerName = btn + "timer";
            DispatcherTimerSetup(btn);
        }

Setting up the timer

        public void DispatcherTimerSetup(string passedBtn)
        {
            DispatcherTimer passedBtn + "Timer" = new DispatcherTimer();
        }

My goal right now is to have the timers be named like "Button1ContentTimer". I'll be using the timers to trigger events upon completion & they will have different TimeSpans. I'll also be implementing a start/stop all button, which is why I'm naming each of them, so I can call them all at once in the start/stop all methods.

Edit:

I'm now creating the timers & adding them to a dictionary. The timers are all named the same, but the string included with them will be different.

        public void DispatcherTimerSetup(string btn)
        {
            Dictionary<string, DispatcherTimer> timerDict =
                new Dictionary<string, DispatcherTimer>(); //Set up a dictionary to house all the timers in

            DispatcherTimer timer = new DispatcherTimer();

            try
            {
                timerDict.Add(btn, timer);
            }
            catch (ArgumentException)
            {
                MessageBox.Show("This timer is already running");
            }
        }

The StopAll method will receive the dictionary & iterate over it for each timer inside.


        static public void StopAll(Dictionary<string, DispatcherTimer> timerDict)
        {
            foreach(KeyValuePair<string,DispatcherTimer> entry in timerDict)
            {

            }
        }

my only remaining question is how to actually stop these timers? Previously, I would just call timerName.Stop(); multiple times, with a different timer name for each timer.

But now that the timers are all named the same & in a dictionary, I can't figure out how to access them. I tried:

        static public void StopAll(Dictionary<string, DispatcherTimer> timerDict)
        {

            foreach(KeyValuePair<string,DispatcherTimer> entry in timerDict)
            {
                timerDict.Remove(DispatcherTimer);
            }
        }

, but it tells me DispatcherTimer is a type which is not valid in the given context. I'm not even sure removing it from the dictionary is the right thing to do, would that stop it? Or do I need to approach this a different way? I feel like there should be a way to actually call each DispatcherTimer element out of the dictionary sequentially, but I haven't been able to figure that one out yet.

  • 3
    Why don't you use a [`Dictionary`](https://learn.microsoft.com/en-us/dotnet/api/system.collections.generic.dictionary-2?view=netframework-4.8)? – Clemens May 08 '19 at 12:30
  • 1
    Why do you need individual names for the timer? Do all timers share the same Tick-Method and you want to identify them? – Tomtom May 08 '19 at 12:32
  • @Clemens, I've never used Dictionaries before, reading into them now. – Schreiberito May 08 '19 at 12:38
  • @Tomtom, the reason I (think I) need to name them individually is mainly for the Stop all method. If I leave all their names the same, I know they'd still run in independent threads, but I don't know of a way I could call them each in the Stop All method. – Schreiberito May 08 '19 at 12:38
  • if you don't need their names, then you can put all into a `List` and iterate through this list if you want to stop all – Tomtom May 08 '19 at 12:45
  • I don't *think* I need their names at this point, but is there any harm in using a dictionary instead? From what I can tell, they're essentially the same, except a dictionary has the ability to store their names as well on the chance I do need them further along in development. – Schreiberito May 08 '19 at 12:54
  • Well basically you need to manage a `Collection` of timers... as far as you described your problem until now, it really doesn't matter whether your collection is a `List` or a `Dictionary`, as long as they contain a reference to every active timer object. Feel free to try both collections - you should learn about them anyway if you want to become better in C# – grek40 May 08 '19 at 13:10
  • Possible duplicate of [Create dynamic variable name](https://stackoverflow.com/questions/20857773/create-dynamic-variable-name) – grek40 May 08 '19 at 13:12
  • @Clemens, I've edited my question at the bottom to include my new code utilizing dictionaries. Thanks for pointing me in that direction! The last hurdle I can't seem to get over is actually accessing them to stop them once they are included in the dictionary. Any pointers? – Schreiberito May 08 '19 at 13:17
  • Haven't you read the documentation? As a hint, clearing a Dictionary by looping over all entries is nonsense. Just call `timerDict.Clear()`. Accessing individual elements by their key is done by `timerDict[name]`. Iterating over all DispatcherTimers would be done by `foreach (var t in timerDict.Values)` – Clemens May 08 '19 at 13:27
  • Also, @Tomtom, I think I've realized I will need the names for sure. If I was just doing a stop all, I could iterate through. However, for the individual stops, I'm not sure how else I could access them other than a predetermined name. Say I only start timers 1, 6, & 9. If I try accessing them by the order they were created, timer 9 would be accessed by button 3. – Schreiberito May 08 '19 at 13:28

1 Answers1

2

Here are the links to the documentation:

Dictionary

DispatcherTimer

To stop timers you could do something like this. Note that simply removing a timer from the dictionary does not stop it.

static public void StopAll(Dictionary<string, DispatcherTimer> timerDict)
{
    foreach(var timer in timerDict.Values) timer.Stop();
    timerDict.Clear();
}

static public void StopTimer(string TimerName, Dictionary<string, DispatcherTimer> timerDict)
{
    if (timerDict.ContainsKey(TimerName)
    {
        timerDict[TimerName].Stop();
        timerDict.Remove(TimerName);
    }        
}
Neil B
  • 2,096
  • 1
  • 12
  • 23