简体   繁体   English

WPF:当TextBox具有焦点时,为ListBox设置IsSelected,而不会丢失LostFocus上的选择

[英]WPF: Setting IsSelected for ListBox when TextBox has focus, without losing selection on LostFocus

I've a ListBox with ListBoxItems with a template so they contain TextBoxes 我有一个带有ListBoxItemsListBox ,它带有一个模板,因此它们包含TextBoxes

带有文本框的ListBox

When the TextBox gets focused I want the ListBoxItem to be selected. TextBox聚焦时,我希望选择ListBoxItem One solution I've found looks like this: 我发现的一个解决方案如下:

<Style TargetType="{x:Type ListBoxItem}">
    <Style.Triggers>
        <Trigger Property="IsKeyboardFocusWithin" Value="True">
            <Setter Property="IsSelected" Value="True"></Setter>
        </Trigger>
    </Style.Triggers>
</Style>

This works great, but when the TextBox loses focus so does the selection. 这很好用,但是当TextBox失去焦点时,选择也是如此。

Is there a way to prevent this from happening? 有没有办法防止这种情况发生?

Best solution I've found to do this with no code behinde is this: 最好的解决方案我发现这样做没有代码behinde是这样的:

<Style TargetType="{x:Type ListBoxItem}">
    <Style.Triggers>
        <EventTrigger RoutedEvent="PreviewGotKeyboardFocus">
            <BeginStoryboard>
                <Storyboard>
                    <BooleanAnimationUsingKeyFrames
                        Storyboard.TargetProperty="(ListBoxItem.IsSelected)">

                        <DiscreteBooleanKeyFrame KeyTime="0" Value="True"/>
                    </BooleanAnimationUsingKeyFrames>
                </Storyboard>
            </BeginStoryboard>
        </EventTrigger>
    </Style.Triggers>
</Style>

You can also keep focus on the text box, but only have one ListBoxItem selected at any given time, with code behind. 您还可以将焦点放在文本框上,但在任何给定时间只选择一个ListBoxItem,后面有代码。

In the ListBox XAML: 在ListBox XAML中:

<ListBox
PreviewLostKeyboardFocus="CheckFocus">
</ListBox>

Then, in the CheckFocus() method in code-behind: 然后,在代码隐藏中的CheckFocus()方法中:

/* Cause the original ListBoxItem to lose focus
    * only if another ListBoxItem is being selected.
    * If a different element type is selected, the
    * original ListBoxItem will keep focus.
    */
private void CheckFocus(object sender, KeyboardFocusChangedEventArgs e)
{
    // check if focus is moving from a ListBoxItem, to a ListBoxItem
    if (e.OldFocus.GetType().Name == "ListBoxItem" && e.NewFocus.GetType().Name == "ListBoxItem")
    {
        // if so, cause the original ListBoxItem to loose focus
        (e.OldFocus as ListBoxItem).IsSelected = false;
    }
}

From the list of suggested solutions nothing helped me to resolve the same issue. 从建议的解决方案列表中没有任何帮助我解决同样的问题。 This is the custom solution I made: 这是我制作的自定义解决方案:

1). 1)。 Create Behavior (class that holds attached properties) that is going to enforce the focus: 创建行为(包含附加属性的类)将强制执行焦点:

public class TextBoxBehaviors
{
    public static bool GetEnforceFocus(DependencyObject obj)
    {
        return (bool)obj.GetValue(EnforceFocusProperty);
    }

    public static void SetEnforceFocus(DependencyObject obj, bool value)
    {
        obj.SetValue(EnforceFocusProperty, value);
    }

    // Using a DependencyProperty as the backing store for EnforceFocus.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty EnforceFocusProperty =
        DependencyProperty.RegisterAttached("EnforceFocus", typeof(bool), typeof(TextBoxBehaviors), new PropertyMetadata(false,
             (o, e) =>
             {
                 bool newValue = (bool)e.NewValue;
                 if (!newValue) return;

                 TextBox tb = o as TextBox;

                 if (tb == null)
                 {
                     MessageBox.Show("Target object should be typeof TextBox only. Execution has been seased", "TextBoxBehaviors warning",
                       MessageBoxButton.OK, MessageBoxImage.Warning);
                 }

                 tb.TextChanged += OnTextChanged;

             }));

    private static void OnTextChanged(object o, TextChangedEventArgs e)
    {
        TextBox tb = o as TextBox;
        tb.Focus();
       /* You have to place your caret at the end of your text manually, because each focus repalce your caret at the beging of text.*/
        tb.CaretIndex = tb.Text.Length;
    }

}

2). 2)。 Use this behavior in your XAML: 在XAML中使用此行为:

 <DataTemplate x:Key="MyDataTemplate">
    <TextBox behaviors:TextBoxBehaviors.EnforceFocus="True"
             Text="{Binding Path=MyProperty, UpdateSourceTrigger=PropertyChanged}" />
</DataTemplate>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM