Подтвердить что ты не робот

Выбор элемента текстового поля в списке не изменяет выбранный элемент списка

У меня есть список wpf, отображающий список текстовых полей. Когда я нажимаю на текстовое поле, выбор списка не изменяется. Я должен щелкнуть рядом с TextBox, чтобы выбрать элемент списка. Есть ли какое-то свойство, которое мне нужно установить для текстового поля для пересылки события click в список?

4b9b3361

Ответ 1

Обязательно используйте соответствующие TargetType: ListViewItem, ListBoxItem или TreeViewItem.

<Style TargetType="ListViewItem">
    <Style.Triggers>
        <Trigger Property="IsKeyboardFocusWithin" Value="true">
            <Setter Property="IsSelected" Value="true" />
        </Trigger>
    </Style.Triggers>
</Style>

Ответ 2

Мы используем следующий стиль для установки PreviewGotKeyboardFocus, который обрабатывает все события элемента управления TextBox и ComboBoxes и т.д.:

    <ListView.ItemContainerStyle>
        <Style TargetType="ListViewItem">
            <EventSetter Event="PreviewGotKeyboardFocus" Handler="SelectCurrentItem"/>
        </Style>
    </ListView.ItemContainerStyle>

И затем мы выбираем строку в коде позади:

    protected void SelectCurrentItem(object sender, KeyboardFocusChangedEventArgs e)
    {
        ListViewItem item = (ListViewItem) sender;
        item.IsSelected = true;
    }

Ответ 3

У меня недостаточно комментариев для комментариев, поэтому я отправляю свой комментарий в качестве ответа. Решение Grazer выше не работает в случаях, когда у вас есть другой элемент управления, например Button, которому требуется SelectedItem. Это происходит из-за того, что в соответствии с Style Trigger значение IsKeyboardFocusWithin становится ложным при нажатии на Button, а SelectedItem становится нулевым.

Ответ 4

Я использовал аналогично решению Роберта, но без кода (используя приложенное поведение).

Чтобы сделать это,

Во-первых. Создайте отдельный класс FocusBehaviour:


using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;

namespace MyBehaviours
{
    public class FocusBehaviour
    {
        #region IsFocused
        public static bool GetIsFocused(Control control)
        {
            return (bool) control.GetValue(IsFocusedProperty);
        }

        public static void SetIsFocused(Control control, bool value)
        {
            control.SetValue(IsFocusedProperty, value);
        }

        public static readonly DependencyProperty IsFocusedProperty = DependencyProperty.RegisterAttached(
            "IsFocused", 
            typeof(bool),
            typeof(FocusBehaviour), 
            new UIPropertyMetadata(false, IsFocusedPropertyChanged));

        public static void IsFocusedPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            var control = sender as Control;
            if (control == null || !(e.NewValue is bool))
                return;
            if ((bool)e.NewValue && !(bool)e.OldValue)
                control.Focus();
        }

        #endregion IsFocused

        #region IsListBoxItemSelected

        public static bool GetIsListBoxItemSelected(Control control)
        {
            return (bool) control.GetValue(IsListBoxItemSelectedProperty);
        }

        public static void SetIsListBoxItemSelected(Control control, bool value)
        {
            control.SetValue(IsListBoxItemSelectedProperty, value);
        }

        public static readonly DependencyProperty IsListBoxItemSelectedProperty = DependencyProperty.RegisterAttached(
            "IsListBoxItemSelected", 
            typeof(bool),
            typeof(FocusBehaviour), 
            new UIPropertyMetadata(false, IsListBoxItemSelectedPropertyChanged));

        public static void IsListBoxItemSelectedPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            var control = sender as Control;
            DependencyObject p = control;
            while (p != null && !(p is ListBoxItem))
            {
                p = VisualTreeHelper.GetParent(p);
            } 

            if (p == null)
                return;

            ((ListBoxItem)p).IsSelected = (bool)e.NewValue;
        }

        #endregion IsListBoxItemSelected
    }
}

Во-вторых. Добавьте стиль в раздел ресурсов (мой стиль округлен по центру). Уведомление setter для свойства FocusBehaviour.IsListBoxItemSelected. Вы должны ссылаться на него в xmlns:behave="clr-namespace:MyBehaviours"

`

    <Style x:Key="PreviewTextBox" BasedOn="{x:Null}" TargetType="{x:Type TextBox}">
        <Setter Property="BorderThickness" Value="1"/>
        <Setter Property="Padding" Value="1"/>
        <Setter Property="AllowDrop" Value="true"/>
        <Setter Property="Background" Value="White"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type TextBox}">
                    <Border
                        Margin="6,2,0,4"
                        BorderBrush="#FFBDBEBD"
                        BorderThickness="1"
                        CornerRadius="8"
                        Background="White"
                        VerticalAlignment="Stretch"
                        HorizontalAlignment="Stretch"
                        MinWidth="100"
                        x:Name="bg">
                        <ScrollViewer 
                            x:Name="PART_ContentHost" 
                            SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
                    </Border>
                    <ControlTemplate.Triggers>
                        <Trigger Property="IsKeyboardFocusWithin" Value="True">
                            <Setter Property="Background" TargetName="bg" Value="Black"/>
                            <Setter Property="Background" Value="Black"/><!-- we need it for caret, it is black on black elsewise -->
                            <Setter Property="Foreground" Value="White"/>
                            <Setter Property="behave:FocusBehaviour.IsListBoxItemSelected" Value="True"/>
                        </Trigger>

                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

`

В-третьих. (необязательно, для обратной задачи)

Вы встретите, если не любую, обратную задачу - сосредоточьтесь на TextBox при выборе ListBoxItem. Я рекомендую использовать другое свойство класса Behavior, IsFocused. Вот пример шаблона для ListBoxItem, обратите внимание на Property="behave:FocusBehaviour.IsFocused" и FocusManager.IsFocusScope="True"

    <DataTemplate x:Key="YourKey" DataType="{x:Type YourType}">
            <Border
            Background="#FFF7F3F7"
            BorderBrush="#FFBDBEBD"
            BorderThickness="0,0,0,1"
            FocusManager.IsFocusScope="True"
            x:Name="bd"
            MinHeight="40">
                <TextBox
                    x:Name="textBox"
                    Style="{StaticResource PreviewTextBox}"
                    Text="{Binding Value}" />
        </Border>
        <DataTemplate.Triggers>
            <DataTrigger
                Binding="{Binding IsSelected,RelativeSource={RelativeSource AncestorType=ListBoxItem}}"
                Value="True">
                <Setter
                    TargetName="textBox"
                    Property="behave:FocusBehaviour.IsFocused" 
                    Value="True" />
            </DataTrigger>
        </DataTemplate.Triggers>
    </DataTemplate>

Ответ 5

Я использую обработчик класса, чтобы установить это поведение. Выполнение этого способа устранит все виды списков в приложении. Я не знаю, почему это не поведение по умолчанию.

В приложении App.xaml.cs добавьте следующее в OnStartup:

protected override void OnStartup(StartupEventArgs e)
    {
        EventManager.RegisterClassHandler(typeof (ListViewItem), 
                                          ListViewItem.PreviewGotKeyboardFocusEvent,
                                          new RoutedEventHandler((x,_) => (x as ListViewItem).IsSelected = true));
    }

Ответ 6

Есть ли какое-то свойство, которое мне нужно установить для текстового поля для пересылки события click в список?

Это не просто свойство, но вы можете обработать событие GotFocus на вашем TextBox, затем используйте VisualTreeHelper найти ListBoxItem и выбрать его:

private void TextBox_GotFocus(object sender, RoutedEventArgs e)
{
    TextBox myTextBox = sender as TextBox;
    DependencyObject parent = VisualTreeHelper.GetParent(myTextBox);
    while (!(parent is ListBoxItem))
    {
        parent = VisualTreeHelper.GetParent(parent);
    }
    ListBoxItem myListBoxItem = parent as ListBoxItem;
    myListBoxItem.IsSelected = true;
}

Ответ 7

Самый простой способ, которым я смог найти это, - использовать событие PreviewMouseDown и установить свойство IsSelected шаблона родителя. Поскольку события предварительного просмотра выходят из строя, ListBoxItem будет обрабатывать событие, как только пользователь нажимает текстовое поле, combobox или любой другой элемент управления, на который вы устанавливаете событие.

Хорошо, что вы можете использовать одно и то же событие для всех типов элементов управления, поскольку все они происходят из элемента Framework. Кроме того, установка IsSelected (вместо установки SelectedItem) приведет к тому, что будут выбраны несколько элементов, если вы установите для параметра SelectionMode в списке "Extended", что может быть или не быть тем, что вы ищете.

т

С# code

private void Element_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
    ((sender as FrameworkElement).TemplatedParent as ListBoxItem).IsSelected = true;
}

XAML

    ...
    <ComboBox PreviewMouseDown="Element_PreviewMouseDown"/>
    <TextBox PreviewMouseDown="Element_PreviewMouseDown"/>
    ...

Ответ 9

Ниже приводится упрощение ответа @Ben без необходимости переопределять DataTemplate. Его можно даже применять как статический стиль. Протестировано с помощью ListView, содержащего GridView > GridViewColumn > TextBox.

Пример:

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

Ответ 10

Listbox обрабатывает выбор элементов, но не знает о фокусе встроенного текстового поля. Если вы хотите изменить выделение, когда текстовое поле получает фокус ввода, вам нужно вручную изменить выбор списка, afaik.

Ответ 11

Я не совсем уверен, что вы захотите установить выделение напрямую, как описано в предыдущем ответе, потому что я думаю, что он сломает мультиселемент и некоторые другие сценарии

. Возможно, вы захотите попробовать переустановить кнопку, как показано ниже, и посмотреть, что произойдет.

<Button ClickMode="Pressed" Focusable="False">
<Button.Template>
    <ControlTemplate>  // change the template to get rid of all the default chrome 
        <Border Background="Transparent"> // Button won't be clickable without some kind of background set
            <ContentPresenter />
        </Border>
    </ControlTemplate>
</Button.Template>
<TextBox />

Ответ 12

Ваша не очень конкретная информация о вашей первоначальной ситуации. Но я предполагаю, что вы используете DataBinding и ItemTemplate. Thats imho легкий способ сделать это, а также, если ваш новичок на эту тему. Это должно работать:

<ListBox ItemsSource="{Binding someDataCollection}" Name="myListBox">
   <ListBox.ItemTemplate>
      <DataTemplate>
         <TextBox Text="{Binding datafield}" Tag="{Binding .}"
                  GotFocus="TextBox_GotFocus"/>
      </DataTemplate>
   </ListBox.ItemTemplate>
</ListBox>

private void TextBox_GotFocus(object sender, RoutedEventArgs e)
{
   myListBox.SelectedItem = (sender as TextBox).Tag; /* Maybe you need to cast to the type of the objects contained in the collection(bound as ItemSource above) */
}

Ответ 13

Попробуйте этот код:

foreach (object item in this.listBox1.Items) {
    if (textbox1.text.equals(item.toString())) {
        //show error message; break
    }
}

Ответ 14

Старая дискуссия, но, может быть, мой ответ помогает другим...

Решение Ben имеет ту же проблему, что и решение Grazer. Плохо то, что выбор зависит от фокуса [клавиатуры] текстового поля. Если у вас есть другой контроль над вашим диалогом (т.е. Кнопка), фокус теряется при нажатии кнопки, и listboxitem становится не выбранным (SelectedItem == null). Таким образом, у вас есть другое поведение для нажатия на элемент (вне текстового поля) и нажатия в текстовом поле. Это очень утомительно для работы и выглядит очень странно.

Я уверен, что для этого нет чистого решения XAML. Для этого нам нужен код. Решение близко к тому, что предложил Марк.

(в моем примере я использую ListViewItem вместо ListBoxItem, но решение работает для обоих).

Code-за:

private void Element_PreviewMouseDown(object sender, MouseButtonEventArgs e)
    {
        var frameworkElement = sender as FrameworkElement;
        if (frameworkElement != null)
        {
            var item = FindParent<ListViewItem>(frameworkElement);
            if (item != null)
                item.IsSelected = true;
        }
    }

с FindParent (взято из http://www.infragistics.com/community/blogs/blagunas/archive/2013/05/29/find-the-parent-control-of-a-specific-type-in-wpf-and-silverlight.aspx):

public static T FindParent<T>(DependencyObject child) where T : DependencyObject
    {
        //get parent item
        DependencyObject parentObject = VisualTreeHelper.GetParent(child);

        //we've reached the end of the tree
        if (parentObject == null) return null;

        //check if the parent matches the type we're looking for
        T parent = parentObject as T;
        if (parent != null)
            return parent;

        return FindParent<T>(parentObject);
    }

В моей DataTemplate:

<TextBox Text="{Binding Name}"
        PreviewMouseDown="Element_PreviewMouseDown"/>