【问题标题】:Tab-Focus on custom TextBox选项卡聚焦自定义文本框
【发布时间】:2015-07-21 11:44:19
【问题描述】:

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

现在我想用 custom-TextBoxes 替换这个标准-TextBoxes,它应该有一个 Null-Text,如果 Text 为空,则会显示。

我自定义的 XAML-TextBox 是:

<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());
    }
}

【问题讨论】:

  • 我尝试使用您的 UserControl,但没有发现任何问题。您使用的是哪个 .NET 框架?你能把你的 UserControl 代码和你的转换器代码贴出来吗?
  • 如果 NullTextBox 所做的只是在值为 null 时显示某些内容,为什么不在像 {Binding Blah, TargetNullValue='Enter text here...'} 这样的常规 TextBox 的绑定库中设置一个 TargetNullValue
  • 我希望 NullText 为深灰色和斜体样式。

标签: c# wpf xaml


【解决方案1】:

Hyperlink 中的 TextBlock 更改为 Run,如下所示(请注意,由于 Run 不支持 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>

【讨论】:

  • 好的。现在我可以通过按 Tab 键两次来切换焦点。现在第一次按下 Tab 键后谁在捕捉焦点?
  • 可能是UserControl 本身。你有它作为Focusable="True"。尝试将其设置为False,看看是否可以解决。
  • 如果这不能解决问题,只需检查 UserControl 中的所有控件...除 TextBox 之外的所有控件都应具有 FocusableIsTabStopFalse。它在我的示例中立即与我提供的代码一起工作,所以可能是因为您在此处发布代码后进行了一些修改。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-04-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-11-08
  • 1970-01-01
  • 2017-10-21
相关资源
最近更新 更多