简体   繁体   中英

WPF: How to keep ListBox SelectedItem visible after resizing?

In our current C# MVVM project we use a ListBox to display items.

There is another container that can be expanded below the ListBox.

Everything is working fine. When the container expands, the ListBox contracts and the ScrollBar appears.

However if an element is selected at the bottom of the ListBox and the container is expanded the item disappears at the end of the ListBox .

Example:

Before container expansion:

+--------------+
| Item 1       |
+--------------+
| Item 2       |
+--------------+
| Item 3       |
+--------------+
| Item 4       |
+--------------+
| SelectedItem |
+--------------+
| Item 6       |
+--------------+
| Item 7       |
+--------------+

+------------------+
| Container        |
+------------------+

After container expansion:

+--------------+---+
| Item 1       | S |
+--------------+ c |
| Item 2       | r |
+--------------+ o |
| Item 3       | l |
+--------------+ l |
| Item 4       |   |
+--------------+---+

+------------------+
|                  |
|                  |
| Container        |
|                  |
|                  |
+------------------+

What I would like to achieve is keeping visible SelectedItem without having to scroll to it.

Like so:

+--------------+---+
| Item 2       | S |
+--------------+ c |
| Item 3       | r |
+--------------+ o |
| Item 4       | l |
+--------------+ l |
| SelectedItem |   |
+--------------+---+

+------------------+
|                  |
|                  |
| Container        |
|                  |
|                  |
+------------------+

What is the best way to achieve this?

I couldn't find anything about it here on SO or anything else.

I have seen that it was possible to scroll programmatically:

I have also seen it was possible to know when a ListBoxItem comes into view ( here and there ) but as my items are already loaded then hidden I don't think this will work.

I don't want to have code-behind that I must copy in every view where I need this functionnality. I have thought about implementing this in a Behavior attached to the ListBox but I highly doubt this would be the best solution.

I have also thought about writing a custom ListBox control but I think this is too much for such a small functionality.

Can someone tell me the best way to achieve this kind of behavior? Thanks in advance.

A Behavior is the ideal way to add this functionality to a control. The code below will scroll the ListBox's SelectedItem into view after a selection changed or resize.

public class perListBoxHelper : Behavior<ListBox>
{
    protected override void OnAttached()
    {
        base.OnAttached();
        AssociatedObject.SelectionChanged += AssociatedObject_SelectionChanged;
        AssociatedObject.SizeChanged += AssociatedObject_SizeChanged;
    }

    protected override void OnDetaching()
    {
        AssociatedObject.SelectionChanged -= AssociatedObject_SelectionChanged;
        AssociatedObject.SizeChanged -= AssociatedObject_SizeChanged;
        base.OnDetaching();
    }

    private static void AssociatedObject_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        ScrollSelectionIntoView(sender as ListBox);
    }

    private static void AssociatedObject_SizeChanged(object sender, SizeChangedEventArgs e)
    {
        ScrollSelectionIntoView(sender as ListBox);
    }

    private static void ScrollSelectionIntoView(ListBox listBox)
    { 
        if (listBox?.SelectedItem == null)
            return;

        Action action = () =>
        {
            listBox.UpdateLayout();
            listBox.ScrollIntoView(listBox.SelectedItem);
        };

        listBox.Dispatcher.BeginInvoke(action, DispatcherPriority.ContextIdle);
    }
}

Usage

<ListBox ... >
    <i:Interaction.Behaviors>
        <vhelp:perListBoxHelper />
    </i:Interaction.Behaviors>
</ListBox>

More discussion about behaviors on my recent blog post .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM