Reputation: 11
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
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
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