it-swarm.com.de

Wie legen Sie programmgesteuert den Fokus auf das SelectedItem in einer WPF-ListBox fest, die bereits den Fokus hat?

Wir möchten den SelectedItemeines ListBoxnamens__ programmgesteuert festlegen und möchten, dass dieses Element dann den Fokus hat, damit die Pfeiltasten relativ zu dem ausgewählten Element funktionieren. Scheint einfach genug.

Das Problem besteht jedoch darin, dass der ListBoxbeim programmgesteuerten Festlegen von SelectedItembereits den Tastaturfokus hat, während die IsSelected-Eigenschaft für ListBoxItemordnungsgemäß aktualisiert wird. Daher wird der Tastaturfokus durch nicht und damit die Pfeiltasten festgelegt Bewegen Sie sich relativ zu dem zuvor fokussierten Element in der Liste und nicht wie erwartet zu dem neu ausgewählten Element.

Dies ist für den Benutzer sehr verwirrend, da die Auswahl bei der Verwendung der Tastatur anscheinend überspringt, während sie wieder an die Stelle zurückspringt, an der sie vor der programmgesteuerten Auswahl war.

Hinweis: Wie bereits erwähnt, geschieht dies nur, wenn Sie die Eigenschaft SelectedItemfür eine ListBoxprogrammgesteuert festlegen, die selbst bereits über den Tastaturfokus verfügt. Wenn dies nicht der Fall ist (oder wenn dies der Fall ist, aber Sie gehen, kehren Sie sofort zurück), und wenn der Tastaturfokus wieder auf ListBoxwechselt, hat das richtige Element nun wie erwartet den Tastaturfokus.

Hier ist ein Beispielcode, der dieses Problem zeigt. Um dies zu demonstrieren, führen Sie den Code aus, wählen Sie mit der Maus "Sieben" in der Liste aus (wobei der Fokus auf dem ListBoxliegt) und klicken Sie dann auf die Schaltfläche "Test". Tippen Sie abschließend auf die Alt-Taste Ihrer Tastatur, um das Fokus-Rechteck anzuzeigen. Sie werden sehen, dass es immer noch auf "Sieben" ist. Wenn Sie die Aufwärts- und Abwärtspfeile verwenden, beziehen sich diese auf diese Zeile und nicht auf "Vier", wie ein Benutzer dies erwarten würde.

Beachten Sie, dass Focusableauf der Schaltfläche auf falsegesetzt ist, um die Listbox beim Drücken nicht des Fokus zu berauben. Wenn ich dies nicht hätte, würde der ListBoxden Fokus verlieren, wenn Sie auf die Schaltfläche klicken, und wenn der Fokus wieder auf die ListBox gelegt wird, würde er sich auf dem richtigen Element befinden.

XAML-Datei:

<Window x:Class="Test.MainWindow"
    xmlns="http://schemas.Microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.Microsoft.com/winfx/2006/xaml"
    Width="525" Height="350" WindowStartupLocation="CenterScreen"
    Title="MainWindow" x:Name="Root">

    <DockPanel>

        <Button Content="Test"
            DockPanel.Dock="Bottom"
            HorizontalAlignment="Left"
            Focusable="False"
            Click="Button_Click" />

        <ListBox x:Name="MainListBox" />

    </DockPanel>

</Window>

Code-Behind:

using System.Collections.ObjectModel;
using System.Windows;

namespace Test
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();

            MainListBox.ItemsSource = new string[]{
                "One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight"
            };

        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            MainListBox.SelectedItem = MainListBox.Items[3];
        }

    }

}

Hinweis: Einige haben vorgeschlagen, IsSynchronizedWithCurrentItemzu verwenden, aber diese Eigenschaft synchronisiert den SelectedItemvon ListBoxmit der Current-Eigenschaft der zugeordneten Ansicht. Es hat nichts mit Fokus zu tun, da dieses Problem immer noch besteht.

Unser Workaround besteht darin, den Fokus vorübergehend an einer anderen Stelle zu setzen, dann das ausgewählte Element zu setzen und dann den Fokus wieder auf ListBoxzu setzen. Dies hat jedoch den unerwünschten Effekt, dass wir ViewModelauf den ListBoxnamen__ aufmerksam machen und dann die Logik abhängig davon ausführen ob es den Fokus hat oder nicht usw. (dh du würdest nicht einfach sagen wollen 'Fokus woanders, dann komm zurück, wenn' hier 'den Fokus nicht schon hatte, als du ihn von woanders stehlen würdest). ) Außerdem können Sie dies nicht einfach durch deklarative Bindungen handhaben. Das ist natürlich hässlich.

Andererseits "hässliche" Schiffe, also gibt es das.

33
MarqueIV

Es ist ein paar Zeilen Code. Wenn Sie es nicht im Code-Behind wollten, bin ich sicher, dass es in einem angehängten Verhalten verpackt werden könnte.

private void Button_Click(object sender, RoutedEventArgs e)
{
    MainListBox.SelectedItem = MainListBox.Items[3];
    MainListBox.UpdateLayout(); // Pre-generates item containers 

    var listBoxItem = (ListBoxItem) MainListBox
        .ItemContainerGenerator
        .ContainerFromItem(MainListBox.SelectedItem);

    listBoxItem.Focus();
}
49
jeff

Vielleicht mit einem angehängten Verhalten? So etwas wie

public static DependencyProperty FocusWhenSelectedProperty = DependencyProperty.RegisterAttached(
            "FocusWhenSelected", 
            typeof(bool), 
            typeof(FocusWhenSelectedBehavior), 
            new PropertyMetadata(false, new PropertyChangedCallback(OnFocusWhenSelectedChanged)));

private static void OnFocusWhenSelectedChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
    {
        var i = (ListBoxItem)obj;
        if ((bool)args.NewValue)
           i.Selected += i_Selected;
        else
           i.Selected -= i_Selected;
    }

static void i_Selected(object sender, RoutedEventArgs e)
{
    ((ListBoxItem)sender).Focus();
}

und in xaml

       <Style TargetType="ListBoxItem">
            <Setter Property="local:FocusWhenSelectedBehavior.FocusWhenSelected" Value="True"/>
        </Style>
2
Dtex

In deiner XAML hast du es versucht und nicht funktioniert?

<ListBox IsSynchronizedWithCurrentItem="True" ItemsSource="{Binding Path=YourCollectionView}" SelectedItem="{Binding SelectedItem}"></ListBox>

Und die SelectedItem-Eigenschaft:

    private YourObject _SelectedItem;
    public YourObject SelectedItem
    {
        get
        {
            return _SelectedItem;
        }
        set
        {
            if (_SelectedItem == value)
                return;

            _SelectedItem = value;

            OnPropertyChanged("SelectedItem");
        }
    }

Jetzt können Sie in Ihrem Code Folgendes tun:

SelectedItem = theItemYouWant;

Für mich funktioniert dieser Ansatz immer.

0
Dummy01

Zuerst) Sie müssen die ausgewählten Elemente in Listbox mit ListBox.Items.IndexOf () ..__ finden.
Second) Fügen Sie jetzt mit ListBox.SelectedItems.Add () Elemente hinzu.

Das ist mein Code:

DataRow[] drWidgetItem = dtItemPrice.Select(widgetItemsFilter);
lbxWidgetItem.SelectedItems.Clear(); foreach(DataRow drvItem in
drWidgetItem)
lbxWidgetItem.SelectedItems.Add(lbxWidgetItem.Items[dtItemPrice.Rows.IndexOf(drvItem)]);

Wenn Sie einen Artikel in ListBox auswählen möchten, können Sie diesen Weg verwenden:
ListBox.SelectedItem = (Ihr ListBoxItem);

Wenn Sie einige Elemente in ListBox auswählen möchten, müssen Sie diesen Weg verwenden:
ListBox.SelectedItems.Add (Ihr ListBoxItem);

0
Amintabar

Sie brauchen nur ListBox.SelectedItem und dann ListBox.ScrollIntoView (listBox.SelectedItem)

Beispielcode:

        private void textBox2_TextChanged(object sender, TextChangedEventArgs e)
    {

        var comparision = StringComparison.InvariantCultureIgnoreCase;
        string myString = textBox2.Text;
        List<dynamic> index = listBox.Items.SourceCollection.OfType<dynamic>().Where(x=>x.Nombre.StartsWith(myString,comparision)).ToList();
        if (index.Count > 0) { 
        listBox.SelectedItem= index.First();


            listBox.ScrollIntoView(listBox.SelectedItem);


        }

    }
0
Richard Aguirre