Calculate new ScrollPercent - after ViewSize changed
Asked Answered
P

1

10

First of all, basically I believe I just need help in figuring out how to calculate it, math isnt really my strong side.

FYI, the MS-Word is most likely not relevant to solve my problem, I basically just mention it so you know the context I am in, but I believe it should be solvable also for people who have no knowledge about MS-Word.

I have the problem that Word has the property VerticalPercentScrolled which is an integer.

Which isnt as accurate as I need it to be, consider a Word Document with 300 pages and the scrollbar can only have a integer between 0 - 100 (percent), so for example 25 percent of a 300 page document is a rather big range.

I have now gone and read the correct value, with the help of UI Automation library - TestStack.White - and can successfully set it to its old value, if some un-desired scrolling happens.

Like this:

var hWnd = (IntPtr)WordUtils.GetHwnd();
var processId = Process.GetCurrentProcess().Id;

var uiApp = TestStack.White.Application.Attach((int)processId);
var uiWindow = uiApp.GetWindow(WindowHandling.GetWindowText(hWnd), InitializeOption.NoCache);

var wf = (IUIItemContainer)uiWindow.Get(SearchCriteria.ByClassName("_WwF"));
var wbs= wf.GetMultiple(SearchCriteria.ByClassName("_WwB"));
if (wbs.Length != 1)
    return;

var wb= (IUIItemContainer)wbs.First();
var wgs = wb.GetMultiple(SearchCriteria.ByClassName("_WwG"));
if (wgs.Length != 1)
    return;

var wg = wgs.First();
var element = wg.AutomationElement;

var oldVerticalPercent = (double)element.GetCurrentPropertyValue(ScrollPattern.VerticalScrollPercentProperty);

with this code I get a percent value of lets say 9.442248572683356 instead of 9.

To reset the value I use the following code:

object scrollPattern;
if (element.TryGetCurrentPattern(ScrollPattern.Pattern, out scrollPattern))
    ((ScrollPattern)scrollPattern).SetScrollPercent(ScrollPattern.NoScroll, oldVerticalPercent);

This works like a charm.

Now my problem is what if my document gets larger/smaller during the time I stored the oldValue and want to reapply it, my oldValue needs to be adjusted.

I can read the following values (at least those I found so far):

  1. ScrollPattern.VerticalScrollPercentProperty
  2. ScrollPattern.VerticalViewSizeProperty

I can also go and look for the scrollbar it self and read the following values:

  1. RangeValuePattern.LargeChangeProperty
  2. RangeValuePattern.MaximumProperty
  3. RangeValuePattern.MinimumProperty
  4. RangeValuePattern.SmallChangeProperty
  5. RangeValuePattern.ValueProperty

To look for the scrollbar, I use the following code:

var hWnd = (IntPtr)WordUtils.GetHwnd();
var processId = Process.GetCurrentProcess().Id;

var uiApp = Ts.Application.Attach((int)processId);
var uiWindow = uiApp.GetWindow(WindowHandling.GetWindowText(hWnd), InitializeOption.NoCache);

var wf = (IUIItemContainer)uiWindow.Get(SearchCriteria.ByClassName("_WwF"));
var wbs = wf.GetMultiple(SearchCriteria.ByClassName("_WwB"));
if (wbs.Length != 1)
    return;

var wb = (IUIItemContainer)wbs.First();
var wgs= wb.GetMultiple(SearchCriteria.ByClassName("_WwG"));
if (wgs.Length != 1)
    return;

var nUiScrollBars = wgs.GetMultiple(SearchCriteria.ByClassName("NUIScrollbar"));
if (scrollBar.Length != 1)
    return;

var nUiScrollBar = (IUIItemContainer)nUiScrollBars.First();
var nUiHwndElements = nUiScrollBar.GetMultiple(SearchCriteria.ByClassName("NetUIHWNDElement"));
if (nUiHwndElements.Length != 1)
    return;

var nUiHwndElement = (IUIItemContainer)nUiHwndElements.First();
var netUiScrollBar = nUiHwndElement.GetElement(SearchCriteria.ByClassName("NetUIScrollBar"));

var scrollBarValue = (double)netUiScrollBar.GetCurrentPropertyValue(RangeValuePattern.ValueProperty);

You may ask yourself, why I dont set the RangeValuePattern.ValueProperty when I am able to access it, the problem there is that Word doesnt update the document when I change this property, the scroll thumb does move but the document doesnt move an inch.

I have to set the ScrollPattern.VerticalScrollPercentProperty for it to work.

So my question, is how do I calculate the new ScrollPattern.VerticalScrollPercentProperty based on the oldValue, where the document could shrink or grow in size in between?

Edit:

Here is a testscenario:

scrollPercent       64.86486486486487
scrollViewSize      74.394463667820062
scrollBarLargeChange    37197
scrollBarMaximum        12803
scrollBarMinimum        0
scrollBarSmallChange    1
scrollBarValue      8304

After inserting 5 new pages

scrollPercent       87.890366182251867 <-- undesired scrolling occured (see desired values below)
scrollViewSize      9.442248572683356
scrollBarLargeChange    4721
scrollBarMaximum        45279
scrollBarMinimum        0
scrollBarSmallChange    1
scrollBarValue      39795 <-- undesired scrolling occured (see desired values below)

And as said, I need to adjust the scrollPercent - after inserting those pages - so that it is again on the old position.

I can tell you that in this testscenario, I would need the new value to be

scrollPercent       2.3278413357480452

after changing it to the desired percentValue the scrollBarValue is the only value getting updated and it is than at

scrollBarValue      1054
Prayer answered 7/8, 2017 at 9:14 Comment(4)
Are you sure the new value of scrollPercent should be 2.32..., I think it should be 18.339627642. If it is 2.32, how did you get that value?Abelmosk
@RobAnthony I scrolled to the exact same position as it was in the first place and this is what I get, aslo tried to set it hardcoded where the calculation should happen and it works fine.Prayer
I can't make sense of the numbers you have given in the example. The connection between ScrollPercent, ScrollBarMaximum and ScrollBarValue is easy to work out it is ScrollPercent = ScrollBarValue / ScrollBarMaximum. This works for both sets of numbers. It also connects the 2.32 value to 1054 and 45279 but If you are 64% of the way through a document sized 12803 you would be 18% of the way through a document sized 45279, not 2.32%Abelmosk
@RobAnthony I believe you didn't take into account that when the ViewSize is relatively small and the scroll thumb is rather big that the scroll value isn't the top of the thumb I think it's the bottom. There for you are getting different results. I believe this can be seen when you compare the scroll bar max in comparison to the large change, the large change is way bigger than the scroll maximum.Prayer
D
1

So, it looks like your scrollPercent is calculated like this:

scrollPercent = 100.0 * scrollBarValue / (scrollBarMaximum - 1);

So the math should work out like this (assuming floating-point division):

scrollPercentOld = 100.0 * scrollBarValueOld / (scrollBarMaximumOld - 1)
scrollPercentNew = 100.0 * scrollBarValueOld / (scrollBarMaximumNew - 1)

From that, you have:

scrollBarValueOld = scrollPercentOld * (scrollBarMaximumOld - 1) / 100.0
scrollBarValueOld = scrollPercentNew * (scrollBarMaximumNew - 1) / 100.0

When you equate the two, you get:

scrollPercentOld * (scrollBarMaximumOld - 1) = scrollPercentNew * (scrollBarMaximumNew - 1)

And then finally:

scrollPercentNew = scrollPercentOld * (scrollBarMaximumOld - 1) / (scrollBarMaximumNew - 1)
Dday answered 16/8, 2017 at 8:18 Comment(14)
What would be the "total height"? Can I assume it is the scrollbarMaximum?Prayer
I just edited my answer to use the terms & names from your question. Just did some calculations, looks like "total height" corresponds to (scrollBarMaximum - 1)Expertise
That seems to be the same approach @RobAnthony used (see comments below question), since your calculation also results in 18.34. Which isnt correct, the new scrollPercent should be 2.3278413357480452. Thats what I used 64,8648648648648*(12803-1)/(45279-1)Prayer
P.S. When calculated this way, scrollPercentNew should maintain the same scrollBarValue between the changes - but, perhaps I misunderstood you. Why 2.3278413357480452?Expertise
Thats the new value I get when I manually move the position to the place where it was before, thats why.Prayer
Are you by any chance inserting or removing pages at a location that comes before the current scroll position? Because then what I proposed wouldn't work, and you would need to track these changes somehow.Expertise
No, just after the scroll position. I have a new created word document (nothing fancy). I inserted 3 line breaks and wrote "Hello", put the cursor after the word. Than I scroll 4 times which results in the letters "Hello" almost not visible bascially just litte lines can be seen (maybe 1 millimeter of the letters). Than I call the method Application.Selection.InsertNewPage(); 5 times. Word than moves the scroll to the last page (6th page) and I desire the scroll position unchanged, I there for manually scroll back where I was and again evaluate the values and thats what I get.Prayer
Hm... Are you sure you haven't mixed up values from two different tests?Expertise
100% sure. Would it help if I provide you my test document?Prayer
I'm asking because the scrollBarValue = 1054 and scrollPercent = 2.3278413357480452 give scrollBarMaximum = 45278, which is different from the 39795 in your test scenario. If you are 100% sure though, then either I made wrong assumptions about how this is calculated, or there's something funky going on with the code.Expertise
? but the scrollBarMaximum is 45279 the 39795 you are talking about is the scrollBarValue which is the incorrect value after inserting 5 pages.Prayer
I'm sorry I got the numbers mixed up. I have another idea. The way this should work is that the old value should be multiplied by a scaling factor. So scrollPercentNew = scrollPercentOld * k, where k is the unknown factor. For the example you give, this yields about 0.03588755, but this only works for that particular scenario. The only way I found to reconstruct that number is to do this: (scrollBarMaximumOld / scrollBarLargeChangeOld) / (scrollBarMaximumNew / scrollBarLargeChangeNew); with your test values, this gives approximately 0.03588732, which is pretty close.Expertise
Essentially, scrollBarMaximum / scrollBarLargeChange expresses the scrollBarMaximum in "units" of the large change, and my hope is that this will remain consistent after you change the number of pages. (Note: Make sure to test this with different numbers of inserted pages. Also, I'm writing in the comment section as I'm not certain this will work.)Expertise
Its a tiny bit off when I insert 500 pages instead of 5, but looks promising.Prayer

© 2022 - 2024 — McMap. All rights reserved.