如何停止Winforms面板的滚动?

24

如果您在高度为300像素的面板上放置了一个高度为400像素的DataGridView,以便面板上有一个滚动条,然后向下滚动,使得网格的下半部分显示出来,然后单击面板外的控件,再单击网格中的一行,则面板会滚动到顶部,选择的网格行不正确。

这不仅仅是DataGridView;任何高于面板的控件都会发生,例如Infragistics UltraWinGrid、富文本框等。我曾向Infragistics提出它是一个错误,但他们说这是一个Microsoft问题。

我尝试使用所有相关的控件事件,但面板滚动会在事件触发之前发生。

有什么建议吗?

4个回答

53

这是由于ScrollableControl类自动触发了ScrollToControl事件,并且事件处理程序滚动以显示获取焦点的控件的左上角。当可滚动容器控件只包含一个控件时,此行为是不帮助的。在我找到停止它的方法之前,我非常沮丧。

停止此行为的方法是覆盖ScrollToControl事件处理程序,像这样:

class PanelNoScrollOnFocus : Panel
{
    protected override System.Drawing.Point ScrollToControl(Control activeControl)
    {
        return DisplayRectangle.Location;
    }
}

用这个面板控件替换你的面板控件。 完成。


5
谢谢,我已经在桌子上猛敲了一个小时。你的解决方案避免了前往医院的旅程! :) - virtualmic
谢谢!这就是我需要的解决方案。 - Cuthbert
我该如何实现这个? - CularBytes
5
首先,将此类添加到您的项目中(创建一个新的空类文件并粘贴上面的代码)。 然后转到表单设计器并查看工具箱。 您现在应该看到一个新控件列在那里,名为PanelNoScrollOnFocus。 将其拖放到画布上;使用它作为您的面板,而不是使用普通的Panel。 要更改现有的表单,请手动编辑.designer.cs文件;搜索“System.Windows.Forms.Panel”,并替换每个Panel的行为为PanelNoScrollOnFocus。 - stone
完美的解决方案,而且代码如此简洁。 - T.S

2
我猜你正在将面板的AutoScroll属性设置为true。这样做会导致切换应用程序时,滚动位置重置为零,面板也会重置其位置。
如果您关闭AutoScroll并添加自己的滚动条,可以将滚动条的最大和最小值设置为与面板要求相匹配,然后在滚动条的滚动事件中设置面板的滚动值。这不会在切换窗口时重置。
类似这样:
private void vScrollBar1_Scroll(object sender, ScrollEventArgs e)
{
    panel1.VerticalScroll.Value = vScrollBar1.Value;
}

这对我来说是新的,我需要重新创建它。也许我需要在我的网站上添加一篇文章来介绍它 :-)

谢谢,看起来很有前途。我们在使用VScrollBar时遇到了一些闪烁的问题,但我相信我们可以想出一些可行的解决方案。这确实解决了原来的跳动问题。 - Paul S

1

谢谢skypecakes,这个方法非常好用 :) 这是你的控件的编辑版本,还可以跟踪滚动条的位置:

class AutoScrollPanel : Panel
{
    public AutoScrollPanel()
    {
        Enter += PanelNoScrollOnFocus_Enter;
        Leave += PanelNoScrollOnFocus_Leave;
    }

    private System.Drawing.Point scrollLocation;

    void PanelNoScrollOnFocus_Enter(object sender, System.EventArgs e)
    {
        // Set the scroll location back when the control regains focus.
        HorizontalScroll.Value = scrollLocation.X;
        VerticalScroll.Value = scrollLocation.Y;
    }

    void PanelNoScrollOnFocus_Leave(object sender, System.EventArgs e)
    {
        // Remember the scroll location when the control loses focus.
        scrollLocation.X = HorizontalScroll.Value;
        scrollLocation.Y = VerticalScroll.Value;
    }

    protected override System.Drawing.Point ScrollToControl(Control activeControl)
    {
        // When there's only 1 control in the panel and the user clicks
        //  on it, .NET tries to scroll to the control. This invariably
        //  forces the panel to scroll up. This little hack prevents that.
        return DisplayRectangle.Location;
    }
}

这仅适用于 Panel 中只有一个控件的情况(尽管我还没有测试过多个控件的情况)。


0

我理解你的痛苦,这个问题曾经困扰过我不止一次。

如果你的DataGridView是面板中唯一的元素,只需将其Dock属性设置为Fill,让DGV自己处理滚动即可。我认为它不会再出现跳动的情况了。否则,你可以将其大小调整为小于面板大小,并让其自行处理滚动。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接