【问题标题】:ScrollViewer.ScrollToBottom not completely scrollingScrollViewer.ScrollToBottom 没有完全滚动
【发布时间】:2016-06-16 08:10:36
【问题描述】:

我创建了一个 WPF 控件,它允许我正在开发的应用程序的用户轻松选择要连接的 SQL Server。在控件上,存在三种不同类别的 SQL Server:本地、最近和网络上的更多服务器。

本地:运行应用程序的计算机上的 SQL Server 实例。

最近:用户最近连接的 SQL Server 实例。

网络上的更多服务器:通过在本地网络上发送搜索请求发现的 SQL Server 实例。 “网络上的更多服务器”不会自动填充,因为有时需要一段时间才能填充。大多数情况下,用户连接到最近使用的 SQL Server 实例,不需要浏览网络。

简而言之,这个控件由几个模板化的 ListBox 和 TextBlock 控件组成,所有这些控件都嵌套在一个主 WPF ScrollViewer 控件内。 ScrollViewer 将增长到适合所有内容所需的任何大小,并且 ScrollViewer 将允许用户滚动到该内容的任何部分。由于整个控件的 XAML 相当冗长,因此我将其压缩为伪代码以了解要点:

<Grid>
    <ScrollViewer x:name="mainScrollViewer">
        <StackPanel>
           <Grid>
             <Grid.RowDefinitions>
               ...
             <Grid.RowDefinitions />  

              <Textblock Text="Local" />
              <ListBox />
           </Grid>

            <Grid>
             ...
              <Textblock Text="Recent" />
              <ListBox />
           </Grid>

          ...

        <StackPanel>


    </ScrollViewer>


</Grid>

大门外,控件启动时是这样的:

如果用户需要在工作上浏览其他SQL Server实例,用户将单击“单击此处搜索本地网络”按钮。单击此按钮将生成一个单独的线程,该线程将执行搜索,同时保持 UI 响应。在此期间,控件会显示一个动画旋转的“等待” gif,如下所示:

当控件完成搜索后,用户将能够点击任何发现的服务器,就像在“本地”和“最近”部分中一样:

然而,根据本地网络环境和其他条件,搜索并不总是能找到所有可用的服务器。发生这种情况时,用户可以单击超链接按钮:“手动将服务器添加到此列表”。单击此超链接按钮时,DataTrigger 会折叠超链接并在其位置放置一个 TextBox,以便用户手动输入服务器名称:

出现文本框,允许用户输入用户名。文本框上有一个“KeyDown”事件的处理程序,用于侦听 ENTER 键。当按下 ENTER 键时,服务器被添加到列表中,文本框被折叠,并调用主 ScrollViewer 控件上的“ScrollToBottom()”方法并选择新添加的项。

以下是 KeyDown 处理程序的代码隐藏:

    private void txtAddServer_KeyDown(object sender, KeyEventArgs e)
    {
        if (e.Key == Key.Escape)
        {
            this.AddServerToListIsShown = false;
        }
        else if (e.Key == Key.Enter)
        {
            if (this.MoreServers == null)
                MoreServers = new ObservableCollection<DatabaseServer>();
            if (this.AllSQLServerNames == null)
                this.AllSQLServerNames = new ObservableCollection<string>();

            if (!this.MoreServers.Any(x => string.Compare(txtAddServer.Text, x.Description, true) == 0))
            {
                this.AllSQLServerNames.Add(this.txtAddServer.Text.ToUpper());
                this.MoreServers.Add(new DatabaseServer { Description = this.txtAddServer.Text.ToUpper(), ServerName = this.txtAddServer.Text.ToUpper() });

                var foundItem = this.MoreServers.FirstOrDefault(x => string.Compare(x.Description, this.txtAddServer.Text, true) == 0);
                if (foundItem != null)
                {
                    this.SelectedServer = foundItem;
                }

                this.AddServerToListIsShown = false;

                mainScrollViewer.ScrollToBottom();
            }
        }
    }

问题:

问题是,当手动添加服务器名称时,ScrollViewer 通常不会像应有的那样一直滚动到底部。根据控件的大小和列表中有多少服务器,它通常会在中间或底部的某个位置滚动(但不是一直滚动),如下所示:

为什么 ScrollViewer 不能一直滚动到底部???

【问题讨论】:

    标签: c# wpf scrollviewer dispatcher


    【解决方案1】:

    在考虑这个问题时,我尝试了一些不同的方法来更好地理解为什么 ScrollViewer 没有按应有的方式滚动到底部。我做的第一件事是添加一个带有“Scroll”内容的测试按钮,该按钮将调用滚动查看器的“ScrollToBotton()”方法。当我这样做时,每次尝试时,ScrollViewer 都会完美地滚动到底部。然后我突然想到,在调用“ScrollViewer.ScrollToBottom()”的同时,Dispatcher 仍在完成其他 UI 操作。我将调用“ScrollToBottom()”的 KeyDown 处理程序中的代码更改为以下内容:

                    Dispatcher.Invoke(new Action(() =>
                   {
                       mainScrollViewer.ScrollToBottom();
                    }), DispatcherPriority.ContextIdle, null);
                }
            }
    
        }
    

    这指示 Dispatcher 在尝试执行 ScrollToBottom() 之前完成其队列中的所有后台优先项,这会导致我的 ScrollViewer 每次都正确滚动。

    【讨论】:

    • 哇,这实际上帮助我解决了另一个问题。我试图检查 ScrollViewer 的 VerticalOffset,但直到所有代码完成运行后它才更新!似乎 WPF 领域的一切都是异步的 :( 这很痛苦......
    猜你喜欢
    • 2020-04-03
    • 2013-01-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-07-13
    • 2022-10-13
    • 2014-07-17
    相关资源
    最近更新 更多