将UserControl绑定到自定义BusyIndi​​cator控件

在加载新视图时,我需要关注特定的文本框。

解决方案是将这行代码添加到视图的OnLoaded事件中:

Dispatcher.BeginInvoke(() => { NameTextBox.Focus(); }); 

所以这适用于一种观点,而不是另一种观点。 我花了一些时间来调试问题并意识到我正在处理的新视图有一个BusyIndi​​cator,它将焦点从所有控件上移开,因为BusyIndi​​cator被设置为true而在OnLoaded事件之后出现了false。

因此解决方案是在将NameTextBox设置为false 后将焦点调用到NameTextBox 。 我的想法是创建一个可重用的BusyIndi​​cator控件来处理这个额外的工作。 但是,我在MVVM中无法做到这一点。

我首先对工具包进行了简单的扩展:BusyIndi​​cator:

 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文件中没有问题:

  ...  ...  

因此,我的想法是在我的ViewModel IsRemoteFocusEnabled设置为true(我在ViewModel中将IsBusy设置为false后执行此操作),焦点将设置为NameTextBox 。 如果它有效,其他人可以使用EnhancedBusyIndicator并绑定到不同的控件,并在他们自己的ViewModel中适当地启用焦点,假设他们的视图有一个初始的BusyIndicator活动。

但是,加载视图时出现此exception:

设置属性’foo.Controls.EnhancedBusyIndi​​cator.ControlToFocusOn’抛出exception。 [线路:45位置:26]

这个解决方案我试图工作吗? 如果是这样,到目前为止我有什么问题(无法设置ControlToFocusOn属性)?


更新1

我安装了适用于Silverlight 5的Visual Studio 10工具,并在导航到新视图时收到了更好的错误消息。 现在我发出此错误消息:

“System.ArgumentException:System.Windows.Data.Binding类型的对象无法转换为System.Windows.Controls.UserControl类型”

此外,我认为我需要更改此控件的DataContext。 在代码隐藏构造函数中,DataContext设置为我的ViewModel。 我尝试将一个DataContext属性添加到EnhancedBusyIndicator ,但这不起作用:

  

更新2

我需要将UserControl更改为Control因为我希望将焦点设置为TextBox对象(实现Control )。 但是,这并没有解决问题。

@Matt,不确定

 DataContext="{Binding RelativeSource={RelativeSource Self}}" 

将在Silverlight 5中工作,您是否尝试将其绑定为静态资源?

如果视图中没有BusyIndicator ,解决焦点问题的常用解决方案是添加代码

 Dispatcher.BeginInvoke(() => { ControlToFocusOn.Focus(); }); 

到视图的Loaded事件。 即使存在BusyIndicator ,这实际上也可以工作; 但是, BusyIndicator立即将焦点从其余的Silverlight控件上移开。 解决方案是在BusyIndicator不忙后调用控件的Focus()方法。

我能够通过制作这样的控件来解决它:

 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; } } } 

要使用它,请使用新的EnhancedBusyIndicator替换xaml中的BusyIndicator标记,并添加相应的命名空间。

在元素内添加一个新属性ControlToFocusOn ,并将其绑定到视图中的现有元素,在EnhancedBusyIndicator消失后,您希望焦点处于打开状态:

  ...  

在这种情况下,我专注于一个名为NameTextBox的文本框。

而已。 每次我们导航到页面时,此控件都会聚焦。 当我们在页面上时,如果EnhancedBusyIndicator变得忙碌并且不忙于agiain,焦点将不会转到控件; 这只发生在初始加载时。

如果要允许EnhancedBusyIndicator再次聚焦到ControlToFocusOn ,请添加另一个属性AllowedToFocus

  ...  

AllowedToFocus设置为true时,下次EnhancedBusyIndicator从忙碌切换到不忙时,焦点将转到ControlToFocusOn

加载视图时,AllowedToFocus也可以设置为false,以防止焦点转到控件。 如果将AllowedToFocus绑定到ViewModel属性,则可能需要更改BindingMode 。 默认情况下,它是OneTime