1

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

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

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

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

所以解决方案是在我的 BusyIndi​​cator 设置为 falseNameTextBox 之后调用焦点。我的想法是创建一个可重用的 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并绑定到不同的控件,并在他们自己的 ViewModel 中适当地启用焦点,假设他们的视图具有初始BusyIndicator活动状态。

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

设置属性 'foo.Controls.EnhancedBusyIndi​​cator.ControlToFocusOn' 引发异常。[行:45 位置:26]

我正在尝试的这个解决方案会起作用吗?如果是这样,到目前为止我所拥有的有什么问题(无法设置ControlToFocusOn属性)?


更新 1

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

“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

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

4

2 回答 2

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变得忙碌而不是再次忙碌,焦点将不会转到控件;这仅在初始加载时发生。

如果您想让EnhancedBusyIndicator焦点转移到ControlToFocusOn另一个时间,请添加另一个属性,AllowedToFocus

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

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

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

于 2012-01-18T22:24:53.013 回答
0

@Matt,不确定

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

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

于 2012-01-13T23:11:29.060 回答