truongnm truongnm - 2 months ago 25
C# Question

Hide mouse cursor and StackPanel after an idle time Windows 8.1 - Universal App

I'm writing a video player app, an Universal App (Windows 8.1 and Windows Phone 8.1) using C# and XAML. There is a very nice UX which is:


  • when the mouse is idle after a set of time, the mouse and all the controls (play, pause..) are hidden

  • when the mouse move, mouse cursor and all the controls are apppeared.



It looks exactly like the Video app on Windows 8.1, althought simple but a very nice UX.

Here is some of my controls, I put them all in a Stackpanel:

<StackPanel x:Name="MyControls"
Orientation="Horizontal" >
<Button x:Name="btnPlay"
Click="btnPlay_Click" />
<Button x:Name="btnPause"
Click="btnPause_Click" />
</StackPanel>


And my code behind for the controls:

private void btnPlay_Click(object sender, RoutedEventArgs e)
{
videoMediaElement.Play();
}

private void btnPause_Click(object sender, RoutedEventArgs e)
{
videoMediaElement.Pause();
}


So again, my question is how to do this ???


  • when the mouse is idle after a set of time, the mouse and all the controls (play, pause..) are hidden

  • when the mouse move, mouse cursor and all the controls are apppeared.



'Cause it's Universal App, I guess the solution is the same for Windows Phone 8.1, just about the controls.

Thanks in advance bros! Any comment, answers really help!

Btw, HAPPY NEW YEAH you guys!!! :D*

Answer

How about creating a DispatcherTimer to hide the StackPanel and cursor after a certain amount of time and show them whenever the pointer is moved?

    private DispatcherTimer _timer = new DispatcherTimer { Interval = TimeSpan.FromSeconds(5) };

    public MainPage()
    {
        this.InitializeComponent();
    }

    private void MainPage_PointerMoved(object sender, Windows.UI.Xaml.Input.PointerRoutedEventArgs e)
    {
        this.ShowControls();

        // restart the timer whenever the user moves the cursor
        _timer.Start();
    }

    private void Timer_Tick(object sender, object e)
    {
        this.HideControls();
    }

    private void btnPlay_Click(object sender, Windows.UI.Xaml.RoutedEventArgs e)
    {
        _timer.Tick += Timer_Tick;
        this.PointerMoved += MainPage_PointerMoved;

        _timer.Start();
    }

    private void btnPause_Click(object sender, Windows.UI.Xaml.RoutedEventArgs e)
    {
        _timer.Tick -= Timer_Tick;
        this.PointerMoved -= MainPage_PointerMoved;

        _timer.Stop();
    }

    private void HideControls()
    {
        // todo: better use animation here
        this.MyControls.Visibility = Visibility.Collapsed;

        Window.Current.CoreWindow.PointerCursor = null;
    }

    private void ShowControls()
    {
        // todo: better use animation here
        this.MyControls.Visibility = Visibility.Visible;

        Window.Current.CoreWindow.PointerCursor = new CoreCursor(CoreCursorType.Arrow, 1);
    }


Bonus

Say if you want to animate the in/out of the StackPanel. First you need to define two Storyboards in your page's xaml.

<Page.Resources>
    <Storyboard x:Name="HideAnimation">
        <DoubleAnimation Duration="0:0:0.3" To="0" Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="MyControls" d:IsOptimized="True"/>
        <DoubleAnimation Duration="0:0:0.3" To="0.6" Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.ScaleX)" Storyboard.TargetName="MyControls" d:IsOptimized="True">
            <DoubleAnimation.EasingFunction>
                <ExponentialEase EasingMode="EaseIn"/>
            </DoubleAnimation.EasingFunction>
        </DoubleAnimation>
        <DoubleAnimation Duration="0:0:0.3" To="0.6" Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.ScaleY)" Storyboard.TargetName="MyControls" d:IsOptimized="True">
            <DoubleAnimation.EasingFunction>
                <ExponentialEase EasingMode="EaseIn"/>
            </DoubleAnimation.EasingFunction>
        </DoubleAnimation>
        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.IsHitTestVisible)" Storyboard.TargetName="MyControls">
            <DiscreteObjectKeyFrame KeyTime="0">
                <DiscreteObjectKeyFrame.Value>
                    <x:Boolean>False</x:Boolean>
                </DiscreteObjectKeyFrame.Value>
            </DiscreteObjectKeyFrame>
            <DiscreteObjectKeyFrame KeyTime="0:0:0.3">
                <DiscreteObjectKeyFrame.Value>
                    <x:Boolean>True</x:Boolean>
                </DiscreteObjectKeyFrame.Value>
            </DiscreteObjectKeyFrame>
        </ObjectAnimationUsingKeyFrames>
    </Storyboard>
    <Storyboard x:Name="ShowAnimation">
        <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="MyControls">
            <SplineDoubleKeyFrame KeyTime="0:0:0.3" Value="1"/>
        </DoubleAnimationUsingKeyFrames>
        <DoubleAnimation Duration="0:0:0.3" To="1" Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.ScaleX)" Storyboard.TargetName="MyControls" d:IsOptimized="True">
            <DoubleAnimation.EasingFunction>
                <ExponentialEase EasingMode="EaseOut"/>
            </DoubleAnimation.EasingFunction>
        </DoubleAnimation>
        <DoubleAnimation Duration="0:0:0.3" To="1" Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.ScaleY)" Storyboard.TargetName="MyControls" d:IsOptimized="True">
            <DoubleAnimation.EasingFunction>
                <ExponentialEase EasingMode="EaseOut"/>
            </DoubleAnimation.EasingFunction>
        </DoubleAnimation>
        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.IsHitTestVisible)" Storyboard.TargetName="MyControls">
            <DiscreteObjectKeyFrame KeyTime="0">
                <DiscreteObjectKeyFrame.Value>
                    <x:Boolean>True</x:Boolean>
                </DiscreteObjectKeyFrame.Value>
            </DiscreteObjectKeyFrame>
            <DiscreteObjectKeyFrame KeyTime="0:0:0.3">
                <DiscreteObjectKeyFrame.Value>
                    <x:Boolean>True</x:Boolean>
                </DiscreteObjectKeyFrame.Value>
            </DiscreteObjectKeyFrame>
        </ObjectAnimationUsingKeyFrames>
    </Storyboard>
</Page.Resources>

Then you just call them instead of setting the Visibility.

    private void HideControls()
    {
        this.HideAnimation.Begin();

        Window.Current.CoreWindow.PointerCursor = null;
    }

    private void ShowControls()
    {
        this.ShowAnimation.Begin();

        Window.Current.CoreWindow.PointerCursor = new CoreCursor(CoreCursorType.Arrow, 1);
    }
Comments