DavidG DavidG - 2 months ago 6
C# Question

Button is not switching from disabled to enabled

I finally got rid of all the error messages as I attempted ways to find a control and enable it.

In the properties pane I disabled a button on mainwindow.

This code runs successfully, albeit annoyingly, because every second I have it give me another msgbox to show code is being triggered. But it is not enabling the button. I'm new to C# so it looks like arabic to me. In VB it would just be:

btnMyButton.Enabled = True


Here is my code behind:

public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
System.Timers.Timer myTimer = new System.Timers.Timer();
myTimer.Elapsed += new ElapsedEventHandler(DisplayTimeEvent);
myTimer.Interval = 1000; // 1000 ms is one second
myTimer.Start();
}

public void DisplayTimeEvent(object source, ElapsedEventArgs e)
{
DateTime now = DateTime.Now;
DateTime today3am = now.Date.AddHours(3);

if (DateTime.Today == today3am.Date && now >= today3am)
{
MessageBox.Show("Code is being triggered");
btnMyButton.IsEnabled = true;
}
}
}


SOLVED: Response suggested this: (IT WORKED)

public void DisplayTimeEvent(object source, ElapsedEventArgs e)
{
DateTime now = DateTime.Now;
DateTime today3am = now.Date.AddHours(3);

if (DateTime.Today == today3am.Date && now >= today3am)
{
MessageBox.Show("Button Should Enable");
this.Dispatcher.Invoke(() => {
btnMyButton.IsEnabled = true;
});
}
}

Answer

When I copy and paste the code you've provided and run it, I get (as expected) an exception when trying to set the IsEnabled property:

The calling thread cannot access this object because a different thread owns it.

This is the standard "wrong thread" exception. You don't see the exception (apparently) because you're not running in a debugger. The Timer thread catches the exception and ignores it.

One way to fix the problem is to, as suggested by others, use Dispatcher.Invoke():

public void DisplayTimeEvent(object source, ElapsedEventArgs e)
{
    DateTime now = DateTime.Now;
    DateTime today3am = now.Date.AddHours(3);

    if (DateTime.Today == today3am.Date && now >= today3am)
    {
        Dispatcher.Invoke(() => btnMyButton.IsEnabled = true);
    }
}

However, since the problem is fundamentally caused by your use of the System.Timers.Timer class, it makes more sense to just use the correct timer class, System.Windows.Threading.DispatcherTimer:

public MainWindow()
{
    InitializeComponent();
    var myTimer = new DispatcherTimer();
    myTimer.Tick += DisplayTimeEvent;
    myTimer.Interval = TimeSpan.FromSeconds(1);
    myTimer.Start();
}

public void DisplayTimeEvent(object source, EventArgs e)
{
    DateTime now = DateTime.Now;
    DateTime today3am = now.Date.AddHours(3);

    if (DateTime.Today == today3am.Date && now >= today3am)
    {
        btnMyButton.IsEnabled = true;
    }
}
Comments