user3259346
user3259346

Reputation: 11

How to make mouse wheel primary source of user interaction in UWP?

I have a UWP app with lots of buttons, checkboxes, etc. In this app, I want to make the MOUSE WHEEL the primary source of user interaction. In other words, once the app runs, ideally the user should be able to navigate through xaml controls(buttons, checkboxes, etc) ONLY USING MOUSE WHEEL. How this is possible?

note 1: by default, when the app runs, mouse cursor appears and it is possible to navigate in the UI using mouse. not interested in this.

note 2: keyboard tab is not working by default to navigate.

Upvotes: 0

Views: 414

Answers (2)

Nico Zhu
Nico Zhu

Reputation: 32775

deally the user should be able to navigate through xaml controls(buttons, checkboxes, etc) ONLY USING MOUSE WHEEL. How this is possible?

Sure, you could use PointerWheelChanged event to monitor current CoreWindow mouse wheel.

CoreWindow.GetForCurrentThread().PointerWheelChanged += MainPage_PointerWheelChanged;

Then you could get the MouseWheelDelta property value from the PointerPointProperties object. The rest is the tedious calculation process. I have realized this with the following code.

public MainPage()
{
    this.InitializeComponent();
    CoreWindow.GetForCurrentThread().PointerWheelChanged += MainPage_PointerWheelChanged;
    this.Loaded += MainPage_Loaded;
}

private void MainPage_Loaded(object sender, RoutedEventArgs e)
{   // RootLayout is Grid name.
    childrenCount = RootLayout.Children.Count;
}

private int childrenCount; // sub items count 
private int index; // index of focus control
private bool IsFirt = true; // first use flag
private void MainPage_PointerWheelChanged(CoreWindow sender, PointerEventArgs args)
{
    //get mouse wheel delta
    var value = args.CurrentPoint.Properties.MouseWheelDelta;

    if (IsFirt)
    {
        switch (value)
        {
            case 120:

                index = childrenCount;
                if (index == 0)
                {
                    index = childrenCount - 1;
                }
                else
                {
                    index--;
                }
                break;

            case -120:

                index = -1;

                if (index == childrenCount - 1)
                {
                    index = 0;
                }
                else
                {
                    index++;
                }
                break;

        }

        IsFirt = false;
    }
    else
    {
        switch (value)
        {
            case 120:

                if (index == 0)
                {
                    index = childrenCount - 1;
                }
                else
                {
                    index--;
                }

                break;

            case -120:

                if (index == childrenCount - 1)
                {
                    index = 0;
                }
                else
                {
                    index++;
                }

                break;
        }

    }
    // focus control with index
    var element = RootLayout.Children[index] as Control;
    element.Focus(FocusState.Keyboard);

}

note 2: keyboard tab is not working by default to navigate.

You could disable Tab navigation in PreviewKeyDown event hender that subscribed by Window.Current.Content. Then determine Tab key pressed set e.Handled = true.

Window.Current.Content.PreviewKeyDown += Content_PreviewKeyDown;

private void Content_PreviewKeyDown(object sender, KeyRoutedEventArgs e)
{        
    e.Handled = e.Key == VirtualKey.Tab ? true : false;
}

The above code will ignore Tab pressed in current content.

And this is code sample that you could refer to.

Upvotes: 1

Josef Lintz
Josef Lintz

Reputation: 32

I don't see any way that isn't "Hackey" what would do, I'd make an event that captures the left/right mouse clicks and returns immediately.

And for every control that will be user-intractable you can bind a command using the command manager to only accept middle mouse input or create an event when the user clicks the middle mouse button.

I will be happy to create some examples if you don't understand something.

Lets take the Mainwindow view and add an event at the top level of the window hierarchy

<Window x:Class="test.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:test"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800"

        <!-- This event captures every mouse down action that is clicked 
             Inside the window -->
        PreviewMouseDown="Window_PreviewMouseDown">

    <Grid>

    </Grid>
</Window>

Code behind of MainWindow

        /// <summary>
        /// This event will also capture any event, But this time you can check if the mouse button clicked is the middle mouse.           /// For now we will just return out of the method
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Window_PreviewMouseDown(object sender, MouseButtonEventArgs e)
        {
             // If the pressed mouse button is either the left or right button
            if(e.ChangedButton == MouseButton.Left || e.ChangedButton == MouseButton.Right)
            {
                // Exit out of the method
                return;
            };
        }

/// <summary>
        /// This event will capture every mouse down event, You can add any logic to it.
        /// For now we will just return out of the method
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
    private void Button_MouseWheel(object sender, MouseButtonEventArgs e)
        {
            // If the pressed mouse button is the middle
            if(e.ChangedButton == MouseButton.Middle)
            {
                // do stuff...
            };
        }

Different Control

<!-- This is what you normally do -->
    <Button Click="Button_Click"/>
    <!-- Or -->
    <Button Command="{Binding MyComamnd}"/>

    <!-- This you will need to do for every interactable control -->
    <Button MouseDown="Button_MouseWheel"/>
    <!-- Or -->
    <Button>
        <!-- Bind to an MVVM input command -->
        <Button.InputBindings>
            <MouseBinding Command="{Binding MyCommand}"
                          MouseAction="MiddleClick"/>
        </Button.InputBindings>
    </Button>

To make a ScrollViewer

<ScrollViewer VerticalScrollBarVisibility="Visible">

        <!-- Use any kind of item panel here, I am using a stack panel 
             But you can also use a grid with a Grid.RowDefenition --> 
        <StackPanel>

            <Button Height="50" MouseDown="Button_MouseDown"/>
            <Button Height="50"/>
            <Button Height="50"/>
            <Button Height="50"/>
            <Button Height="50"/>

        </StackPanel>
    </ScrollViewer>

Upvotes: 0

Related Questions