C# 在列表框中选择文本框项不会更改列表框的选定项

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/653524/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-04 11:58:24  来源:igfitidea点击:

Selecting a Textbox Item in a Listbox does not change the selected item of the listbox

c#wpfxamllistboxselecteditem

提问by

I Have a wpf Listbox that display's a list of textboxes. When I click on the Textbox the Listbox selection does not change. I have to click next to the TextBox to select the listbox item. Is there some property I need to set for the Textbox to forward the click event to the Listbox?

我有一个显示文本框列表的 wpf 列表框。当我单击文本框时,列表框选择不会改变。我必须在 TextBox 旁边单击才能选择列表框项。是否需要为文本框设置一些属性以将单击事件转发到列表框?

回答by Joey

The Listbox handles item selection but does not know about focus of the textbox embedded within. If you want to change the selection whenever a textbox gets input focus then you need to change the listbox selection manually, afaik.

列表框处理项目选择,但不知道嵌入其中的文本框的焦点。如果您想在文本框获得输入焦点时更改选择,那么您需要手动更改列表框选择,afaik。

回答by Robert Macnee

Is there some property I need to set for the Textbox to forward the click event to the Listbox?

是否需要为文本框设置一些属性以将单击事件转发到列表框?

It's not a simple property, but you can handle the GotFocusevent on your TextBox, then use VisualTreeHelperto find the ListBoxItemand select it:

这不是一个简单的属性,但您可以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;
}

回答by Steven

I'm not entirely sure you would want to set the selection directly as described in the previous answer because I think it would break multiselection and some other scenerios

我不完全确定您是否希望按照上一个答案中的描述直接设置选择,因为我认为它会破坏多选和其他一些场景

. You might want to try restyling a button like below and see what happens.

. 您可能想尝试重新设计一个像下面这样的按钮,看看会发生什么。

<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 />

回答by Marcel B

Your not very specific about your initial situation. But i assume that you use DataBinding and an ItemTemplate. Thats imho an easy way to do this, as well if your beginner on this topic. This should work:

您对您的初始情况不是很具体。但我假设您使用 DataBinding 和一个 ItemTemplate。恕我直言,这是一个简单的方法,如果您是这个主题的初学者也是如此。这应该有效:

<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) */
}

回答by Mark Synowiec

The simplest way I've been able to find to do this is to use the PreviewMouseDown event and set the IsSelected property of the templated parent. Since the preview events bubble down, the ListBoxItem will process the event as soon as the user clicks the textbox, combobox, or any other control you set the event on.

我能找到的最简单的方法是使用 PreviewMouseDown 事件并设置模板化父级的 IsSelected 属性。由于预览事件冒泡,一旦用户单击文本框、组合框或您设置事件的任何其他控件,ListBoxItem 就会处理该事件。

One nice thing about this is that you can use the same event for all types of controls since they all derive from Framework element. Also, setting IsSelected (instead of setting the SelectedItem) will cause multiple items to be selected when you set the SelectionMode of the listbox to "Extended", which could or could not be what you're looking for.

这样做的一个好处是您可以对所有类型的控件使用相同的事件,因为它们都派生自 Framework 元素。此外,当您将列表框的 SelectionMode 设置为“扩展”时,设置 IsSelected(而不是设置 SelectedItem)将导致选择多个项目,这可能是您要查找的内容,也可能不是。

ie:

IE:

c# code

代码

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

xaml

xml

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

回答by Arcturus

We use the following style to set a PreviewGotKeyboardFocus which handles all events of TextBox control and ComboBoxes and such:

我们使用以下样式设置一个 PreviewGotKeyboardFocus,它处理 TextBox 控件和 ComboBoxes 等的所有事件:

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

And then we select the row in code behind:

然后我们选择后面代码中的行:

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

回答by Natrium

回答by Ben

I used similar to Robert's solution, but without code behind (using attached behavior).

我使用了类似于 Robert 的解决方案,但没有背后的代码(使用附加行为)。

To do so,

为此,

First. Create separate class FocusBehaviour:

第一的。创建单独的类 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
    }
}

Second. Add a style in resources section (my style is rounded black on focus). Notice setter for FocusBehaviour.IsListBoxItemSelected property. You should reference it in xmlns:behave="clr-namespace:MyBehaviours"

第二。在资源部分添加样式(我的样式在焦点上是圆形的黑色)。注意 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>

`

`

Third. (optional, for reverse task)

第三。(可选,用于反向任务)

You will meet, if not any, reverse task - focusing on TextBox when ListBoxItem get selected. I recommend using another property of Behaviour class, IsFocused. Here is a sample template for ListBoxItem, please notice Property="behave:FocusBehaviour.IsFocused"and FocusManager.IsFocusScope="True"

您将遇到(如果没有)反向任务 - 当 ListBoxItem 被选中时,将重点放在 TextBox 上。我建议使用 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>

回答by oillio

I use a class handler to set this behavior. Doing it this way will fix all of the list views in the application. I don't know why this is not the default behavior.

我使用类处理程序来设置此行为。这样做将修复应用程序中的所有列表视图。我不知道为什么这不是默认行为。

In your App.xaml.cs, add the following to OnStartup:

在 App.xaml.cs 中,将以下内容添加到 OnStartup:

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

回答by Grazer

Be sure to use appropriate TargetType: ListViewItem, ListBoxItem or TreeViewItem.

确保使用适当的 TargetType:ListViewItem、ListBoxItem 或 TreeViewItem。

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