none
[UWP] Selection border over an uielement

    Question

  • Hello,

    I want to draw selection border over any UIElement. For example

    When I click on a TextBlock, I want to draw selection border over it. This selection border should allows scaling.

    The selection border should be drawn with dotted line. In the middle of the right line of the border should be placed a smal rectangle.

    When I press the rectangle, and move mouse selected object should be scaled.

    How to code such functionality?

    Monday, March 4, 2019 2:43 PM

All replies

  • Hi,

    Based on your requirements, there is no build-in controls could do that. So a possible way is to create a custom container that already drawn in dotted line. And it could be controlled to show or hidden when the target element is clicked. I remember there is a similar question there on StackOverflow and someone had already created the custom control. You could open favorite engine and search for "uwp- Draw dotted border" and take a look at that.

    Best regards,

    Roy


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Tuesday, March 5, 2019 8:03 AM
    Moderator
  • Hello,

    Actually there is build in functionality that allow to draw visuals over control. It is Visual layer 

    Bellow you can find code which draw selection border over TextBlock but it can be any UIElement.

      <Grid x:Name="RootGrid">
            <TextBlock x:Name="TextBlockControl" 
                       Text="Hello World" HorizontalAlignment="Left"
                       Margin="552,319,0,0" VerticalAlignment="Top" Height="80" Width="275"/>
            <Button 
                Content="Select TextBlock" HorizontalAlignment="Left"
                Margin="862,683,0,0" VerticalAlignment="Top" 
                Height="111" Width="236" Click="OnSelectTextBlock"/>
            <Button Content="Clear selection" 
                    HorizontalAlignment="Left"
                    Margin="552,683,0,0" Click="OnDeselectTextBlock"
                    VerticalAlignment="Top" Height="111" Width="225"/>
    
        </Grid>
    using System.Collections.Generic;
    using System.Numerics;
    using Windows.UI;
    using Windows.UI.Composition;
    using Windows.UI.Xaml;
    using Windows.UI.Xaml.Controls;
    using Windows.UI.Xaml.Hosting;

    public sealed partial class MainPage : Page { public MainPage() { this.InitializeComponent(); } private void OnSelectTextBlock(object sender, RoutedEventArgs e) { float tickSize = 3f; float tickMargin = 10f; var width = 2 * tickSize + (float)TextBlockControl.Width; var height = 2 * tickSize + (float)TextBlockControl.Height; this.CreateUIElementSelectionBorder(this.TextBlockControl, height, width, tickSize, tickMargin); } private void OnDeselectTextBlock(object sender, RoutedEventArgs e) { ElementCompositionPreview.SetElementChildVisual(this.TextBlockControl, null); } private void CreateUIElementSelectionBorder(UIElement element, float height, float width, float tickSize, float tickMargin) { var uiElementVisual = ElementCompositionPreview.GetElementVisual(element); var compositor = uiElementVisual.Compositor; var root = compositor.CreateContainerVisual(); ElementCompositionPreview.SetElementChildVisual(element, root); int horizontalDotsCount = (int)(width / (tickSize + tickMargin)) + 1; int verticalDotsCount = (int)(height / (tickSize + tickMargin)) + 1; var topPanel = CreatePanel( compositor, size: new Vector2(width, tickSize), offest: new Vector3(new Vector2(-tickSize, -tickSize), 0), dots: CreateDottedLine(compositor, horizontalDotsCount, tickSize, tickMargin, Direction.Horizontal)); var bottomPanel = CreatePanel( compositor, size: new Vector2(width, tickSize), offest: new Vector3(new Vector2(-tickSize, height + tickSize), 0), dots: CreateDottedLine(compositor, horizontalDotsCount, tickSize, tickMargin, Direction.Horizontal)); var rightPanel = CreatePanel( compositor, size: new Vector2(tickSize, height), offest: new Vector3(new Vector2(width + tickSize, -tickSize), 0), dots: CreateDottedLine(compositor, verticalDotsCount, tickSize, tickMargin, Direction.Vertical)); var leftPanel = CreatePanel( compositor, size: new Vector2(tickSize, height), offest: new Vector3(new Vector2(-tickSize, -tickSize), 0), dots: CreateDottedLine(compositor, verticalDotsCount, tickSize, tickMargin, Direction.Vertical)); root.Children.InsertAtTop(topPanel); root.Children.InsertAtTop(bottomPanel); root.Children.InsertAtTop(rightPanel); root.Children.InsertAtTop(leftPanel); } private Visual CreatePanel(Compositor compositor, Vector2 size, Vector3 offest, List<Visual> dots) { var panel = compositor.CreateSpriteVisual(); panel.Size = size; panel.Offset = offest; foreach (var item in dots) { panel.Children.InsertAtTop(item); } return panel; } private List<Visual> CreateDottedLine(Compositor compositor, int count, float size, float margin, Direction dirrection) { List<Visual> dots = new List<Visual>(); for (int i = 0; i < count; i++) { var visual = compositor.CreateSpriteVisual(); visual.Opacity = 0.5f; if(dirrection == Direction.Horizontal) { visual.Offset = new Vector3(new Vector2((size + margin) * i, 0), 0); } else { visual.Offset = new Vector3(new Vector2(0, (size + margin) * i), 0); } visual.Brush = compositor.CreateColorBrush(Colors.Red); visual.Size = new Vector2(size); dots.Add(visual); } return dots; } private enum Direction { Horizontal, Vertical } }




    Make the community better together

    • Proposed as answer by Tuman_ Thursday, March 7, 2019 8:09 AM
    • Unproposed as answer by BitSmithy Tuesday, April 16, 2019 3:16 PM
    Tuesday, March 5, 2019 12:36 PM
  • Hi BitSmithy,

    The recommended way to change the look and feel of a built-in control is via Style and  ControlTemplate. You shouldn't have to write code to be able to facilitate the functionality you are looking for. You should be able to do everything in XAML.

    Control templates
    https://docs.microsoft.com/en-us/windows/uwp/design/controls-and-patterns/control-templates

    XAML styles
    https://docs.microsoft.com/en-us/windows/uwp/design/controls-and-patterns/xaml-styles

    Give this a go on your own and let me know if you need some additional help.

    -James

    


    Windows SDK Technologies - Microsoft Developer Services - http://blogs.msdn.com/mediasdkstuff/

    • Marked as answer by BitSmithy Tuesday, April 16, 2019 2:06 PM
    • Unmarked as answer by BitSmithy Tuesday, April 16, 2019 2:06 PM
    Tuesday, March 5, 2019 8:49 PM
    Owner
  • Hi BitSmithy,

    The recommended way to change the look and feel of a built-in control is via Style and  ControlTemplate. You shouldn't have to write code to be able to facilitate the functionality you are looking for. You should be able to do everything in XAML.

    Fine, but how to do template for my task. This looks very dificult.

    Tuesday, April 16, 2019 2:09 PM
  • Hello,

    Actually there is build in functionality that allow to draw visuals over control. It is Visual layer 

    This code is fine, and it really draws rectangle over UIElement, but I cant create a small rectangle which allows scaling UIElement. Visual class doesnt contain events which can handle mouse click, and mouse drag.

    If it is possible to add to this code such behaviors, we will be at the target.

    Tuesday, April 16, 2019 3:16 PM