我有一个wpf列表框,显示了一个文本框列表。当我单击文本框时,列表框选择不会更改。我必须单击TextBox旁边的以选择列表框项。是否需要为Textbox设置一些属性以将click事件转发到Listbox?
答案 0 :(得分:38)
我们使用以下样式设置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;
}
答案 1 :(得分:37)
确保使用适当的TargetType:ListViewItem,ListBoxItem或TreeViewItem。
<Style TargetType="ListViewItem">
<Style.Triggers>
<Trigger Property="IsKeyboardFocusWithin" Value="true">
<Setter Property="IsSelected" Value="true" />
</Trigger>
</Style.Triggers>
</Style>
答案 2 :(得分:6)
我没有足够的代表发表评论,因此我将评论作为答案发布。如果您有另一个需要Button
的{{1}}控件,上面的Grazer解决方案不起作用。这是因为根据SelectedItem
,Style Trigger
在您点击IsKeyboardFocusWithin
时变为false,而Button
变为空。
答案 3 :(得分:3)
我使用类似于Robert的解决方案,但没有代码(使用附加行为)。
要这样做,
首先。创建单独的类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
}
}
二。在资源部分添加样式(我的样式在焦点上呈黑色圆角)。注意FocusBehaviour.IsListBoxItemSelected属性的setter。您应该在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>
`
第三。 (可选,用于反向任务)
您将会遇到(如果不是)任何反向任务 - 在选择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>
答案 4 :(得分:3)
我使用类处理程序来设置此行为。这样做将修复应用程序中的所有列表视图。我不知道为什么这不是默认行为。
在App.xaml.cs中,将以下内容添加到OnStartup:
protected override void OnStartup(StartupEventArgs e)
{
EventManager.RegisterClassHandler(typeof (ListViewItem),
ListViewItem.PreviewGotKeyboardFocusEvent,
new RoutedEventHandler((x,_) => (x as ListViewItem).IsSelected = true));
}
答案 5 :(得分:2)
我是否需要为Textbox设置一些属性以将click事件转发到Listbox?
这不是一个简单的属性,但您可以在TextBox
处理GotFocus
事件,然后使用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;
}
答案 6 :(得分:1)
我能够找到的最简单的方法是使用PreviewMouseDown事件并设置模板化父级的IsSelected属性。由于预览事件会向下冒泡,因此只要用户单击文本框,组合框或您设置事件的任何其他控件,ListBoxItem就会处理该事件。
关于这一点的一个好处是你可以对所有类型的控件使用相同的事件,因为它们都派生自Framework元素。此外,当您将列表框的SelectionMode设置为“Extended”时,设置IsSelected(而不是设置SelectedItem)将导致选择多个项目,这可能是也可能不是您要查找的内容。
即:
c#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"/>
...
答案 7 :(得分:1)
答案 8 :(得分:1)
以下是@ Ben的答案的简化,无需覆盖DataTemplate。它甚至可以作为静态样式应用。使用包含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>
答案 9 :(得分:0)
列表框处理项目选择,但不知道嵌入的文本框的焦点。如果您想在文本框获得输入焦点时更改选择,则需要手动更改列表框选择,afaik。
答案 10 :(得分:0)
我不完全确定你会想要直接设置选择,如前面的答案所述,因为我认为它会打破多选和其他一些场景
。您可能想尝试重新设置如下所示的按钮,看看会发生什么。
<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 />
答案 11 :(得分:0)
您对初始情况并不十分具体。但我假设您使用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) */
}
答案 12 :(得分:0)
试试这段代码:
foreach (object item in this.listBox1.Items) {
if (textbox1.text.equals(item.toString())) {
//show error message; break
}
}
答案 13 :(得分:0)
旧的讨论,但也许我的答案可以帮助别人......
Ben的解决方案与Grazer的解决方案存在同样的问题。不好的是,选择取决于文本框的[键盘]焦点。如果您的对话框(即按钮)上有另一个控件,则单击该按钮时焦点会丢失,并且listboxitem将被取消选中(SelectedItem == null)。因此,您在单击项目(文本框外部)并单击文本框时会有不同的行为。处理起来非常繁琐,看起来很奇怪。
我非常确定没有纯XAML解决方案。我们需要代码隐藏。解决方案接近马克建议。
(在我的示例中,我使用ListViewItem而不是ListBoxItem,但解决方案适用于两者)。
代码隐藏:
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"/>
答案 14 :(得分:0)
基于Arcturus Answer的附加行为,以使其可重用并且不会隐藏在后面的代码中。
public static class SelectListBoxItemWhenControlInsideTheItemIsClickedBehavior
{
public static readonly DependencyProperty EnableProperty = DependencyProperty.RegisterAttached(
"Enable",
typeof(bool),
typeof(SelectListBoxItemWhenControlInsideTheItemIsClickedBehavior),
new FrameworkPropertyMetadata(false, OnEnableChanged));
public static bool GetEnable(FrameworkElement frameworkElement)
{
return (bool)frameworkElement.GetValue(EnableProperty);
}
public static void SetEnable(FrameworkElement frameworkElement, bool value)
{
frameworkElement.SetValue(EnableProperty, value);
}
private static void OnEnableChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if ( d is ListBoxItem listBoxItem)
listBoxItem.PreviewGotKeyboardFocus += ListBoxItem_PreviewGotKeyboardFocus;
}
private static void ListBoxItem_PreviewGotKeyboardFocus(object sender, System.Windows.Input.KeyboardFocusChangedEventArgs e)
{
var listBoxItem = (ListBoxItem)sender;
listBoxItem.IsSelected = true;
}
}
例如<Windows.Resources>
<Window.Resources>
<Style TargetType="ListViewItem">
<Setter Property="myBehavior:SelectListBoxItemWhenControlInsideTheItemIsClickedBehavior.Enable" Value="true"/>
</Style>
</Window.Resources>
如果Visual Studio不够聪明,无法自动添加它。例如,当您的项目名为“ MyApp”并将文件保存在“ MyBehaviors”文件夹中时,命名空间将位于“窗口”下:
<Window
xmlns:myBehavior="clr-namespace:MyApp.MyBehaviors"
>