简体   繁体   English

WPF StackPanel“跳转”

[英]WPF StackPanel “Jumps”

I have a StackPanel that contains a TextBox and a Combobox. 我有一个包含文本框和组合框的StackPanel。

When I set the focus inside a textbox (not the first one), the Contents of the StackPanel "jumps" and goes to the top. 当我将焦点设置在文本框(而不是第一个文本框)中时,StackPanel的内容“跳转”并转到顶部。

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 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 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">

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中:

<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. 这样,它不会尝试一次将每个StackPanel滚动到视图中并确保整个项目可见,而是尝试将整个ListBox滚动到视图中,这超出了分配给ScrollViewer的高度,因此它将使用所需的基于内容的滚动更流畅。

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. 应该注意的是,这将立即渲染整个ListBox ,而不进行任何虚拟化,因此,如果您有很多行并且依赖于虚拟化来提高性能,则不建议使用此方法。 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. 我也不是很肯定,但是您可能还必须将其嵌套在另一个面板中,以使ListBox可以增长到所需的高度。 See this answer for more details if needed. 如果需要,请参阅此答案以获取更多详细信息。

Here is another answer. 这是另一个答案。 It works with a simple WPF. 它与简单的WPF一起使用。

However, my real situation had an Infragistics control and Rachel's answer worked. 但是,我的实际情况是Infragistics控制的,Rachel的答案起作用了。

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 http://social.msdn.microsoft.com/Forums/vstudio/en-US/a3532b1f-d76e-4955-b3da-84c98d6d435c/annoying-auto-scroll-of-partially-displayed-items-in-wpf-listbox?论坛= 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;
        }

The effect is reproducible if you click into the TextBox of the last visible row. 如果您单击到最后一个可见行的文本框,效果是可重现的。 If that row isn't fully scrolled into the view the listbox automatically scrolls that line into view to be fully visible. 如果该行没有完全滚动到视图中,则列表框会自动将该行滚动到视图中以使其完全可见。 That in turn means all rows scroll up one row which makes you feel the jumping effect. 这又意味着所有行向上滚动一行,使您感受到跳跃的效果。 To my knowledge you cannot change that behaviour. 据我所知,您无法改变这种行为。

When a command like SetFocus runs on a child of the scrollviewer, it triggers a ReqestBringInto view on the scrrollviewer but the act of scrolling to the child controls is implemented under the covers by the scrollviewer's ScrollInfo object. 当类似SetFocus的命令在scrollviewer的子级上运行时,它会在scrrollviewer上触发ReqestBringInto视图,但是滚动到子控件的动作是由scrollviewer的ScrollInfo对象在幕后实现的。

I think the key here is to create a class which implements IScrollInfo. 我认为这里的关键是创建一个实现IScrollInfo的类。 I implemented one to override the amount the SV scrolls when using the mouse wheel. 我实现了一个方法来覆盖使用鼠标滚轮时SV滚动的数量。 In my case, I cloned the default implementation from the .NET source for ScrollContentProvider ) and changed some properties. 就我而言,我从.NET源中为ScrollContentProvider克隆了默认实现,并更改了一些属性。

Internally, ScrollViewer will call the IScrollInfo::MakeVisible() on the desired child control. 在内部,ScrollViewer将在所需的子控件上调用IScrollInfo :: MakeVisible()。 You could just ignore that request. 您可以忽略该请求。

Create an instance of your own scroll provider to the scrollviewer using something like: 使用以下类似方法为scrollviewer创建您自己的滚动提供程序的实例:

var myProvider = new MyScrollInfo();
myScrollViewer.ScrollInfo = myProvider;

用这个:

<ListBox ScrollViewer.PanningMode="None">

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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