2015-07-21 130 views
1

在我的应用程序中,我有一个TabControl。在一个TabItem有三个TextBoxes,我可以通过按Tab键在它们之间切换。Tab-Focus on custom TextBox

现在我想用custom- TextBoxes替换这个标准TextBoxes,它应该有一个空文本,如果文本是空的,将显示空文本。

我定做TextBox的XAML是:

<UserControl x:Class="MyApplication.Controls.NullTextTextBox" 
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
      xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
      xmlns:converter="clr-namespace:ScM.Converter" 
      mc:Ignorable="d" d:DesignHeight="24" d:DesignWidth="300" 
      x:Name="nullTextTextBox" IsHitTestVisible="True" Focusable="True"> 
    <Grid> 
     <Grid.ColumnDefinitions> 
      <ColumnDefinition Width="*"/> 
      <ColumnDefinition Width="Auto"/> 
     </Grid.ColumnDefinitions> 
     <TextBox Grid.Column="0" VerticalAlignment="Stretch" x:Name="tbInput" 
       Text="{Binding ElementName=nullTextTextBox,Path=Text, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" 
       AcceptsReturn="{Binding ElementName=nullTextTextBox, Path=AcceptsReturn, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}" 
       TextWrapping="{Binding ElementName=nullTextTextBox, Path=TextWrapping, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}" 
       IsTabStop="True" /> 
     <TextBlock Grid.Column="0" VerticalAlignment="Top" Text="{Binding ElementName=nullTextTextBox,Path=NullText, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Left" 
        FontStyle="Italic" Foreground="DarkGray" Margin="4,4,0,0" IsHitTestVisible="False" 
        Visibility="{Binding ElementName=nullTextTextBox, Path=Text, Mode=OneWay, UpdateSourceTrigger=PropertyChanged, Converter={converter:StringIsNullToVisibilityConverter}}" 
        Focusable="False"/> 
     <TextBlock Grid.Column="1" VerticalAlignment="Center" HorizontalAlignment="Center"> 
      <TextBlock.Visibility> 
       <MultiBinding Converter="{converter:DeleteButtonMultiConverter}"> 
        <Binding ElementName="nullTextTextBox" Path="IsClearButtonVisible" Mode="OneWay" UpdateSourceTrigger="PropertyChanged"/> 
        <Binding ElementName="nullTextTextBox" Path="Text" Mode="OneWay" UpdateSourceTrigger="PropertyChanged"/> 
       </MultiBinding> 
      </TextBlock.Visibility> 
      <Hyperlink TextDecorations="{x:Null}" Command="{Binding ElementName=nullTextTextBox, Path=ClearTextCommand, Mode=OneWay}" 
         Focusable="False" > 
       <TextBlock FontFamily="Wingdings 2" Text="Î" Foreground="Red" FontWeight="Bold" FontSize="14" VerticalAlignment="Center" Margin="1,1,2,1"/> 
      </Hyperlink> 
     </TextBlock> 
    </Grid> 
</UserControl> 

我会说这XAML的代码隐藏是不相关的,因为只有注册DependencyProperties

我的默认-TextBox的行为就像我期望的那样。但是,如果在焦点位于一个NullTextBox内时按下Tab键,焦点将切换到TabHeader而不是第二个NullTextBox。

其中NullTextBoxes位于它看起来像XAML:

<Grid> 
    <Grid.RowDefinitions> 
     <RowDefinition Height="Auto"/> 
     <RowDefinition Height="Auto"/> 
     <RowDefinition Height="Auto"/> 
     <RowDefinition Height="Auto"/> 
    </Grid.RowDefinitions> 
    <controls:NullTextTextBox Grid.Row="0" NullText="Value 1"/> 
    <controls:NullTextTextBox Grid.Row="1" NullText="Value 2"/> 
    <controls:NullTextTextBox Grid.Row="2" NullText="Value 3"/> 
</Grid> 

为什么当我按下Tab密钥我的第二和第三NullTextBox没有得到关注?


我发现如果删除包含超链接的TextBlock,Tab-Order按预期工作。但我需要这个TextBlock的...


我的自定义文本框的后台代码的样子:

public partial class NullTextTextBox : UserControl, INotifyPropertyChanged 
{ 
    public static readonly DependencyProperty TextProperty = DependencyProperty.Register(
     "Text", typeof (string), typeof (NullTextTextBox), new PropertyMetadata(default(string))); 

    public static readonly DependencyProperty NullTextProperty = DependencyProperty.Register(
     "NullText", typeof (string), typeof (NullTextTextBox), new PropertyMetadata(default(string))); 

    public static readonly DependencyProperty IsClearButtonVisibleProperty = DependencyProperty.Register(
     "IsClearButtonVisible", typeof (bool), typeof (NullTextTextBox), new PropertyMetadata(default(bool))); 

    public static readonly DependencyProperty AcceptsReturnProperty = DependencyProperty.Register(
     "AcceptsReturn", typeof (bool), typeof (NullTextTextBox), new PropertyMetadata(default(bool))); 

    public static readonly DependencyProperty TextWrappingProperty = DependencyProperty.Register(
     "TextWrapping", typeof (TextWrapping), typeof (NullTextTextBox), new PropertyMetadata(default(TextWrapping))); 

    public TextWrapping TextWrapping 
    { 
     get { return (TextWrapping) GetValue(TextWrappingProperty); } 
     set 
     { 
      SetValue(TextWrappingProperty, value); 
      OnPropertyChanged(); 
     } 
    } 

    private ICommand clearTextCommand; 

    public NullTextTextBox() 
    { 
     InitializeComponent(); 
     IsClearButtonVisible = false; 
     Text = string.Empty; 
     NullText = "Enter text here..."; 
     AcceptsReturn = false; 
     TextWrapping = TextWrapping.NoWrap; 
    } 

    public bool AcceptsReturn 
    { 
     get { return (bool) GetValue(AcceptsReturnProperty); } 
     set 
     { 
      SetValue(AcceptsReturnProperty, value); 
      OnPropertyChanged(); 
     } 
    } 

    public ICommand ClearTextCommand 
    { 
     get { return clearTextCommand ?? (clearTextCommand = new RelayCommand<object>(p => ClearText())); } 
    } 

    public bool IsClearButtonVisible 
    { 
     get { return (bool) GetValue(IsClearButtonVisibleProperty); } 
     set 
     { 
      SetValue(IsClearButtonVisibleProperty, value); 
      OnPropertyChanged(); 
     } 
    } 

    public string Text 
    { 
     get { return (string) GetValue(TextProperty); } 
     set 
     { 
      SetValue(TextProperty, value); 
      OnPropertyChanged(); 
     } 
    } 

    public string NullText 
    { 
     get { return (string) GetValue(NullTextProperty); } 
     set 
     { 
      SetValue(NullTextProperty, value); 
      OnPropertyChanged(); 
     } 
    } 

    public event PropertyChangedEventHandler PropertyChanged; 

    private void ClearText() 
    { 
     Text = string.Empty; 
     tbInput.Focus(); 
    } 

    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) 
    { 
     PropertyChangedEventHandler handler = PropertyChanged; 
     if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName)); 
    } 
} 

和使用转换器:

internal class DeleteButtonMultiConverter : MarkupExtension, IMultiValueConverter 
{ 
    private static DeleteButtonMultiConverter converter; 

    public DeleteButtonMultiConverter() 
    { 

    } 

    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) 
    { 
     if (values != null && values.Length == 2 && values[0] is bool && values[1] is string) 
     { 
      if ((bool) values[0] && !string.IsNullOrEmpty((string) values[1])) 
       return Visibility.Visible; 
      return Visibility.Collapsed; 
     } 
     return values; 
    } 

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) 
    { 
     throw new NotImplementedException(); 
    } 

    public override object ProvideValue(IServiceProvider serviceProvider) 
    { 
     return converter ?? (converter = new DeleteButtonMultiConverter()); 
    } 
} 
+0

我试图用你用户控件,我并没有发现任何问题。你使用哪种.NET框架?你可以发布你的UserControl代码和你的转换器代码吗? –

+0

如果所有的Nu​​llTextBox的do都显示一些东西,如果这个值为null,那么为什么不直接在一个常规TextBox的绑定库中设置一个'TargetNullValue',比如'{Binding Blah,TargetNullValue ='在这里输入文本...'}'? –

+0

我希望NullText为深灰色和斜体样式。 – Tomtom

回答

1

更改TextBlock的在你的超链接运行,像这样(注意,s因斯运行不支持VerticalAlignmentMargin,我要么删除或移动这些属性):

<TextBlock Grid.Column="1" VerticalAlignment="Center" HorizontalAlignment="Center" Margin="1,1,2,1"> 
    <TextBlock.Visibility> 
     <MultiBinding Converter="{converter:DeleteButtonMultiConverter}"> 
      <Binding ElementName="nullTextTextBox" Path="IsClearButtonVisible" Mode="OneWay" UpdateSourceTrigger="PropertyChanged"/> 
      <Binding ElementName="nullTextTextBox" Path="Text" Mode="OneWay" UpdateSourceTrigger="PropertyChanged"/> 
     </MultiBinding> 
    </TextBlock.Visibility> 
    <Hyperlink TextDecorations="{x:Null}" Command="{Binding ElementName=nullTextTextBox, Path=ClearTextCommand, Mode=OneWay}" 
       Focusable="False" > 
     <Run FontFamily="Wingdings 2" Text="Î" Foreground="Red" FontWeight="Bold" FontSize="14" /> 
    </Hyperlink> 
</TextBlock> 
+0

好的。现在我可以通过按Tab键两次来切换焦点。在第一次按Tab键后,谁抓住了焦点? – Tomtom

+0

可能是'UserControl'本身。你把它当作'Focusable =“True”'。尝试将其设置为“假”,看看是否能解决这个问题。 – almulo

+0

如果这样不能解决问题,只需检查UserControl内的所有控件......除TextBox外,其他所有控件都应具有“Focusable”或“IsTabStop”为“False”。它在我提供的代码示例中马上工作,所以也许是因为您在此处发布代码后进行了一些修改。 – almulo