原文http://www.cnblogs.com/xiaoxueliang/archive/2010/08/08/1795128.html
Silverlight中的焦点常用设置控件的外观和键盘操作。在做模板控件时,我们常常需要捕获元素焦点状态。根据元素是否具有焦点来呈现不同的视觉状态。最近的项目中碰到一个奇怪现象:我将一个模板控件在ScrollViewer中,在MouseLeftButtonDown调用Focus时,Focus()返回true,控件会得到焦点,然而瞬间又失去焦点,导致控件无法正常获取焦点。如果将该控件放在Canvas、Grid中都能正确的获取焦点,并显示焦点视觉效果。 下面是模板控件中的示意代码:
代码
public TemplatedControl1()
{
this.DefaultStyleKey = typeof(TemplatedControl1);
}
public bool isFocused = false;
public bool IsFocused
{
get
{
return isFocused;
}
set
{
if (isFocused != value)
{
isFocused = value;
UpdateStates(true);
}
}
}
protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
{
base.OnMouseLeftButtonDown(e);
Focus();
}
protected override void OnGotFocus(RoutedEventArgs e)
{
base.OnGotFocus(e);
isFocused = true;
UpdateStates(true);
}
protected override void OnLostFocus(RoutedEventArgs e)
{
base.OnLostFocus(e);
isFocused = false;
UpdateStates(true);
}
private void UpdateStates(bool useTransitions)
{
if (isFocused)
{
VisualStateManager.GoToState(this, "Focused", useTransitions);
}
else
{
VisualStateManager.GoToState(this, "Unfocused", useTransitions);
}
}
这个问题让我觉得Silverlight的焦点不太稳定。进过观察发现,ScrollViewer通过获取MouseLeftButtonDown的路由事件,然后做了一些我们不知道的操作,导致控件失去了焦点。如何解决这个问题,这里提供两种思路:
第一种:在模板控件的重载方法OnMouseLeftButtonDown中加上e.Handled = true。 这样就阻止了ScrollViewer获取点击事件。这种方法的弊端就是也停止了OnMouseLeftButtonDown的路由。
第二种:在MouseLeftButtonUp中调用Focus()获取焦点,此方法调用在ScrollViewer发生作用之后,所以能正确的设置焦点状态。缺点是:如果模板控件已经有焦点时,点击控件,就会导致控件先失去焦点,然后在MouseLeftButtonUp事件中再得到焦点,形成无谓的视觉效果跳动。
这样焦点的问题是可以解决,不过ScrollViewer在OnMouseLeftButtonDown事件中为什么会夺取去子元素的焦点,还是不得而知。