locked
Repointed Win8 -> Win8.1 App, VisualState PointerOver no longer working RRS feed

  • Question

  • Hi All,

          I have been searching for awhile and can't seem to find an answer to this, but it has me stumped.   I had a Win8 C# with a custom Templated Control.  The control basically inherits from a Button and has a few bound dependency properties to customize buttons in more detail.

    Under my <ControlTemplate> I had the following:

    <VisualStateGroup x:Name="CommonStates">
        <VisualState x:Name="Normal" />
        <VisualState x:Name="PointerOver">
            <Storyboard>
                ...
            </Storyboard>
        </VisualState>

        <VisualState x:Name="Pressed">
            <Storyboard>
                ...
            </Storyboard>
        </VisualState>

        <VisualState x:Name="Disabled">
            <Storyboard>
                ...
            </Storyboard>
        </VisualState>
    </VisualStateGroup>

    In Win8, all 4 Visual States worked fine when the mouse entered, left, pressed.  It also rendered properly when disabled.  I targeted Win8.1 and now only 3 of the visual states work (Normal, Pressed and Disabled).  The PointerOver visual state doesn't seem to do anything anymore.

    Is there something specific that needs to be done here?

    Thanks in advance,
    Rob

    Saturday, November 16, 2013 7:28 AM

Answers

  • Hi Rob,

    I figure out the reason, I upload a sample to the skydrive where you could try with it: http://sdrv.ms/1epaO0z

    The reason is the normal image eat the PointOver event and the PointOver cannot pass to the button therefore the PointOver for the Button does not work. If you mouse hover on the grid (the red zone), you should be able to see the correct responding.

    Best Regards,

    --James


    <THE CONTENT IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, WHETHER EXPRESS OR IMPLIED>
    Thanks
    MSDN Community Support

    Please remember to "Mark as Answer" the responses that resolved your issue. It is a common way to recognize those who have helped you, and makes it easier for other visitors to find the resolution later.

    Wednesday, November 27, 2013 3:47 AM
    Moderator
  • Hi James,
          While I don't fully understand exactly why that would be the case (the image itself wouldn't respond to visual state changes, would it?), I was able to pick something out of your sample that does resolve the problem for me.

    If I specify a Background on the StackPanel element, the problem is fixed.

    Before:
    <StackPanel x:Name="pnlContent">

    After:
    <StackPanel x:Name="pnlContent" Background="#00FFFFFF">

    Note that if you remove the Background in your sample, it will similarly break.

    An interesting side effect is that if I have multiple buttons in a vertical layout grid, the grid will have the width of the widest image.  When I do the mouseover, all of the shortest ones work fine, but the longest one will only recognize the PointerOver state if I enter from the top or bottom, doing a mouseover from the side doesn't work.  In case someone else sees that problem, I was able to fix that with a 20 point margin within the control itself.

    Do you also know if something changed between Win8 and Win8.1 in this behavior?  As I said, the problem didn't happen until I repointed the app...  Seems like ultimately something here changed for the worse.

    Thanks again for looking into all of this,
    Rob


    • Edited by Rob Skoon Wednesday, November 27, 2013 7:17 AM Add text
    • Marked as answer by Rob Skoon Wednesday, January 8, 2014 1:15 AM
    Wednesday, November 27, 2013 7:13 AM

All replies

  • Thanks for your response. The PointerEntered seems to be the actual event on a UIElement. I previously was handling this in the VisualState. See here where they show it:

    http://msdn.microsoft.com/en-us/library/windows/apps/windows.ui.xaml.visualstate.aspx

    For what its worth, I did try PointerEntered, but that failed as well.

    Thanks,

    Rob

    Saturday, November 16, 2013 11:57 PM
  • Hi Rob,

    It should be PointerOver, not PointEnter, I modified a "PointerOver" section yesterday for a PasswordBox control under 8.1 and works fine. Can you validate if you miss something within storyboard or can you share code with us for a further analysis?

    --James


    <THE CONTENT IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, WHETHER EXPRESS OR IMPLIED>
    Thanks
    MSDN Community Support

    Please remember to "Mark as Answer" the responses that resolved your issue. It is a common way to recognize those who have helped you, and makes it easier for other visitors to find the resolution later.

    Friday, November 22, 2013 9:45 AM
    Moderator
  • Hi James,

          Thanks for the confirmation...  I recreated the issue w/ a simple image over button.  Please see below, let me know if you have further questions.  As mentioned above, "Normal", "Pressed", and "Disabled" work fine, just not "PointerOver"

    Thanks,
    Rob

    generic.xaml:
    ******************

    <Style TargetType="controls:SkinnedButton">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="controls:SkinnedButton">
                        <StackPanel x:Name="pnlContent">
                            <Image Source="{TemplateBinding ImageSourceNormal}"
                                           Visibility="Visible"
                                           x:Name="normalImage"
                                           Grid.Row="0"
                                           Margin="0,5"
                                           Height="{TemplateBinding ImageHeight}"
                                          />
                            <Image Source="{TemplateBinding ImageSourceHover}"
                                           Visibility="Collapsed"
                                           x:Name="mouseoverImage"
                                           Grid.Row="0"
                                           Margin="0,5"
                                           Height="{TemplateBinding ImageHeight}"
                                            />
                            <Image Source="{TemplateBinding ImageSourceDisabled}"
                                           Visibility="Collapsed"
                                           x:Name="disabledImage"
                                           Grid.Row="0"
                                           Margin="0,5"
                                           Height="{TemplateBinding ImageHeight}"
                                            />
                            <VisualStateManager.VisualStateGroups>
                                <VisualStateGroup x:Name="CommonStates">
                                    <VisualState x:Name="Normal" />

                                    <VisualState x:Name="PointerOver">
                                        <Storyboard>
                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Visibility" Storyboard.TargetName="mouseoverImage">
                                                <DiscreteObjectKeyFrame KeyTime="0" Value="Visible"/>
                                            </ObjectAnimationUsingKeyFrames>

                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Visibility" Storyboard.TargetName="normalImage">
                                                <DiscreteObjectKeyFrame KeyTime="0" Value="Collapsed"/>
                                            </ObjectAnimationUsingKeyFrames>

                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Visibility" Storyboard.TargetName="disabledImage">
                                                <DiscreteObjectKeyFrame KeyTime="0" Value="Collapsed"/>
                                            </ObjectAnimationUsingKeyFrames>

                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Opacity" Storyboard.TargetName="pnlContent">
                                                <DiscreteObjectKeyFrame KeyTime="0" Value="1"/>
                                            </ObjectAnimationUsingKeyFrames>
                                        </Storyboard>
                                    </VisualState>

                                    <VisualState x:Name="Pressed">
                                        <Storyboard>
                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Visibility" Storyboard.TargetName="mouseoverImage">
                                                <DiscreteObjectKeyFrame KeyTime="0" Value="Visible"/>
                                            </ObjectAnimationUsingKeyFrames>

                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Visibility" Storyboard.TargetName="normalImage">
                                                <DiscreteObjectKeyFrame KeyTime="0" Value="Collapsed"/>
                                            </ObjectAnimationUsingKeyFrames>

                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Visibility" Storyboard.TargetName="disabledImage">
                                                <DiscreteObjectKeyFrame KeyTime="0" Value="Collapsed"/>
                                            </ObjectAnimationUsingKeyFrames>

                                            <DoubleAnimation Storyboard.TargetName="pnlContent"
                                                             Storyboard.TargetProperty="Opacity"
                                                             To=".5"
                                                             Duration="0:0:0.1" />

                                            <PointerDownThemeAnimation Storyboard.TargetName="pnlContent"/>
                                        </Storyboard>
                                    </VisualState>

                                    <VisualState x:Name="Disabled">
                                        <Storyboard>
                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Visibility" Storyboard.TargetName="mouseoverImage">
                                                <DiscreteObjectKeyFrame KeyTime="0" Value="Collapsed"/>
                                            </ObjectAnimationUsingKeyFrames>

                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Visibility" Storyboard.TargetName="normalImage">
                                                <DiscreteObjectKeyFrame KeyTime="0" Value="Collapsed"/>
                                            </ObjectAnimationUsingKeyFrames>

                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Visibility" Storyboard.TargetName="disabledImage">
                                                <DiscreteObjectKeyFrame KeyTime="0" Value="Visible"/>
                                            </ObjectAnimationUsingKeyFrames>

                                        </Storyboard>
                                    </VisualState>

                                </VisualStateGroup>
                            </VisualStateManager.VisualStateGroups>
                        </StackPanel>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>

    SkinnedButton.cs
    *******************

        public sealed class SkinnedButton : Button
        {
            public SkinnedButton()
            {
                this.DefaultStyleKey = typeof(SkinnedButton);
            }

            public static readonly DependencyProperty ImageHeightProperty = DependencyProperty.Register("ImageHeight",
                                                                               typeof(double),
                                                                               typeof(SkinnedButton),
                                                                               new PropertyMetadata(null));

            public static readonly DependencyProperty ButtonLabelProperty = DependencyProperty.Register("ButtonLabel",
                                                                                        typeof(string),
                                                                                        typeof(SkinnedButton),
                                                                                        new PropertyMetadata(null));

            public static readonly DependencyProperty ImageSourceNormalProperty = DependencyProperty.Register("ImageSourceNormal",
                                                                                                typeof(ImageSource),
                                                                                                typeof(SkinnedButton),
                                                                                                new PropertyMetadata(null));

            public static readonly DependencyProperty ImageSourceHoverProperty = DependencyProperty.Register("ImageSourceHover",
                                                                                                typeof(ImageSource),
                                                                                                typeof(SkinnedButton),
                                                                                                new PropertyMetadata(null));

            public static readonly DependencyProperty ImageSourceDisabledProperty = DependencyProperty.Register("ImageSourceDisabled",
                                                                                                typeof(ImageSource),
                                                                                                typeof(SkinnedButton),
                                                                                                new PropertyMetadata(null));

            public ImageSource ImageSourceNormal
            {
                get { return (ImageSource)GetValue(ImageSourceNormalProperty); }
                set { SetValue(ImageSourceNormalProperty, value); }
            }

            public ImageSource ImageSourceHover
            {
                get { return (ImageSource)GetValue(ImageSourceHoverProperty); }
                set { SetValue(ImageSourceHoverProperty, value); }
            }

            public ImageSource ImageSourceDisabled
            {
                get { return (ImageSource)GetValue(ImageSourceDisabledProperty); }
                set { SetValue(ImageSourceDisabledProperty, value); }
            }

            public double ImageHeight
            {
                get { return (double)GetValue(ImageHeightProperty); }
                set { SetValue(ImageHeightProperty, value); }
            }

            public string ButtonLabel
            {
                get { return (string)GetValue(ButtonLabelProperty); }
                set { SetValue(ButtonLabelProperty, value); }
            }

        }

    Monday, November 25, 2013 6:26 PM
  • Hi Rob,

    In the code-behind for the template control, you can override the OnPointerEntered method to call your visual states.

    e.g:

           

    protected override void OnPointerEntered(PointerRoutedEventArgs e)
    {
      VisualStateManager.GoToState(this, "PointerOver", false);
    }

    Tuesday, November 26, 2013 11:50 PM
  • Hi Rob,

    It weird that the only PointOver does not work, I think the reason is PointOver is not triggered, I can see that the PointOver image has been changed in Blend, the problem is the button will not fire the pointOver event, btw, the "pressed" also looks strange, the opacity of the gird should always be 0.5, but the real situation is it convert to a PointerOver (opacity = 1) . Take a look at the documentation: http://msdn.microsoft.com/en-us/library/windows/apps/jj709909.aspx. I will try to figure out why it is and update you later.

    BTW, tsw's answer might be a solution, but I'm not sure about that.

    -James


    <THE CONTENT IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, WHETHER EXPRESS OR IMPLIED>
    Thanks
    MSDN Community Support

    Please remember to "Mark as Answer" the responses that resolved your issue. It is a common way to recognize those who have helped you, and makes it easier for other visitors to find the resolution later.




    Wednesday, November 27, 2013 2:54 AM
    Moderator
  • Hi Rob,

    I figure out the reason, I upload a sample to the skydrive where you could try with it: http://sdrv.ms/1epaO0z

    The reason is the normal image eat the PointOver event and the PointOver cannot pass to the button therefore the PointOver for the Button does not work. If you mouse hover on the grid (the red zone), you should be able to see the correct responding.

    Best Regards,

    --James


    <THE CONTENT IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, WHETHER EXPRESS OR IMPLIED>
    Thanks
    MSDN Community Support

    Please remember to "Mark as Answer" the responses that resolved your issue. It is a common way to recognize those who have helped you, and makes it easier for other visitors to find the resolution later.

    Wednesday, November 27, 2013 3:47 AM
    Moderator
  • Hi James,
          While I don't fully understand exactly why that would be the case (the image itself wouldn't respond to visual state changes, would it?), I was able to pick something out of your sample that does resolve the problem for me.

    If I specify a Background on the StackPanel element, the problem is fixed.

    Before:
    <StackPanel x:Name="pnlContent">

    After:
    <StackPanel x:Name="pnlContent" Background="#00FFFFFF">

    Note that if you remove the Background in your sample, it will similarly break.

    An interesting side effect is that if I have multiple buttons in a vertical layout grid, the grid will have the width of the widest image.  When I do the mouseover, all of the shortest ones work fine, but the longest one will only recognize the PointerOver state if I enter from the top or bottom, doing a mouseover from the side doesn't work.  In case someone else sees that problem, I was able to fix that with a 20 point margin within the control itself.

    Do you also know if something changed between Win8 and Win8.1 in this behavior?  As I said, the problem didn't happen until I repointed the app...  Seems like ultimately something here changed for the worse.

    Thanks again for looking into all of this,
    Rob


    • Edited by Rob Skoon Wednesday, November 27, 2013 7:17 AM Add text
    • Marked as answer by Rob Skoon Wednesday, January 8, 2014 1:15 AM
    Wednesday, November 27, 2013 7:13 AM
  • Hi Rob - it's an interesting point that your app only starts working when you add the background element.  I will file a bug on this for our development team to look into. but for now, I am going to make James' response as the answer.  As far as what changed... lots of stuff. :-)


    Matt Small - Microsoft Escalation Engineer - Forum Moderator
    If my reply answers your question, please mark this post as answered.

    NOTE: If I ask for code, please provide something that I can drop directly into a project and run (including XAML), or an actual application project. I'm trying to help a lot of people, so I don't have time to figure out weird snippets with undefined objects and unknown namespaces.

    Thursday, December 5, 2013 4:46 PM
    Moderator