web-dev-qa-db-ja.com

リストボックスでテキストボックスアイテムを選択しても、リストボックスの選択されたアイテムは変更されません

テキストボックスのリストを表示するwpfリストボックスがあります。テキストボックスをクリックしても、リストボックスの選択は変わりません。 TextBoxの横をクリックしてリストボックス項目を選択する必要があります。 TextboxがクリックイベントをListboxに転送するために設定する必要があるプロパティはありますか?

45
Zack

次のスタイルを使用して、TextBoxコントロールやComboBoxなどのすべてのイベントを処理するPreviewGotKeyboardFocusを設定します。

    <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;
    }
38
Arcturus

必ず適切なTargetType(ListViewItem、ListBoxItem、またはTreeViewItem)を使用してください。

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

コメントするのに十分な担当者がいないので、コメントを回答として投稿しています。上記のGrazerのソリューションは、Buttonを必要とするSelectedItemなどの別のコントロールがある場合は機能しません。これは、Style Trigger、そのIsKeyboardFocusWithinをクリックするとButtonがfalseになり、SelectedItemがnullになります。

6
dotnetzen

私は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プロパティのセッターに注意してください。 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>
3
Ben

この動作を設定するには、クラスハンドラーを使用します。このようにすると、アプリケーションのすべてのリストビューが修正されます。これがデフォルトの動作ではない理由がわかりません。

App.xaml.csで、OnStartupに以下を追加します。

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

TextboxがクリックイベントをListboxに転送するために設定する必要があるプロパティはありますか?

これは単純なプロパティではありませんが、GotFocusTextBox イベントを処理し、次に 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;
}
2
Robert Macnee
1
Natrium

以下は、DataTemplateをオーバーライドする必要のない@Benの回答を簡略化したものです。静的なスタイルとしても適用できます。 GridView > GridViewColumn > TextBoxを含むListViewでテストされています。

例:

<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>
1
Graeme Wicksted

これを行うために見つけた最も簡単な方法は、PreviewMouseDownイベントを使用して、テンプレート化された親のIsSelectedプロパティを設定することです。プレビューイベントはバブルダウンするので、ユーザーがテキストボックス、コンボボックス、またはイベントを設定したその他のコントロールをクリックするとすぐに、ListBoxItemがイベントを処理します。

これの1つの良い点は、すべてのタイプのコントロールがすべてフレームワーク要素から派生しているため、同じタイプのコントロールに同じイベントを使用できることです。また、(SelectedItemを設定する代わりに)IsSelectedを設定すると、リストボックスのSelectionModeを "Extended"に設定したときに複数の項目が選択されます。

つまり:

c#コード

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"/>
    ...
1
Mark Synowiec

古い議論ですが、おそらく私の答えは他の人を助けます...

ベンのソリューションには、グレイザーのソリューションと同じ問題があります。悪い点は、選択がテキストボックスの[キーボード]フォーカスに依存することです。ダイアログに別のコントロール(ボタンなど)がある場合、ボタンをクリックするとフォーカスが失われ、listboxitemが選択解除されます(SelectedItem == null)。そのため、(テキストボックスの外の)アイテムをクリックする場合と、テキストボックスをクリックする場合の動作が異なります。これは処理が非常に退屈で、非常に奇妙に見えます。

このための純粋なXAMLソリューションはないと確信しています。これにはコードビハインドが必要です。解決策はマークが提案したものに近いです。

(私の例では、ListBoxItemの代わりにListViewItemを使用していますが、ソリューションは両方で機能します)。

コードビハインド:

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"/>
0
Sven Bardos

前の回答で説明したように、選択を直接設定することを完全に確信しているわけではありません。複数選択や他のいくつかのシーンを壊してしまうためです。

。以下のようにボタンのスタイルを変更して、何が起こるか確認してみてください。

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

このコードを試してください:

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

リストボックスはアイテムの選択を処理しますが、埋め込まれたテキストボックスのフォーカスについては知りません。テキストボックスが入力フォーカスを取得するたびに選択を変更したい場合は、リストボックスの選択を手動で変更する必要があります。

0
Joey

あなたの初期状況についてあまり具体的ではありません。ただし、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) */
}
0
Marcel B