2012-01-13 131 views
1

我有一个要求,即在加载新视图时专注于特定的文本框。将用户控件绑定到自定义BusyIndi​​cator控件

的解决方案是这一行的代码添加到装载的事件的看法:

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

所以这个工作了一个观点,而不是其他。我花了一些时间调试问题,并意识到我正在处理的新视图有一个BusyIndi​​cator,它将焦点从所有控件中移除,因为BusyIndi​​cator在OnLoaded事件之后被设置为true和false。

所以解决的办法是在后将焦点调用到NameTextBox我的BusyIndi​​cator已被设置为false。我的想法是创建一个可重用的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文件,没有问题:

<my:EnhancedBusyIndicator 
    ControlToFocusOn="{Binding ElementName=NameTextBox}" 
    RemoteFocusIsEnabled="{Binding IsRemoteFocusEnabled}" 
    IsBusy="{Binding IsDetailsBusyIndicatorActive}" 
... 
>  
... 
    <my:myTextBox (this extends TextBox) 
     x:Name="NameTextBox" 
    ... 
    /> 
... 
</my:EnhancedBusyIndicator> 

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

不过,我得到这个例外视图加载时:

设置属性“foo.Controls.EnhancedBusyIndi​​cator.ControlToFocusOn”引发了异常。 [Line:45 Position:26]

我想尝试这个解决方案吗?如果是这样,到目前为止我有什么问题(不能设置ControlToFocusOn属性)?


更新1

我安装了Visual Studio 10点的工具为Silverlight 5和导航到新视图时,有一个更好的错误消息。现在我格特此错误消息:

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

另外,我觉得我需要更改此控件的DataContext。在代码隐藏构造函数中,DataContext被设置为我的ViewModel。我尝试添加一个DataContext属性的EnhancedBusyIndicator,但没有奏效:

<my:EnhancedBusyIndicator 
    DataContext="{Binding RelativeSource={RelativeSource Self}}" 
    ControlToFocusOn="{Binding ElementName=NameTextBox}" 
    RemoteFocusIsEnabled="{Binding IsRemoteFocusEnabled}" 
    IsBusy="{Binding IsDetailsBusyIndicatorActive}" 
... 
> 

更新2

我需要改变UserControlControl,因为我会希望将焦点设置到TextBox对象(实现Control)。但是,这并不能解决问题。

回答

0

如果没有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消失后:

<my:EnhancedBusyIndicator 
    ControlToFocusOn="{Binding ElementName=NameTextBox}" 
    ... 
> 
    ... 
</my:EnhancedBusyIndicator> 

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

就是这样。每次我们导航到页面时,此控件都会获得焦点。当我们在页面上时,如果EnhancedBusyIndicator变得忙碌而不是忙碌,焦点不会去控制;这只发生在初始加载时。

如果你想允许EnhancedBusyIndicator集中到ControlToFocusOn另一个时间,添加其他财产,AllowedToFocus

<my:EnhancedBusyIndicator 
    ControlToFocusOn="{Binding ElementName=NameTextBox}" 
    AllowedToFocus="{Binding IsAllowedToFocus}" 
    ... 
> 
    ... 
</my:EnhancedBusyIndicator> 

AllowedToFocus设置为true,接下来的时间,从繁忙的EnhancedBusyIndicator切换到不旺,重点将转到ControlToFocusOn

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

0

@马特,不知道

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

将在Silverlight 5的工作,你有没有试过结合它作为一个静态资源?

+0

我实际上使用Silverlight 4;我只是通过使用适用于Silverlight 4的Visual Studio 10 Tools for Silverlight 5获得了更好的错误消息,该消息发布在“Update 1”中。我没有尝试将其作为静态资源进行绑定。我会试一试。 – 2012-01-16 19:48:45