用于聚焦控件的覆盖层






4.43/5 (5投票s)
这应有助于提高可用性

介绍
我一直在思考如何提高可用性的可能性,其中一个想法是“聚焦”到一个控件上,向用户展示他/她可以在哪里进行操作。
Using the Code
使用方法非常简单。在添加了对库的引用后,只需编写如下代码:
var overlay = new Focuser.FocusOverlay<TextBox>(this.Container, this.Test);
overlay.Show();
要隐藏在 mouseclick
上的叠加层,您的代码应如下所示
overlay.MouseDown += new MouseButtonEventHandler((sender2, e2) =>
{
overlay.Hide();
this.Test = (TextBox)overlay.CloneBack()
});
CloneBack
函数用显示在叠加层中的控件(即克隆)替换原始控件。如果您希望保留对控件所做的更改,同时在叠加层中显示它,则需要调用此函数。
重要提示:如果您有一个变量保存对控件的引用(通常情况下,如果您为控件指定了名称),则需要重新分配此变量!否则,引用将失效。
背景
叠加层是一个 Adorner
,您可以在此了解更多信息。
要在 Adorner
中使用控件,必须重写 Adorner
类中的几个函数,即 VisualChildrenCount
、GetVisualChild
、MeasureOverride
和 ArangeOverride
。并且 - 您需要使用 AddLogicalChild
和 AddVisualChild
函数设置子项。
子项不是聚焦的控件本身,而是一个包含控件的 Canvas
。这是为了将控件精确地放置在其原始位置。可以这样找到绝对原始位置
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);
如您所见,使用 TransformToAncestor
函数找到位置,该函数返回一个 GeneralTransforum
。然后您需要从位置中减去边距,因为它也被克隆了。
要确定控件的宽度和高度,使用其 ActualWidth
和 ActualHeight
属性。
通过定时器更新位置,以便在窗口调整大小后保持最新。您可以在演示应用程序中测试这一点。
要聚焦的控件必须是 FrameworkElement
,因为该类包含 Parent
属性,该属性用于将原始控件替换为克隆。
只有当控件包含在 Panel
或 ItemsControl
中时,这才能工作。代码如下所示
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;
关注点
克隆是以一种有趣的方式完成的,实际上是我从互联网上获得的
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);
这可能不是非常优雅,但它有效.. ;-)。
历史
- 2008年9月24日:创建文章