将焦点设置为ContentPresenter的内容

时间:2014-11-21 16:34:53

标签: wpf focus contentpresenter

我需要将焦点设置为ContentPresenter的内容。我可以假设ContentTemplate包含一个IInputElement但不包含其他任何内容。

以下是一个简化的示例,说明了问题:

主窗口:

<Window x:Class="FiedControlTest.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:custom="clr-namespace:Esatto.Wpf.CustomControls;assembly=Esatto.Wpf.CustomControls"
    xmlns:local="clr-namespace:FiedControlTest">
    <Window.Resources>
        <Style TargetType="TextBox" BasedOn="{StaticResource {x:Type TextBox}}">
            <Setter Property="Margin" Value="5"/>
            <Style.Triggers>
                <Trigger Property="IsFocused" Value="True">
                    <Setter Property="Background" Value="LightBlue"/>
                </Trigger>
            </Style.Triggers>
        </Style>
    </Window.Resources>
    <StackPanel Orientation="Vertical">
        <StackPanel Orientation="Horizontal">
            <ComboBox ItemsSource="{Binding Path=Options}" Name="cbOptions" DisplayMemberPath="Description"/>
            <Button Content="Set focus" Click="SetFocus"/>
        </StackPanel>
        <StackPanel Orientation="Horizontal">
            <Label Content="TextBox:"/>
            <TextBox Name="tbText" Text="A bare text box."/>
        </StackPanel>
        <StackPanel Orientation="Horizontal">
            <Label Content="ContentPresenter:"/>
            <ContentPresenter Content="TextBox in a ContentPresenter" Name="cpText">
                <ContentPresenter.ContentTemplate>
                    <DataTemplate>
                        <TextBox Text="{Binding Mode=OneWay}" IsReadOnly="True"/>
                    </DataTemplate>
                </ContentPresenter.ContentTemplate>
            </ContentPresenter>
        </StackPanel>
    </StackPanel>
</Window>

代码隐藏:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        this.DataContext = this;
        Options = new ObservableCollection<Option>(new[]{
            new Option(){TargetType=typeof(TextBox), Description="Bare Text Box"},
            new Option(){TargetType=typeof(ContentPresenter), Description="Content Presenter"}
        });
        InitializeComponent();
        cbOptions.SelectedIndex = 0;
    }

    private void SetFocus(object sender, RoutedEventArgs e)
    {
        var opt = cbOptions.SelectedItem as Option;
        if (opt.TargetType == typeof(TextBox))
            tbText.Focus();
        if (opt.TargetType == typeof(ContentPresenter))
            cpText.Focus();
    }

    public ObservableCollection<Option> Options { get; set; }

    public class Option
    {
        public Type TargetType { get; set; }
        public string Description { get; set; }
    }
}

那里并不多。裸TextBox按预期获得焦点; TextBox提供的ContentPresenter没有。

我尝试将Focusable="True"添加到ContentPresenter,但它没有任何明显的效果。我尝试过使用Keyboard.SetFocus代替UIElement.Focus,但行为并没有改变。

这是怎么做到的?

1 个答案:

答案 0 :(得分:0)

实际上,您设置焦点的是ContentPresenter,而不是内部TextBox。因此,您可以使用VisualTreeHelper来查找子视觉元素(在本例中为TextBox)并为其设置焦点。但是,如果IsReadOnlytrue,您将看不到任何符号闪烁(这可能也是您想要的)。要以只读模式显示,我们只需将IsReadOnlyCaretVisible设置为true

即可
private void SetFocus(object sender, RoutedEventArgs e)
{
    var opt = cbOptions.SelectedItem as Option;
    if (opt.TargetType == typeof(TextBox))
        tbText.Focus();
    if (opt.TargetType == typeof(ContentPresenter)) {
       var child = VisualTreeHelper.GetChild(cpText, 0) as TextBox;
       if(child != null) child.Focus();
    }            
}

此处编辑的XAML代码添加了IsReadOnlyCaretVisible

<TextBox Text="{Binding Mode=OneWay}" IsReadOnly="True" 
         IsReadOnlyCaretVisible="True"/>

请注意,上述代码只能应用于您使用TextBox作为ContentPresenter的ContentTemplate的根视觉的特定情况。一般情况下,您需要一些递归方法来查找子视觉(基于VisualTreeHelper),您可以搜索更多内容,我不想在此处包含它,因为它是一个非常着名的问题/ WPF中的代码在WPF中查找可视子项。 (斜体短语可用作搜索更多的关键字。)