DavidG
DavidG

Reputation: 834

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

Upvotes: 0

Views: 300

Answers (3)

Peter Duniho
Peter Duniho

Reputation: 70661

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

Upvotes: 2

Banners
Banners

Reputation: 247

I think you need to set the property on the Dispatcher thread as you are not on the UI thread in the event handler

Upvotes: 0

rbr94
rbr94

Reputation: 2277

Try to use Dispatcher. It may be that the GUI blocks up the change of controls from Code. The Dispatcher coordinates the access to an element from multiple threads:

this.Dispatcher.Invoke(() => {
    btnMyButton.IsEnabled = true;
});

Upvotes: 1

Related Questions