我有一个Silverlight应用程序,它有一个包含多个TabItem的TabControl。当用户选择一个标签项时,我想将焦点设置为该TabItem中的特定控件。我该怎么做?
我尝试为TabControl的SelectionChanged
事件创建一个事件处理程序,并添加了以下代码:
private void tcTabs_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (tcTabs != null)
{
switch (tcTabs.SelectedIndex)
{
case 0:
txtTextBox1.Focus();
break;
case 1:
txtTextBox2.Focus();
break;
...
}
}
}
txtTextBox1
和txtTextBox2
是相关标签中的TextBox控件。
如果我在Focus
方法调用上设置断点,我看到当我从一个选项卡切换到另一个选项卡时它们被调用,但是当选项卡显示时控件没有聚焦。我的推测是我需要在稍后的时间拨打Focus
,但我不知道何时打电话或如何打电话。
非常感谢任何帮助。
由于
答案 0 :(得分:6)
TabControl的有趣事实:每次切换选项卡时,都会再次加载TabItem的子控件。也就是说,它的Loaded事件被提升了。所以你可以在那里附上一个事件。
那就是说,我的偏好是使用Expression SDK中提供的Trigger / Action行为,所以我可以通过XAML挂钩所有这些(对我而言,它比每次需要时附加事件感觉更可重用)。
添加对System.Windows.Interactivity.dll的引用(如果您还没有)。
使用此触发器操作子类:
using System.Windows;
using System.Windows.Controls;
using System.Windows.Interactivity;
namespace SilverlightApplication1 {
public class SetFocusAction : TriggerAction<DependencyObject> {
public static readonly DependencyProperty TargetProperty =
DependencyProperty.Register( "Target", typeof( Control ), typeof( SetFocusAction ), new PropertyMetadata( null ) );
public Control Target {
get { return (Control) GetValue( TargetProperty ); }
set { SetValue( TargetProperty, value ); }
}
protected override void Invoke( object parameter ) {
if( Target != null ) {
Target.Focus();
}
}
}
}
然后把它连接起来:
<UserControl x:Class="SilverlightApplication1.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:local="clr-namespace:SilverlightApplication1">
<Grid x:Name="LayoutRoot">
<sdk:TabControl>
<sdk:TabItem Header="Tab 1">
<Grid>
<i:Interaction.Triggers>
<i:EventTrigger EventName="Loaded">
<local:SetFocusAction Target="{Binding ElementName=tb1}"></local:SetFocusAction>
</i:EventTrigger>
</i:Interaction.Triggers>
<TextBox Width="200" Height="30" x:Name="tb1"></TextBox>
</Grid>
</sdk:TabItem>
<sdk:TabItem Header="Tab 2">
<Grid>
<i:Interaction.Triggers>
<i:EventTrigger EventName="Loaded">
<local:SetFocusAction Target="{Binding ElementName=tb2}"></local:SetFocusAction>
</i:EventTrigger>
</i:Interaction.Triggers>
<TextBox Width="200" Height="30" x:Name="tb2"></TextBox>
</Grid>
</sdk:TabItem>
</sdk:TabControl>
</Grid>
</UserControl>
请注意,当您首次运行带有此功能的应用时,Silverlight对象本身可能没有焦点,因此您必须连接javascript以手动关注它。但是,一旦用户点击Silverlight应用程序(或您的javascript设置焦点),此操作将完成其工作。
为了好玩,这里有一个完整的行为子类,它将与DataForm一起使用,并且应该适用于其他模板化控件。
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Interactivity;
using System.Windows.Media;
namespace SilverlightApplication1 {
public class SetFocusBehavior : Behavior<FrameworkElement> {
public static readonly DependencyProperty TargetNameProperty =
DependencyProperty.Register( "TargetName", typeof( string ), typeof( SetFocusBehavior ), new PropertyMetadata( null ) );
private bool _setFocusOnLayoutUpdated;
public string TargetName {
get { return (string) GetValue( TargetNameProperty ); }
set { SetValue( TargetNameProperty, value ); }
}
protected override void OnAttached() {
base.OnAttached();
this.AssociatedObject.LayoutUpdated += new EventHandler( AssociatedObject_LayoutUpdated );
this.AssociatedObject.Loaded += new RoutedEventHandler( AssociatedObject_Loaded );
}
protected override void OnDetaching() {
base.OnDetaching();
this.AssociatedObject.LayoutUpdated -= new EventHandler( AssociatedObject_LayoutUpdated );
this.AssociatedObject.Loaded -= new RoutedEventHandler( AssociatedObject_Loaded );
}
private void AssociatedObject_Loaded( object sender, RoutedEventArgs e ) {
if( !FindAndSetFocus() ) {
_setFocusOnLayoutUpdated = true;
}
}
private void AssociatedObject_LayoutUpdated( object sender, EventArgs e ) {
if( _setFocusOnLayoutUpdated ) {
_setFocusOnLayoutUpdated = false;
FindAndSetFocus();
}
}
private bool FindAndSetFocus() {
var found = Find( this.AssociatedObject ) as Control;
if( found != null ) {
found.Focus();
return true;
}
return false;
}
private DependencyObject Find( DependencyObject root ) {
if( root != null ) {
if( (string) root.GetValue( FrameworkElement.NameProperty ) == TargetName ) {
return root;
}
for( int i = 0; i < VisualTreeHelper.GetChildrenCount( root ); i++ ) {
var result = Find( VisualTreeHelper.GetChild( root, i ) );
if( result != null )
return result;
}
}
return null;
}
}
}
和XAML:
<UserControl x:Class="SilverlightApplication1.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:tk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/toolkit"
xmlns:local="clr-namespace:SilverlightApplication1">
<Grid x:Name="LayoutRoot">
<sdk:TabControl>
<sdk:TabItem Header="Tab 1">
<Grid>
<i:Interaction.Behaviors>
<local:SetFocusBehavior TargetName="tb1"></local:SetFocusBehavior>
</i:Interaction.Behaviors>
<TextBox Width="200" Height="30" x:Name="tb1"></TextBox>
</Grid>
</sdk:TabItem>
<sdk:TabItem Header="Tab 2">
<Grid>
<i:Interaction.Behaviors>
<local:SetFocusBehavior TargetName="tb2"></local:SetFocusBehavior>
</i:Interaction.Behaviors>
<tk:DataForm CurrentItem="sometext">
<tk:DataForm.EditTemplate>
<DataTemplate>
<TextBox Width="200" Height="30" x:Name="tb2"></TextBox>
</DataTemplate>
</tk:DataForm.EditTemplate>
</tk:DataForm>
</Grid>
</sdk:TabItem>
</sdk:TabControl>
</Grid>
</UserControl>