0

I'm fairly new to C# and to programming in general.

In a previous question "C# Reset a countdown timer-DispatcherTimer-" I got help to reset my timer. Then I tried to make my code more elegant and tried to create a separate class for the timer and update the countdown text block through databinding instead of hardcoding the text property in this line in timer_Tick():

  Countdown.Text = (int)(duration - sw.Elapsed).TotalSeconds + " second(s)

My problem is that the binding fails. I still struggle with MVVM. Here is my code:

CountDownTimer.cs

class CountDownTimer : DispatcherTimer
{
    public System.Diagnostics.Stopwatch sw { get; set; }

    static readonly TimeSpan duration = TimeSpan.FromSeconds(60);

    private int _seconds;

    public int Seconds
    {
        get { return _seconds; }
        set { _seconds = value; NotifyPropertyChanged("Seconds"); }
    }

    private string _timeElapsed;

    public string TimeElapsed
    {
        get { return _timeElapsed; }
        set { _timeElapsed = value; NotifyPropertyChanged("TimeElapsed"); }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    protected void NotifyPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }


    public void timer_Tick(object sender, object e)
    {
        if (sw.Elapsed <= duration)
        {
            Seconds = (int)(duration - sw.Elapsed).TotalSeconds;
            TimeElapsed = String.Format("{0} second(s)", Seconds);
        }
        else
        {
            TimeElapsed = "Times Up";
            this.Stop();
        }
    }
}

EquationView.xaml

 <StackPanel x:Name="timePanel" Orientation="Horizontal" Visibility="Collapsed">
            <TextBlock Text="Time Left: " Height="auto" 
                       Margin="20,10,5,10" FontSize="26"/>
            <TextBlock x:Name="countdown" Text="{Binding TimeElapsed}" 
                       Margin="20,10,20,10" Width="200"  
                       Height="auto" FontSize="26"/>
 </StackPanel>

EquationView.xaml.cs

public sealed partial class EquationView : Page
{

    //code

    private void startButton_Click(object sender, RoutedEventArgs e)
    {
        //more code

        // If level == difficult enable timer
        if (Level == PlayerModel.LevelEnum.Difficult)
        {
            // timer commands
            timer.sw = System.Diagnostics.Stopwatch.StartNew();
            timer.Interval = new TimeSpan(0, 0, 0, 1);
            timer.Tick += timer.timer_Tick;
            timer.Start();

            countdown.DataContext = timer;

     //more code

    } //end of method

    // much more code

} //end of class EquationView

I inserted the line countdown.Text = timer.TimeElapsed; to try to figure out what was off and it gave me a System.NullReferenceException. Then I changed it to timer.Seconds.ToString() the first time it showed 0 but after that it returns 56 or 57.

p.s. I retyped the property changed method from my BindableBase class because I don't want to deal with multiple inheritance right now.

Community
  • 1
  • 1
D3v
  • 305
  • 1
  • 2
  • 16
  • Where are you set your datacontext? – Hamlet Hakobyan Dec 28 '14 at 20:52
  • after timer.Start(); countdown.DataContext = timer; I just commented it out to try some things after it didn't work. – D3v Dec 28 '14 at 21:33
  • There is a lot of information in this article about timers and bound classes. http://www.codeproject.com/Articles/330073/A-WPF-MVVM-Countdown-Timer – Walt Ritscher Dec 29 '14 at 05:09
  • Please edit your question so that the code shows what you believe _should_ work but which doesn't. The code here, I would not expect to work, but it doesn't seem like the code you've posted is really the code you expected to work anyway, so addressing the issues here wouldn't be useful. If you set the `DataContext` correctly, bind to the correct property, and make sure that property has a valid value (i.e. not null), it should work. By the way, calling `TimeElapsed.ToString()` is pointless...the property is already a string! – Peter Duniho Dec 29 '14 at 08:11
  • Yes you're right I changed it. Sorry, I meant to write Seconds.toString(); in the description but in my code I had it that way. – D3v Dec 29 '14 at 09:47
  • I suspect two things one being that maybe because I set first this.DataContext = equation; and then the countdown.Datacontext there is some kind of conflict the other is timeElapsed being null in the first call – D3v Dec 29 '14 at 09:53

1 Answers1

2

I changed the countdown timer seeing this question: How do I display changing time within a TextBlock?. I'd seen before I started building the timer but it helped me more now.

CountDownTimer.cs

public class CountDownTimer :  BindableBase
{
    System.Diagnostics.Stopwatch sw;

    static readonly TimeSpan duration = TimeSpan.FromSeconds(60);

    private DispatcherTimer timer;

    public CountDownTimer() 
    {
        timer = new DispatcherTimer();
        sw = System.Diagnostics.Stopwatch.StartNew();
        timer.Interval = new TimeSpan(0, 0, 0, 1);
        timer.Tick += timer_Tick;
    }

    private int? _seconds;

    public int? Seconds
    {
        get { return _seconds; }
        set { _seconds = value; NotifyPropertyChanged("Seconds"); }
    }

    private string _timeElapsed;

    public string TimeElapsed
    {
        get { return _timeElapsed; }
        set { _timeElapsed = value; NotifyPropertyChanged("TimeElapsed"); }
    }


    public void timer_Tick(object sender, object e)
    {
        if (sw.Elapsed < duration)
        {
            Seconds = (int)(duration - sw.Elapsed).TotalSeconds;
            TimeElapsed = String.Format("{0} second(s)", Seconds);
        }
        else
        {
            TimeElapsed = "Times Up";
            timer.Stop();
        }
    }

   public void StartCountDown()
    {
        sw.Start();
        timer.Start();
    }

    public void StopCountDown()
    {
        timer.Stop();
        sw.Stop();
    }
}
Community
  • 1
  • 1
D3v
  • 305
  • 1
  • 2
  • 16
  • This is not an answer, its more like a different question. – BradleyDotNET Jan 05 '15 at 17:36
  • Well my timer now works and it pauses and continues where it left off before the message. I just still have a small problem #1. Even in posts with many answers it may happen that they do not solve the problem completely. – D3v Jan 05 '15 at 17:47
  • You could argue that your code constitutes an answer in that sense. If you are going for that, I would at least put your "problems" at the end, as it looks like you are asking for more help within the answer. Also, this is a *very* poor answer, in that you just posted the working code. It would be far better to explain what was wrong with the original, rather than expecting a visitor to do a manual diff of the code. – BradleyDotNET Jan 05 '15 at 17:53
  • I have seen many types of answers: others provide help with what worked for them, others provide sources without saying something-even if it is not always obvious-, others pinpoint to what they think is wrong others give a full explanation. The argument concerning which tactic is the best is futile I think. I do not know why the original doesn't work. I think it should work that's why I left the original question someone might give a useful input. – D3v Jan 05 '15 at 18:08
  • I have no problem leaving the original question as is. But your basic answer is (in the best case): "Here's a ton of code that kind of works, it breaks in this case". Do other (poor) answers do this also? Yes, but that doesn't make it right. This example is a bit more egregious in my opinion due to the immense amount of code that is effectively useless unless we are actually running your program. I would *at least* just summarize the changes instead of posting that huge block. – BradleyDotNET Jan 05 '15 at 18:11
  • I could answer you about the amount of code and more, but I won't. I suspected it at first but now I'm really sure that you are being sarcastic with your "" and italic text. It seems you want to criticize people not help. Not that I am against criticism but yours is not benevolent. – D3v Jan 05 '15 at 18:28
  • I'm not trying to be sarcastic at all, and I'm sorry you feel my criticism is not constructive. I truly am trying to help you turn this into a high quality answer (though I still somewhat hold my doubts about it *being* an answer, I'm willing to suspend them in an effort to improve your post). – BradleyDotNET Jan 05 '15 at 18:30
  • If it is a misunderstanding ok then. I'll remove most of EquationView.xaml.cs or maybe all of it. – D3v Jan 05 '15 at 18:39
  • I removed it when I remembered that there is a comment in my linked question of the person who answered it, concerning the delay and I'm researching it now. – D3v Jan 05 '15 at 20:07