我需要在加载新视图时专注于特定的文本框。
解决方案是将这行代码添加到视图的OnLoaded事件中:
Dispatcher.BeginInvoke(() => { NameTextBox.Focus(); });
所以这适用于一种观点,但不适用于另一种观点。我花了一些时间调试问题,并意识到我正在处理的新视图有一个BusyIndicator,它将焦点从所有控件上移开,因为BusyIndicator被设置为true而在OnLoaded事件之后出现了错误。
所以解决方法是在我的BusyIndicator设置为false之后将焦点调用到NameTextBox
。我的想法是创建一个可重用的BusyIndicator控件来处理这个额外的工作。但是,我在MVVM中无法做到这一点。
我首先对工具包进行了简单的扩展:BusyIndicator:
public class EnhancedBusyIndicator : BusyIndicator
{
public UserControl ControlToFocusOn { get; set; }
private bool _remoteFocusIsEnabled = false;
public bool RemoteFocusIsEnabled
{
get
{
return _remoteFocusIsEnabled;
}
set
{
if (value == true)
EnableRemoteFocus();
}
}
private void EnableRemoteFocus()
{
if (ControlToFocusOn.IsNotNull())
Dispatcher.BeginInvoke(() => { ControlToFocusOn.Focus(); });
else
throw new InvalidOperationException("ControlToFocusOn has not been set.");
}
我将控件添加到我的XAML文件中没有问题:
<my:EnhancedBusyIndicator
ControlToFocusOn="{Binding ElementName=NameTextBox}"
RemoteFocusIsEnabled="{Binding IsRemoteFocusEnabled}"
IsBusy="{Binding IsDetailsBusyIndicatorActive}"
...
>
...
<my:myTextBox (this extends TextBox)
x:Name="NameTextBox"
...
/>
...
</my:EnhancedBusyIndicator>
所以我的想法是在我的ViewModel中将IsRemoteFocusEnabled
设置为true(我在ViewModel中将IsBusy
设置为false后执行此操作),焦点将设置为{{1} }。如果它有效,其他人可以使用NameTextBox
并绑定到不同的控件并在他们自己的ViewModel中适当地启用焦点,假设他们的视图具有初始EnhancedBusyIndicator
活动。
但是,加载视图时出现此异常:
设置属性'foo.Controls.EnhancedBusyIndicator.ControlToFocusOn'抛出异常。 [行:45位置:26]
这个解决方案我试图工作吗?如果是这样,到目前为止我有什么问题(不能设置BusyIndicator
属性)?
更新1
我为Silverlight 5安装了Visual Studio 10工具,并在导航到新视图时收到了更好的错误消息。现在我发出此错误消息:
“System.ArgumentException:System.Windows.Data.Binding类型的对象无法转换为System.Windows.Controls.UserControl类型”
另外,我认为我需要更改此控件的DataContext。在代码隐藏构造函数中,DataContext设置为我的ViewModel。我尝试将一个DataContext属性添加到ControlToFocusOn
,但这不起作用:
EnhancedBusyIndicator
更新2
我需要将<my:EnhancedBusyIndicator
DataContext="{Binding RelativeSource={RelativeSource Self}}"
ControlToFocusOn="{Binding ElementName=NameTextBox}"
RemoteFocusIsEnabled="{Binding IsRemoteFocusEnabled}"
IsBusy="{Binding IsDetailsBusyIndicatorActive}"
...
>
更改为UserControl
,因为我希望将焦点设置为Control
个对象(实现TextBox
)。但是,这并没有解决问题。
答案 0 :(得分:0)
@Matt,不确定
DataContext="{Binding RelativeSource={RelativeSource Self}}"
将在Silverlight 5中运行,您是否尝试将其绑定为静态资源?
答案 1 :(得分:0)
如果视图中没有BusyIndicator
,解决焦点问题的常用解决方案是添加代码
Dispatcher.BeginInvoke(() => { ControlToFocusOn.Focus(); });
到视图的Loaded
事件。这实际上即使在BusyIndicator
存在的情况下也能正常工作;但是,BusyIndicator
立即将焦点从其余的Silverlight控件上移开。解决方案是在Focus()
不忙后调用控件的BusyIndicator
方法。
我能够通过制作这样的控件来解决它:
public class EnhancedBusyIndicator : BusyIndicator
{
public EnhancedBusyIndicator()
{
Loaded += new RoutedEventHandler(EnhancedBusyIndicator_Loaded);
}
void EnhancedBusyIndicator_Loaded(object sender, RoutedEventArgs e)
{
AllowedToFocus = true;
}
private readonly DependencyProperty AllowedToFocusProperty = DependencyProperty.Register("AllowedToFocus", typeof(bool), typeof(EnhancedBusyIndicator), new PropertyMetadata(true));
public bool AllowedToFocus
{
get { return (bool)GetValue(AllowedToFocusProperty); }
set { SetValue(AllowedToFocusProperty, value); }
}
public readonly DependencyProperty ControlToFocusOnProperty = DependencyProperty.Register("ControlToFocusOn", typeof(Control), typeof(EnhancedBusyIndicator), null);
public Control ControlToFocusOn
{
get { return (Control)GetValue(ControlToFocusOnProperty); }
set { SetValue(ControlToFocusOnProperty, value); }
}
protected override void OnIsBusyChanged(DependencyPropertyChangedEventArgs e)
{
base.OnIsBusyChanged(e);
if (AllowedToFocus && !IsBusy)
{
Dispatcher.BeginInvoke(() => { ControlToFocusOn.Focus(); });
AllowedToFocus = false;
}
}
}
要使用它,请使用新的BusyIndicator
替换xaml中的EnhancedBusyIndicator
标记,然后添加相应的命名空间。
在元素中添加一个新属性ControlToFocusOn
,并将其绑定到视图中的现有元素,在EnhancedBusyIndicator
消失后,您希望焦点处于打开状态:
<my:EnhancedBusyIndicator
ControlToFocusOn="{Binding ElementName=NameTextBox}"
...
>
...
</my:EnhancedBusyIndicator>
在这种情况下,我专注于一个名为NameTextBox
的文本框。
就是这样。每次我们导航到页面时,此控件都会聚焦。当我们在页面上时,如果EnhancedBusyIndicator
变得忙碌并且不忙于agiain,焦点将不会转向控件;这只发生在初始加载时。
如果您想让EnhancedBusyIndicator
再次关注ControlToFocusOn
,请添加其他媒体资源AllowedToFocus
:
<my:EnhancedBusyIndicator
ControlToFocusOn="{Binding ElementName=NameTextBox}"
AllowedToFocus="{Binding IsAllowedToFocus}"
...
>
...
</my:EnhancedBusyIndicator>
当AllowedToFocus
设置为true时,下次EnhancedBusyIndicator
从忙碌切换到不忙时,焦点将转到ControlToFocusOn
。
加载视图时,AllowedToFocus也可以设置为false,以防止焦点转到控件。如果将AllowedToFocus
绑定到ViewModel属性,则可能需要更改BindingMode
。默认情况下,它是OneTime
。