An alternative way to create Adorner Layers in Windows 8 App

Article ID: 2770998
Expand all | Collapse all

On This Page

About Author:

Collapse this tableExpand this table
Collapse this imageExpand this image
2401266
Leo Lorenzo Luis is a Microsoft MVP, he has also been a Microsoft Student Partner from 2009 to 2011, and became a Worldwide Imagine Cup Finalist to represent the Philippines for 2011 that was held in New York, United States. He is passionate in developing applications in the .NET Framework and has been helping the community to share his expertise and knowledge about the technology. More about Leo on his website http://www.luisleo.net

Summary

An Adorner is a custom FrameworkElement that is bound to a UIElement. Adorners are rendered in an AdornerLayer, which is rendering surface that is always on top of the adorned element or a collection of adorned elements. Rendering of an adorner is independent from rendering of the UIElement that the adorner is bound to. An adorner is typically positionde relative to the element to which it is bound, using the standard 2-D coordinate origin located at the upper-left of the adorned element.


Common applications for adorners include:

  • Adding functional handles to a UIElement that enable a user to manipulate the element in some way (resize, rotate, reposition, etc).
  • Provide visual feedback to indicate various states, or in response to various events.
  • Overlay visual decorations on a UIElement.
  • Visually mask or override part or all of a UIElement.

This step-by-step article shows you how to create a substitute implementation of Adorner in Windows 8 development.

Requirements

  • Microsoft Visual Studio .NET 2012
  • Familiar with C# and XAML

Create a user interface


1. Start Microsoft Visual Studio 2012, click File, click New, and then click Project.

2. In the New Project dialog box, expand Visual C#, click Windows Store, and then click Blank App (XAML). Name the project as Popups.

3. In the MainPage.xaml, create the user interface and add the code to be
<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<TextBox Name="sampleTextBox" Width="600" Text="Lorem Ipsum" Height="150" />
<Button Name="addHighlightBtn" Content="Add highlight" Margin="383,304,0,42" Click="Button_Click_1"/>
<Grid x:Name="secondGrid" Grid.Row="2" HorizontalAlignment="Center" VerticalAlignment="Top">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Text="Name"/>
<TextBlock Grid.Row="1" Text="Address"/>
<TextBlock Grid.Row="2" Text="School"/>

<TextBox Grid.Column="1" Grid.Row="0"/>
<TextBox Grid.Column="1" Grid.Row="1"/>
<TextBox Grid.Column="1" Grid.Row="2"/>
</Grid>
</Grid>


4. The expected output for the user interface should look like this

Collapse this imageExpand this image
Expected output


Adding event handlers to show a UI Element on top of the existing UI on the screen

1. Add the event handler behind the code for the 'addHighlightBtn' the AddHighlight method is already defined on the XAML for the click event.

private void AddHighlight(object sender, RoutedEventArgs e)
{
var popUp = new Popup();
var rectangle = new Rectangle()
{
Fill = new SolidColorBrush(Colors.Yellow), Opacity = 0.5, Width = sampleTextBox.Width, Height = sampleTextBox.Height
};
popUp.Child = rectangle;

var transform = sampleTextBox.TransformToVisual(Window.Current.Content);
var point = transform.TransformPoint(new Point(0, 0));
popUp.HorizontalOffset = point.X;
popUp.VerticalOffset = point.Y;
popUp.IsOpen = true;
}

2. Popup will be the class that you will mostly encounter when creating a UI Element that you want to place on top of your screen. For example, creating settings pane, or you just simply want to make floating controls on top of each other.

3. After adding the code, every time you click the button it should do a highlight on the textbox. a simple rectangle is shown to simulate a highlight functionality.

4. We want to also simulate removing the highlight when the user clicks on the rectangle. Add this at the end of the last line before closing the method

rectangle.PointerPressed += popUp_PointerPressed;

5. Create a method called 'popUp_PointerPressed' and handle the pointer press and closes the pop up

void popUp_PointerPressed(object sender, PointerRoutedEventArgs e)
{
var popup = sender as Rectangle;
if (popup != null)
{
var popUp = popup.Parent as Popup;
if (popUp != null) popUp.IsOpen = false;
}
}


6. Run the build and click the add highlight button. You should be able to see a yellow border on top of the textbox that simulates a highlighting functionality.

Collapse this imageExpand this image
Expected output


Other use for pop up or putting some user control on top of a user control.

1. Usually, I create an attach property for creating an adorner, say adding a required asterisk on fields label.

2. In this project, we will try to create pop up that has a textblock in it that contains "*" in red color.

3. In the constructor, add an event handler for the Loaded event.


public MainPage()
{
this.InitializeComponent();
this.Loaded += MainPage_Loaded;
}
4. Add a MainPage_Loaded method to handle the event and add a method called CreateRequiredFieldUI that will create a pop up that has a textblock in it and gets the current point from the Current Window's Content and set the position of the pop up. I added -10 just to move the pop up a little away from the actual point that it will get.

void MainPage_Loaded(object sender, RoutedEventArgs e)
{
CreateRequiredFieldUI();
}

private void CreateRequiredFieldUI()
{
foreach (var child in secondGrid.Children)
{
if(child is TextBlock)
{
var popUp = new Popup();
popUp.Child = new TextBlock() { Text = "*", Foreground = new SolidColorBrush(Colors.Red) };
var transform = child.TransformToVisual(Window.Current.Content);
var point = transform.TransformPoint(new Point(0, 0));
popUp.HorizontalOffset = point.X - 10;
popUp.VerticalOffset = point.Y;
popUp.IsOpen = true;
}
}
}

5. Build and run the application, you should be able to see now some '*' beside the field labels.


Collapse this imageExpand this image
Output



Handling window size changes

1. Most of the time, user has the ability to change its resolution. For example, the user presses the home button to change the resolution and went back to the application. The textblock won't react to the changes and the position will be wrong.

2. In the constructor of the MainPage.xaml.cs, add this line of code to handle the Window size

Window.Current.SizeChanged += Current_SizeChanged;Window.Current.SizeChanged += Current_SizeChanged;


3. Add the Current_SizeChanged method, and just call the CreateRequiredFieldUI();

void Current_SizeChanged(object sender, WindowSizeChangedEventArgs e)
{
CreateRequiredFieldUI();
}


4. Run and build the application, you should be able to see the final output like this and try changing your screen resolution and it should re-create the textblock.


Collapse this imageExpand this image
2771051


Notes

1. Changing resolution will leave the previous textblock pop up's in the screen. Need to add some logic that will remove the pop ups from the screen and re-create them.

2. When using the TransformToVisual and TransformPoint to get the user control element points. Do get it through the Constructor, use the Loaded event so the controls are already positioned or else you will get the {0, 0} point when you do it in the constructor.

Community Solutions Content Disclaimer

MICROSOFT CORPORATION AND/OR ITS RESPECTIVE SUPPLIERS MAKE NO REPRESENTATIONS ABOUT THE SUITABILITY, RELIABILITY, OR ACCURACY OF THE INFORMATION AND RELATED GRAPHICS CONTAINED HEREIN. ALL SUCH INFORMATION AND RELATED GRAPHICS ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. MICROSOFT AND/OR ITS RESPECTIVE SUPPLIERS HEREBY DISCLAIM ALL WARRANTIES AND CONDITIONS WITH REGARD TO THIS INFORMATION AND RELATED GRAPHICS, INCLUDING ALL IMPLIED WARRANTIES AND CONDITIONS OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, WORKMANLIKE EFFORT, TITLE AND NON-INFRINGEMENT. YOU SPECIFICALLY AGREE THAT IN NO EVENT SHALL MICROSOFT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY DIRECT, INDIRECT, PUNITIVE, INCIDENTAL, SPECIAL, CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF USE, DATA OR PROFITS, ARISING OUT OF OR IN ANY WAY CONNECTED WITH THE USE OF OR INABILITY TO USE THE INFORMATION AND RELATED GRAPHICS CONTAINED HEREIN, WHETHER BASED ON CONTRACT, TORT, NEGLIGENCE, STRICT LIABILITY OR OTHERWISE, EVEN IF MICROSOFT OR ANY OF ITS SUPPLIERS HAS BEEN ADVISED OF THE POSSIBILITY OF DAMAGES.

Properties

Article ID: 2770998 - Last Review: October 26, 2012 - Revision: 5.0
Keywords: 
KB2770998

Give Feedback

 

Contact us for more help

Contact us for more help
Connect with Answer Desk for expert help.
Get more support from smallbusiness.support.microsoft.com