Surface Dial and Windows Wheel UWP application development, dialuwp
With the release of Microsoft Surface Studio, a very eye-catching accessory in the Demo Video is Surface Dial. Dial is a new member of the Windows input device family and we classify it as a Windows Wheel device. Today, we will introduce how to develop your own applications with this magic device.
Dial is a device similar to a scroll wheel that can help users quickly enter information on computers. However, Dial is not a device designed for accurate input, in other words, if you want to click a certain point on the screen, we recommend that you use your fingers to touch the Surface Pan or mouse to complete this task. Dial is more suitable for rotating a canvas like, stroke selection and other quick operations.
The Surface Dial operation is very simple, with only three operation eventsLong press,Click, AndRotateIf the Surface Dial and Surface Studio are used together, you can use the Surface Dial screen menu for the Surface Dial menu, that is, place Dial on the Surface Studio screen and then perform operations on the Surface Dial, A menu appears around the Dial screen.
Dial itself is closely connected with windows and has built-in system tools such as adjusting the system volume, downgrading, and revoking the slave program. In addition, Dial is tightly integrated with Windows Ink. If your WUP application already uses InkCanvas and InkToolbar, Dial will automatically combine with the content in the InkToolbar, such as adjusting the angle of the ruler and the stroke size.
However, for our developers, Surface also provides APIs (UWP and Win32 versions are available here. This article focuses on the UWP version). In fact, it is very easy to develop.
First, key points
RadialControllerClass to obtain the instance through the CreateForCurrentView () static method.
RadialControllerMenuItemClass to customize the menu content. When Dial is long, the custom menu is displayed.
ButtonClickedEvent to capture Dial click events.
RotationChangedEvent to capture Dial rotation events.
ScreenContactStarted Event, capture the Dial placed on the Surface Studio event, and obtain the Dial location on the screen from the callback parameter.
ScreenContactContinuedEvent, capture the Dial placed on Surface Studio and move the location, and obtain the Dial position on the screen from the callback parameter.
ScreenContactEndedEvent to capture the Dial event from Surface Studio.
ControlLostEvent to capture the focus of the operation.
Copy the demo code on MSDN to demonstrate the usage andHow to determine the location of Dial on Surface Studio.
Xaml code
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"><Grid.RowDefinitions> <RowDefinition Height="Auto"/> <RowDefinition Height="*"/></Grid.RowDefinitions><StackPanel x:Name="HeaderPanel" Orientation="Horizontal" Grid.Row="0"> <TextBlock x:Name="Header" Text="RadialController customization sample" VerticalAlignment="Center" Style="{ThemeResource HeaderTextBlockStyle}" Margin="10,0,0,0" /></StackPanel><Grid Grid.Row="1" x:Name="RootGrid"> <Grid.RowDefinitions> <RowDefinition Height="*"/> <RowDefinition Height="*"/> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition Width="*"/> <ColumnDefinition Width="*"/> </Grid.ColumnDefinitions> <Grid x:Name="Grid0" Grid.Row="0" Grid.Column="0"> <StackPanel Orientation="Vertical" VerticalAlignment="Center" HorizontalAlignment="Center"> <!-- Slider for rotational input --> <Slider x:Name="RotationSlider0" Width="300" HorizontalAlignment="Left"/> <!-- Switch for button input --> <ToggleSwitch x:Name="ButtonToggle0" HorizontalAlignment="Left"/> </StackPanel> </Grid> <Grid x:Name="Grid1" Grid.Row="0" Grid.Column="1"> <StackPanel Orientation="Vertical" VerticalAlignment="Center" HorizontalAlignment="Center"> <!-- Slider for rotational input --> <Slider x:Name="RotationSlider1" Width="300" HorizontalAlignment="Left"/> <!-- Switch for button input --> <ToggleSwitch x:Name="ButtonToggle1" HorizontalAlignment="Left"/> </StackPanel> </Grid> <Grid x:Name="Grid2" Grid.Row="1" Grid.Column="0"> <StackPanel Orientation="Vertical" VerticalAlignment="Center" HorizontalAlignment="Center"> <!-- Slider for rotational input --> <Slider x:Name="RotationSlider2" Width="300" HorizontalAlignment="Left"/> <!-- Switch for button input --> <ToggleSwitch x:Name="ButtonToggle2" HorizontalAlignment="Left"/> </StackPanel> </Grid> <Grid x:Name="Grid3" Grid.Row="1" Grid.Column="1"> <StackPanel Orientation="Vertical" VerticalAlignment="Center" HorizontalAlignment="Center"> <!-- Slider for rotational input --> <Slider x:Name="RotationSlider3" Width="300" HorizontalAlignment="Left"/> <!-- Switch for button input --> <ToggleSwitch x:Name="ButtonToggle3" HorizontalAlignment="Left"/> </StackPanel> </Grid></Grid></Grid>
Code-behind code
Slider ActiveSlider;ToggleSwitch ActiveSwitch;Grid ActiveGrid;public MainPage(){ ... myController.ScreenContactStarted += MyController_ScreenContactStarted; myController.ScreenContactContinued += MyController_ScreenContactContinued; myController.ScreenContactEnded += MyController_ScreenContactEnded; myController.ControlLost += MyController_ControlLost; //Set initial grid for Surface Dial input. ActiveGrid = Grid0; ActiveSlider = RotationSlider0; ActiveSwitch = ButtonToggle0;}private void MyController_ScreenContactStarted(RadialController sender, RadialControllerScreenContactStartedEventArgs args){ //find grid at contact location, update visuals, selection ActivateGridAtLocation(args.Contact.Position);}private void MyController_ScreenContactContinued(RadialController sender, RadialControllerScreenContactContinuedEventArgs args){ //if a new grid is under contact location, update visuals, selection if (!VisualTreeHelper.FindElementsInHostCoordinates( args.Contact.Position, RootGrid).Contains(ActiveGrid)) { ActiveGrid.Background = new SolidColorBrush(Windows.UI.Colors.White); ActivateGridAtLocation(args.Contact.Position); }}private void MyController_ScreenContactEnded(RadialController sender, object args){ //return grid color to normal when contact leaves screen ActiveGrid.Background = new SolidColorBrush(Windows.UI.Colors.White);}private void MyController_ControlLost(RadialController sender, object args){ //return grid color to normal when focus lost ActiveGrid.Background = new SolidColorBrush(Windows.UI.Colors.White);}private void ActivateGridAtLocation(Point Location){ var elementsAtContactLocation = VisualTreeHelper.FindElementsInHostCoordinates(Location, RootGrid); foreach (UIElement element in elementsAtContactLocation) { if (element as Grid == Grid0) { ActiveSlider = RotationSlider0; ActiveSwitch = ButtonToggle0; ActiveGrid = Grid0; ActiveGrid.Background = new SolidColorBrush( Windows.UI.Colors.LightGoldenrodYellow); return; } else if (element as Grid == Grid1) { ActiveSlider = RotationSlider1; ActiveSwitch = ButtonToggle1; ActiveGrid = Grid1; ActiveGrid.Background = new SolidColorBrush( Windows.UI.Colors.LightGoldenrodYellow); return; } else if (element as Grid == Grid2) { ActiveSlider = RotationSlider2; ActiveSwitch = ButtonToggle2; ActiveGrid = Grid2; ActiveGrid.Background = new SolidColorBrush( Windows.UI.Colors.LightGoldenrodYellow); return; } else if (element as Grid == Grid3) { ActiveSlider = RotationSlider3; ActiveSwitch = ButtonToggle3; ActiveGrid = Grid3; ActiveGrid.Background = new SolidColorBrush( Windows.UI.Colors.LightGoldenrodYellow); return; } }}
Of course, there is another key point: how to create a custom menuController. Menu. Items. Add ()Add and use methodsRemove ()Method to delete a custom menu.
Note: The Surface Dial menu hereSupports 7 OptionsIf there are more than 7 Dial controls, you need to select them with floating controls. This will affect the user experience.Not recommended.
private void CreateMenuItems() { menuItems = new List<RadialControllerMenuItem> { RadialControllerMenuItem.CreateFromKnownIcon("Item0", RadialControllerMenuKnownIcon.InkColor), RadialControllerMenuItem.CreateFromKnownIcon("Item1", RadialControllerMenuKnownIcon.NextPreviousTrack), RadialControllerMenuItem.CreateFromKnownIcon("Item2", RadialControllerMenuKnownIcon.Volume), RadialControllerMenuItem.CreateFromIcon("Item3", RandomAccessStreamReference.CreateFromUri(new Uri("ms-appx:///Assets/Item3.png"))), RadialControllerMenuItem.CreateFromIcon("Item4", RandomAccessStreamReference.CreateFromUri(new Uri("ms-appx:///Assets/Item4.png"))), RadialControllerMenuItem.CreateFromIcon("Item5", RandomAccessStreamReference.CreateFromUri(new Uri("ms-appx:///Assets/Item5.png"))) }; sliders = new List<Slider> { Slider0, Slider1, Slider2, Slider3, Slider4, Slider5 }; toggles = new List<ToggleSwitch> { Toggle0, Toggle1, Toggle2, Toggle3, Toggle4, Toggle5 }; for (int i = 0; i < menuItems.Count; ++i) { RadialControllerMenuItem radialControllerItem = menuItems[i]; int index = i; radialControllerItem.Invoked += (sender, args) => { OnItemInvoked(index); }; } } private void OnItemInvoked(int selectedItemIndex) { activeItemIndex = selectedItemIndex; } private void AddItem(object sender, RoutedEventArgs e) { RadialControllerMenuItem radialControllerMenuItem = GetRadialControllerMenuItemFromSender(sender); if (!Controller.Menu.Items.Contains(radialControllerMenuItem)) { Controller.Menu.Items.Add(radialControllerMenuItem); } } private void RemoveItem(object sender, RoutedEventArgs e) { RadialControllerMenuItem radialControllerMenuItem = GetRadialControllerMenuItemFromSender(sender); if (Controller.Menu.Items.Contains(radialControllerMenuItem)) { Controller.Menu.Items.Remove(radialControllerMenuItem); } } private void SelectItem(object sender, RoutedEventArgs e) { RadialControllerMenuItem radialControllerMenuItem = GetRadialControllerMenuItemFromSender(sender); if (Controller.Menu.Items.Contains(radialControllerMenuItem)) { Controller.Menu.SelectMenuItem(radialControllerMenuItem); PrintSelectedItem(); } }
For menu options, we recommend that you use a 64x64 pixel PNG transparent image, but the minimum pixel value of 44x44 is also supported.
Note: The black border is used to make the icons visible in high contrast mode.
The following is the example code of Microsoft: RadialControlle.
I hope that the summary will help you, and you are welcome to communicate with me or @ Wang Bo _ Nick on Sina Weibo.