views:

128

answers:

2

I asked the following a while ago, but only got back to the problem today. Further investigation has revealed that the problem is that the mouse enter event for the button isn't always firing. Most of the time it does, but either initially or after the button has been hidden (or collapses) the event doesn't fire. If I change to another case where the buttons should be enabled it does. Even setting the ZIndex of the buttons to 9999 doesn't seem to help.


Old title:

Why isn't my button activation code always working?

I'm experimenting with a UI where certain buttons are only active under certain conditions and only become visible when the mouse moves over their location. (NOTE: I'm actually thinking of abandoning this approach but I'd like to know why my code isn't working.)

The problem I've got is that under some circumstances the button isn't activated.

The button isn't visible or active when I first run the program, but should become active (although invisible by dint of there being no text or image set) when an album is selected and there are other albums by the same artist.

However, this doesn't happen for the first qualifying album selected. If another album is selected which meets these criteria then the button does become visible and behaves correctly.

So it looks like something isn't initialised properly, but it's not obvious to me what I've missed.

I have the following XAML:

<BitmapImage x:Key="NextAlbumSource" CacheOption="OnLoad"
             CreateOptions="IgnoreImageCache" UriSource="resources/next.png"/>


<Window.CommandBindings>
    <CommandBinding Command="{x:Static local:AlbumChooser.Next}"
                    CanExecute="NextCanExecute" Executed="NextExecuted" />
</Window.CommandBindings>


    <Button Height="50" Width="50" Margin="0,0,10,155"
            Command="{x:Static local:AlbumChooser.Next}" Name="NextAlbum"
            ToolTip="Next Album" HorizontalAlignment="Right"
            VerticalAlignment="Bottom"
            MouseEnter="NextAlbum_MouseEnter" MouseLeave="NextAlbum_MouseLeave">
        <Image />
    </Button>

Then in the "MouseEnter" handler I have the following:

    private void NextAlbum_MouseEnter(object sender, MouseEventArgs e)
    {
        if (haveAlbum && moreAlbumsBySameArtist)
        {
            ((sender as Button).Content as Image).Source = this.nextImage;
        }
    }

I've double checked and it's definitely getting to the line that sets the image source. It's just not displaying it.

The "MouseLeave" handler (for completeness is):

    private void NextAlbum_MouseLeave(object sender, MouseEventArgs e)
    {
        ((sender as Button).Content as Image).Source = null;
    }

Then when an album is chosen I call the following code to make the next (and previous) album buttons selectable.

        Visibility navigationVisiblity = haveAlbum && moreAlbumsBySameArtist 
            ? Visibility.Visible : Visibility.Hidden;
        this.NextAlbum.Visibility = navigationVisiblity;

The command handler NextCanExecute is the same code:

private void NextCanExecute(object sender, CanExecuteRoutedEventArgs e)
{
    e.CanExecute = haveAlbum && moreAlbumsBySameArtist;
    e.Handled = true;
}

(Yes, there is a case for refactoring here).

NOTE:

haveAlbum is actually a test on !string.IsNullOrEmpty(this.albumPath.Text)

and

moreAlbumsBySameArtist is a method call.

UPDATE

I've just tried changing the code to set the Opacity of the image rather than setting the Source and the same problem occurs. Further testing has revealed that it's the fact that the mouse over event handler isn't being called. I'm not adding or removing the handler at run time, so it looks like the system isn't firing the event?

Why would that be? Setting the Visibility of the button clearly affects this - is there something I must call after setting it back to Visible to get the event handlers wired up again?

A: 

It might be that your NextCanExecute method on the CommandBinding returns false under certain conditions, disabling your button.

Arcturus
I should have added that the `NextCanExecute` uses the same test as the visibility code. I'll double check that, but I'll also update the question.
ChrisF
And does it return true for the e.CanExecute?
Arcturus
When I try to debug, the code *appears* to behave itself. It's difficult to tell for sure as I'm updating the UI and these events fire when the app loses and regains focus. But if I step through the methods everything returns the expected values.
ChrisF
That is pretty odd. I've tested if the commandbindings still fire when your button would be collapsed, and they do. You could try to call CommandManager.InvalidateRequerySuggested(); so that your commandbindings will be triggered from the start?
Arcturus
A: 

There are some possible pitfalls in this situation. Since MouseEnter and MouseLeave are RoutedEvents, they are possibly handled by other elements. There is also an issue when dragging using DragMove(). It prevents all those Events from being fired while dragging.

Alex Maker
I have come across some information about RoutedEvents - I wasn't sure if it applied or not, but now that you've mentioned it I'll check again.
ChrisF