Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WPF StackPanel "Jumps"

Tags:

c#

wpf

xaml

I have a StackPanel that contains a TextBox and a Combobox.

When I set the focus inside a textbox (not the first one), the Contents of the StackPanel "jumps" and goes to the top.

Below is the code. I have researched this and post the one I found and tried (but did not worK).

I want to prevent the "jumping".

So run the code below. Scroll the vertical bar until you see:

Name Three       <<Text Box
(No Selection) ComboBox \/
Name Four      <<Text Box
(No Selection) ComboBox \/

Now put your cursor in the "Name Four" text box.......and watch it "jump" to the top. (You don't see Three and Four now, you see Four and Five.)

My stackpanel is much more complex than this in real life, and its driving my end-users nutty.

Thanks.

MainWindow.xaml

<Window x:Class="ListBoxControlSample.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="160" Width="250">
    <Grid Margin="10">
        <ListBox ItemsSource="{Binding Models}" SelectionMode="Single" RequestBringIntoView="FrameworkElement_OnRequestBringIntoView" SelectionChanged="Selector_OnSelectionChanged" >
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <StackPanel>
                        <TextBox Text="{Binding Name}"/>
                        <ComboBox VerticalContentAlignment="Top" VerticalAlignment="Top" Grid.Column="1" ItemsSource="{Binding Options}" >
                        </ComboBox>
                        <TextBlock Text="{Binding Title}"></TextBlock>
                    </StackPanel>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
    </Grid>
</Window>

MainWindow.xaml.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace ListBoxControlSample
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            DataContext = this;
        }

        private IList<Model> _models;
        public IList<Model> Models
        {
            get
            {
                return _models ?? (_models = new List<Model>
                    {
                        new Model{ Name = "Name One", Title = "Title One"},
                        new Model{ Name = "Name Two", Title = "Title Two"},
                        new Model{ Name = "Name Three", Title = "Title Three"},
                        new Model{ Name = "Name Four", Title = "Title Four"},
                        new Model{ Name = "Name Five", Title = "Title Five"},
                        new Model{ Name = "Name Six", Title = "Title Six"},
                        new Model{ Name = "Name Seven", Title = "Title Seven"}
                    });
            }
        }

        private void FrameworkElement_OnRequestBringIntoView(object sender, RequestBringIntoViewEventArgs e)
        {
            e.Handled = true;
        }

        private void Selector_OnSelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            //throw new NotImplementedException();
        }

        private void Selector_OnSelected(object sender, RoutedEventArgs e)
        {
            //throw new NotImplementedException();
        }
    }

    public class Model
    {
        public string Name { get; set; }
        public string Title { get; set; }
        private IList<string> _options;
        public IList<string> Options
        {
            get
            {
                return _options ?? (_options = new List<string>
                    {
                        "left",
                        "right",
                        "both"
                    });
            }
        }
    }
}

What I've found and tried (to prevent the jumping)

        <DataTemplate>
                    <StackPanel ScrollViewer.CanContentScroll="False">
like image 751
granadaCoder Avatar asked Sep 16 '25 18:09

granadaCoder


2 Answers

I'm guessing it has something to do with the default scroll behavior of trying to show the full item whenever it gets selected.

Try disabling the scrolling, and wrap it in another ScrollViewer:

<ScrollViewer VerticalScrollBarVisibility="Auto" CanContentScroll="True" Height="250">
    <ListBox ScrollViewer.VerticalScrollBarVisibility="Disabled">
        ...
    </ListBox>
</ScrollViewer>

This way, instead of trying to scroll each individual StackPanel into view at a time, and ensuring the full item is visible, it will try to scroll the entire ListBox into view, which exceeds the height allotted to the ScrollViewer, so it will use the smoother content-based scrolling that you want.

It should be noted that this will render the entire ListBox at once, without any virutalization, so it isn't advisable to use this method if you have a lot of rows and are depending on virtualization for performance. But based on your question, it doesn't sound like that is your case.

I'm also not positive, but you may have to nest this in one more panel as well to allow the ListBox to grow to whatever height it wants. See this answer for more details if needed.

like image 130
Rachel Avatar answered Sep 19 '25 07:09

Rachel


Here is another answer. It works with a simple WPF.

However, my real situation had an Infragistics control and Rachel's answer worked.

However, I want to post this for completeness.

I'm pasting the code from this url:

http://social.msdn.microsoft.com/Forums/vstudio/en-US/a3532b1f-d76e-4955-b3da-84c98d6d435c/annoying-auto-scroll-of-partially-displayed-items-in-wpf-listbox?forum=wpf

Here is the code:

  <ListBox.ItemContainerStyle>
            <Style TargetType="ListBoxItem">
                <EventSetter Event="RequestBringIntoView" Handler="ListBoxItem_RequestBringIntoView"/>
            </Style>
        </ListBox.ItemContainerStyle>

and

  void ListBoxItem_RequestBringIntoView(object sender, RequestBringIntoViewEventArgs e)
        {
            e.Handled = true;
        }
like image 42
granadaCoder Avatar answered Sep 19 '25 06:09

granadaCoder