[wpf] Wenn Sie ein Textfeldelement in einem Listenfeld auswählen, wird das ausgewählte Element des Listenfelds nicht geändert


Answers

Wir verwenden den folgenden Stil, um einen PreviewGotKeyboardFocus festzulegen, der alle Ereignisse des TextBox-Steuerelements und der ComboBoxen behandelt:

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

Und dann wählen wir die Zeile im Code hinter:

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

Ich habe eine WPF-Listbox, die eine Liste von Textboxen anzeigt. Wenn ich auf die Textbox klicke, ändert sich die Listbox-Auswahl nicht. Ich muss neben dem Textfeld klicken, um den Listeneintrag auszuwählen. Gibt es eine Eigenschaft, die ich für das Textfeld festlegen muss, um das Klickereignis an die Listbox weiterzuleiten?




Sie sind nicht sehr genau über Ihre Ausgangssituation. Aber ich nehme an, dass Sie DataBinding und ein ItemTemplate verwenden. Thats imho eine einfache Möglichkeit, dies zu tun, auch wenn Ihr Anfänger zu diesem Thema. Das sollte funktionieren:

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






Alte Diskussion, aber vielleicht hilft meine Antwort anderen ...

Bens Lösung hat das gleiche Problem wie Grazer's Lösung. Das Schlimme ist, dass die Auswahl vom [Tastatur-] Fokus der Textbox abhängt. Wenn Sie ein anderes Steuerelement in Ihrem Dialogfeld haben (z. B. eine Schaltfläche), geht der Fokus verloren, wenn Sie auf die Schaltfläche klicken, und das Listenfeld wird nicht ausgewählt (SelectedItem == null). Sie haben also ein anderes Verhalten, wenn Sie auf das Element (außerhalb des Textfelds) klicken und in das Textfeld klicken. Dies ist sehr mühsam zu handhaben und sieht sehr seltsam aus.

Ich bin mir ziemlich sicher, dass es dafür keine reine XAML-Lösung gibt. Dafür brauchen wir Code-Behind. Die Lösung kommt dem nahe, was Mark vorgeschlagen hat.

(In meinem Beispiel verwende ich ListViewItem anstelle von ListBoxItem, aber die Lösung funktioniert für beide).

Code-hinten:

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

mit FindParent (entnommen von 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);
    }

In meiner DataTemplate:

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



Die Listbox behandelt die Elementauswahl, weiß aber nicht über den Fokus der darin eingebetteten Textbox. Wenn Sie die Auswahl jedes Mal ändern möchten, wenn ein Textfeld den Eingabefokus erhält, müssen Sie die Listenfeldauswahl manuell ändern, afaik.




Gibt es eine Eigenschaft, die ich für das Textfeld festlegen muss, um das Klickereignis an die Listbox weiterzuleiten?

Es ist keine einfache Eigenschaft, aber Sie können das GotFocus Ereignis in Ihrem TextBox und anschließend mit VisualTreeHelper das ListBoxItem VisualTreeHelper suchen und auswählen:

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



Ich habe ähnlich wie Roberts Lösung gearbeitet, aber ohne Code dahinter (mit angehängtem Verhalten).

Um dies zu tun,

Zuerst. Erstellen Sie eine separate Klasse 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
    }
}

Zweite. Fügen Sie einen Stil im Ressourcenbereich hinzu (mein Stil ist im Fokus schwarz gerundet). Benachrichtigungssetter für die FocusBehaviour.IsListBoxItemSelected-Eigenschaft. Du solltest es in xmlns:behave="clr-namespace:MyBehaviours" referenzieren 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>

`

Dritte. (optional, für umgekehrte Aufgabe)

Sie werden, wenn nicht, eine Reverse-Aufgabe treffen, die sich auf TextBox konzentriert, wenn ListBoxItem ausgewählt wird. Ich empfehle, eine andere Eigenschaft der Behavior-Klasse IsFokussiert zu verwenden. Hier ist eine Beispielvorlage für ListBoxItem , ListBoxItem Sie bitte Property="behave:FocusBehaviour.IsFocused" und 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>



Links