Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

An Overlay to Focus on Control

0.00/5 (No votes)
24 Sep 2008 1  
This should help in improving usability

Introduction 

I was thinking about possibilities to improve usability and one of my ideas was to "focus" on a control to show the user where s/he can do something. 

Using the Code

The usage is pretty simple. After adding a reference to the library, just type some code that looks like this: 

var overlay = new Focuser.FocusOverlay<TextBox>(this.Container, this.Test);
overlay.Show();	 

To hide the overlay on mouseclick, your code should look like this:

overlay.MouseDown += new MouseButtonEventHandler((sender2, e2) =>
    {
        overlay.Hide();
        this.Test = (TextBox)overlay.CloneBack() 
    }); 

The CloneBack function replaces the original control by the one that is shown in the overlay (which is a clone). You need to call this function if you want to keep the changes made to the control while showing it in the overlay.

Important: If you have a variable keeping a reference to the control, which is usually the case if you have given a name to the control, you need to reassign this variable! Otherwise, the reference is out-of-date.

Background

The overlay is an Adorner, which you can read more about here.

To use a control in an Adorner, one has to override several functions from the Adorner class, which are VisualChildrenCount, GetVisualChild, MeasureOverride and ArangeOverride. And - you have to set the child using the AddLogicalChild and AddVisualChild functions.

The child is not the focused control itself, but a Canvas containing the control. This is needed to place the control exactly at its original position. The absolute original position can be found out like this:

var pos = this.FocusedControl.TransformToAncestor(this.Target).Transform(new Point());
 
//Subtract margin because the margin is also cloned 
pos -= new Vector(this.FocusedControlClone.Margin.Left, 
	this.FocusedControlClone.Margin.Top);  

As you can see, the position is found out using the TransformToAncestor function, which returns a GeneralTransforum. Then you have to subtract the margin from the position because it is also cloned.
To find out the width and height of the control, its ActualWidth and ActualHeight property are used.

The position is updated by a timer to stay up-to-date when the window is resized. You can test this in the demo application.

The control to focus on must be a FrameworkElement, because this is the class containing the Parent-property which is needed to replace the original control by the clone.

That only works if the control is contained by a Panel or ItemsControl. The code looks like this:

this.Canvas.Children.Remove(this.FocusedControlClone);
//Exchange control
if (this.FocusedControl.Parent is Panel)
{
    var parent = this.FocusedControl.Parent as Panel;
    parent.Children.Remove(this.FocusedControl);
    parent.Children.Add(this.FocusedControlClone);
}
else
{
    var parent = this.FocusedControl.Parent as ItemsControl;
    var index = parent.Items.IndexOf(this.FocusedControl);
    parent.Items.Remove(this.FocusedControl);
    parent.Items.Insert(index, this.FocusedControlClone);
}

//Update reference to original control
this.FocusedControl = this.FocusedControlClone; 
//Remove reference to clone, because this is the original now 
this.FocusedControlClone = null; 

Points of Interest

The cloning is done in an interesting way that I actually got from the internet:

if (original == null)
    return null;

string s = XamlWriter.Save(original);
StringReader stringReader = new StringReader(s);
XmlReader xmlReader = XmlTextReader.Create(stringReader, new XmlReaderSettings());   

return (T)XamlReader.Load(xmlReader); 

This might not be very elegant, but it works.. ;-).

History

  • 24.09.08: Article created

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here