2012-01-13 184 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