ScrollBar value set incorrectly

2019-04-12 08:04发布

问题:

I am trying to implement something similar to Excel's "infinite" scrollability; in that a user can scroll to the "bottom" of the document; but then keep scrolling (using either the scrollwheel or the down arrow on the scrollbar), and more, empty rows are generated for them. I have this mostly working (when using the mouse scrollwheel it works perfectly); but I am having troubles with the SmallIncrement functionality - that is; when the user clicks the down arrow on the scrollbar, it should go down by scrollbar.SmallChange, despite being at the bottom of the scrollbar's scrollable range.

Here is my code (in the handler of scrollBar_Scroll):

int difference = e.NewValue - e.OldValue;
if (e.Type == ScrollEventType.SmallIncrement)
{
    if (difference != scrollBar.SmallChange)
    {
        int increase = (scrollBar.SmallChange - difference);
        scrollBar.Maximum += increase;
        scrollBar.Value += increase;
    }
}

Looking at it in the debugger, this sets the values exactly as I would expect. However, something (not sure what) happens after the function ends, causing scrollBar.Value to be set back to its original value, plus one. If I hold down the down-arrow, it works mostly correctly. It still jumps back up a bit once the button is released.

Any idea what could be causing this, and any way of fixing it?

Cheers!

Edit: Here is my scrollwheel code. It's so similar that it's confusing why it's not working. This is in the containing panel's MouseWheel event handler.

int desiredValue = scrollBar.Value - e.Delta;
scrollBar.MaximumValue = (Math.Max(normalBottom, desiredValue + scrollBar.LargeChange));
scrollBar.Value = Math.Max(0, desiredValue);

normalBottom is a variable remembering the "finite" ending of the scrollbar - in excel, this would be either the lowest user-entered data, or the height of the screen; so it scrolls normally above this value (without going negative).

回答1:

What is happening with your scrollbar is the following: when the user interacts with the scrollbar causing the event and your event handler is called the property value have not yet been updated, after you event handler returns the property is set internally by the scrollbar overwriting the value you set and causing the "jump back" effect you mention. How does it remember what value it have to set? Easy: it's in e.NewValue. And that's exactly your solution, to be able to correctly way to alter the final value of this property during the scroll event just write to e.NewValue as follows:

int difference = e.NewValue - e.OldValue;
        if (e.Type == ScrollEventType.SmallIncrement)
        {
            if (difference != scrollBar.SmallChange)
            {
                int increase = (scrollBar.SmallChange - difference);
                scrollBar.Maximum += increase;
                e.NewValue = scrollBar.Value + increase;
            }
        }

I want to link theese pages that may be relevant to you: http://msdn.microsoft.com/en-us/library/system.windows.forms.scrollbar.maximum.aspx

Note in remarks (This is why even moving the Maximun you still get it advance only 1):

The maximum value can only be reached programmatically. The value of a scroll bar cannot reach its maximum value through user interaction at run time. The maximum value that can be reached through user interaction is equal to 1 plus the Maximum property value minus the LargeChange property value. If necessary, you can set the Maximum property to the size of the object -1 to account for the term of 1.

http://msdn.microsoft.com/en-us/library/system.windows.forms.scrollbar.scroll.aspx http://msdn.microsoft.com/en-us/library/system.windows.forms.scrolleventargs.newvalue.aspx (Gets or sets the new Value of the scroll bar. [Emphasis in sets])