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):
ScrollPattern.VerticalScrollPercentProperty
ScrollPattern.VerticalViewSizeProperty
I can also go and look for the scrollbar it self and read the following values:
RangeValuePattern.LargeChangeProperty
RangeValuePattern.MaximumProperty
RangeValuePattern.MinimumProperty
RangeValuePattern.SmallChangeProperty
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
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)
Related
I have a progress bar for a image download in my ASP.NET application.
In a while loop is the following code, in which I divide the length of bytes from the current stream by the expected stream to get the desired progress:
if (ExpectedStreamSize.HasValue && _configSize.HasValue)
{
var expected = ExpectedStreamSize + _configSize.Value;
var progress = _stream.ReadPosition / (float) expected;
var limitedProgress = progress > 1 ? 1 : progress;
var epsilon = 0.001;
if (!_lastReportedProgress.HasValue || _lastReportedProgress.Value + epsilon < limitedProgress)
_onProgressChanged?.Invoke(limitedProgress);
_lastReportedProgress = limitedProgress;
LogToFile(limitedProgress); // Logged to see the values
}
However, I expect values from 0 to 1. So from 0% to 100%.
When I debug I get the following value assignments:
ExpectedStreamSize.HasValue = true
_configSize.HasValue = 1714
ExpectedStreamSize = 8700000 // 8.7 MB
_configSize.Value = 1714
--> expected: 8701714
_stream.ReadPosition = 1722
expected: 8701714
--> progress = 0.000197892048
I logged the values for the limitedProgress, which are the following ones:
0,000197892
0,0001981219
0,0001983517
...
0,0004684135
But I need the values from 0,00019xxxx to 1,0 (so that I reach the 100%).
Can someone explain to me what I am doing wrong and how to get the correct progress status?
So I found the bug myself and fixed it.
lastReportedProgress = limitedProgress of course belongs in the if loop, that's wrong otherwise.
The upper solution would probably have worked, but the time expenditure would have been extreme, because too many intermediate steps are output and queried here.
Now it works and the log also returns the values I imagined:
0,001000033
0,002000066
...
0,9970638
0,998064
0,9990641
I also adjusted the float value above to make the second condition in the if loop look better.
private float _lastReportedProgress = 0;
// some code
if(...)
{
if (_lastReportedProgress + epsilon < limitedProgress)
}
Using Excel Interop, I can configure a sheet for printing with code like this:
_xlSheetPlatypus.PageSetup.PrintArea = "A1:" +
GetExcelTextColumnName(
_xlSheetPlatypus.UsedRange.Columns.Count) +
_xlSheetPlatypus.UsedRange.Rows.Count;
_xlSheetPlatypus.PageSetup.Orientation = Excel.XlPageOrientation.xlLandscape;
_xlSheetPlatypus.PageSetup.Zoom = false;
_xlSheetPlatypus.PageSetup.FitToPagesWide = 1;
_xlSheetPlatypus.PageSetup.FitToPagesTall = 100;
_xlSheetPlatypus.PageSetup.LeftMargin = _xlApp.Application.InchesToPoints(0.5);
_xlSheetPlatypus.PageSetup.RightMargin = _xlApp.Application.InchesToPoints(0.5);
_xlSheetPlatypus.PageSetup.TopMargin = _xlApp.Application.InchesToPoints(0.5);
_xlSheetPlatypus.PageSetup.BottomMargin = _xlApp.Application.InchesToPoints(0.5);
_xlSheetPlatypus.PageSetup.HeaderMargin = _xlApp.Application.InchesToPoints(0.5);
_xlSheetPlatypus.PageSetup.FooterMargin = _xlApp.Application.InchesToPoints(0.5);
_xlSheetPlatypus.PageSetup.PrintTitleRows = String.Format("${0}:${0}", CUSTOMER_HEADING_ROW);
I think I can pretty much emulate that with Spreadsheet Light with this code:
SLPageSettings ps = new SLPageSettings();
// PrintArea
// ???
// PrintTitleRows
ps.PrintHeadings = true;
ps.SetCenterHeaderText(String.Format("${0}:${0}", CUSTOMER_HEADING_ROW);
// Margins
ps.SetNarrowMargins();
ps.TopMargin = 0.5;
ps.BottomMargin = 0.5;
ps.LeftMargin = 0.5;
ps.RightMargin = 0.5;
ps.HeaderMargin = 0.5;
ps.FooterMargin = 0.5;
// Orientation
ps.Orientation = OrientationValues.Landscape;
// Zoom
//psByCust.ZoomScale = what should this be? Is not a boolean...
// FitToPagesWide
//psByCust.FitToWidth = ; "cannot be assigned to" so how can I set this?
// FitToPagesTall
//psByCust.FitToHeight = 100; "cannot be assigned to" so how can I set this?
I'm not sure about many of these, though, especially the replacement code for "PrintTitleRows" ("PrintHeadings" and "SetCenterHeaderText"), but one thing seems to be totally missing from Spreadsheet Light, namely "PrintArea".
Also, what should the "Zoom" value be? And what corresponds to "FitToPagesWide" and "FitToPagesTall"?
What is the analagous way to accomplish the same thing with Spreadsheet Light? Or does Spreadsheet Light just automatically determine the range to print based on non-empty cells?
I can help with some of these. First up, Print Area.
As Vincent says: Rule 1: Everything begins and ends with SLDocument
SLDocument myWorkbook = new SLDocument();
myWorkbook.SetPrintArea("A1", "E10");
// or
myWorkbook.SetPrintArea(1, 1, 10, 5);
Next: Fit to Pages:
SLPageSettings settings = new SLPageSettings();
settings.ScalePage(2, 3) // print 2 pages wide and 3 long
// There is no info on how to just scale in one dimension, I would use
// a definitely too big™ number in the field you don't care about
// Eg for fit all columns on one page:
settings.ScalePage(1, 99999);
Zoom is a view (not print) thing AFAIK and can be changed between 10 and 400 to set the Zoom percentage - equivalent to Ctrl-scrolling when viewing a spreadsheet.
PrintHeadings displays the row (1, 2, 3, ...) and column headings (A, B, C, ...) when you print, so you can see the value in say, D25 easier.
For printing titles, you use the Set<position>HeaderText in SLPageSettings:
settings.SetCenterHeaderText("My Workbook Title");
Similarly SetLeftHeaderText and SetRightHeaderText
I don't know how to set 'RowsToRepeatAtTop' and 'ColumnsToRepeatAtLeft' which would match Interop's PrintTitleRows.
ProTip: The chm help file that comes with SpreadsheetLight is very useful.
I would really appreciate it if someone could tell me the best approach to splitting a list which contains text data. The current program reads a text file and stores the values to a list, the number of lines/data is not constant so i wanted to split the full list in percentage if that's possible for example the first 15% = start, the next 70% = middle and finally the last 15% = end.
Additional info = the program monitors a running session hence the start(warm up) middle (main run) and end (cool down) aspect to the question. Ultimately i want to be able to incorporate this into a zedgraph and show my performance in the running sessions.
I am having a problem researching this and putting it into computational terms, i do appreciate your knowledge and time.
You can use a little Linq:
var index1 = (int) Math.Round(array.Length * .15);
var index2 = (int) Math.Round(array.Length * .70);
var start = array.Take(index1);
var middle = array.Skip(index1).Take(index2 - index1);
var end = array.Skip(index2);
See Take and Skip methods.
You could also use the ArraySegment<T> class:
var index1 = (int) Math.Round(array.Length * .15);
var index2 = (int) Math.Round(array.Length * .70);
// Replace T with your class name
var start = new ArraySegment<T>(array, 0, index1);
var middle = new ArraySegment<T>(array, index1, index2 - index1);
var end = new ArraySegment<T>(array, index2, array.Length - index2);
Only in the System.Console do I get the result, it print the number of characters that are left, and it update it
So whats wrong, how do i update it in the Element?
Hope you guys can help me with this.
Console:
Characters typed(left): in Value it should write the number of characters that are left.
var root = new RootElement ("Send Message");
var messageElement = new MultilineEntryElement ("", "0123456789")
{
Editable = true,
Height = 120
};
var messageSection = new Section ();
int leangtOfChar = 200 - messageElement.Value.Length;
var lengthElement = new StringElement ("characters typed:", leangtOfChar.ToString());
messageElement.Changed += delegate {
System.Console.WriteLine (leangtOfChar.ToString ());
//lengthElement.Value = (leangtOfChar.ToString());
};
root.Add(messageSection);
The problem is that when you update a normal StringElement it doesn't automatically update the attached cell.
To force an update for just that cell, I would recommend either:
calling root.Reload(lengthElement, UITableViewRowAnimation.Fade) after you change the value
or using a custom element/cell type instead of StringElement - basically you could model this on the simple code in BooleanElement - but use a UILabel as the accessory instead of a UISwitch.
If you wanted to go further - to actually allow StringElement to be updated without a reload - then you can do this by modifying the Element class to track whether a cell instance is currently attached. I've done exactly that in a databinding branch of monotouch.dialog - https://github.com/slodge/MvvmCross/blob/master/Cirrious/Cirrious.MvvmCross.Dialog/Dialog/Elements/Element.cs - but this is almost certainly overkill for what you are trying to do right now.
I'm using the latest version of iTextSharp found here: http://sourceforge.net/projects/itextsharp/
I am trying to use ColumnText.SetSimpleColumn after getting the position of some AcroFields using GetFieldPositions( fieldName ).
All the examples I can find show GetFieldPositions returning a float[] however this doesn't appear to be the case anymore. It now appears to be returning IList which doesn't (according to Visual Studio) implicitly convert to a float[].
Inside the return value at the 0 index is a position member that is a Rectangle, but since the examples I've seen perform math operations on the returned float[] I'm not sure what values from the return value in GetFieldPostions to use when using SetSimpleColumn. Here's one article that I'm referencing: http://blog.dmbcllc.com/2009/07/08/itextsharp-html-to-pdf-positioning-text/
Simplest accepted answer will be how to translate the value from GetFieldPositions to SetSimpleColumn.
Thanks!
I think this was done for two reasons. 1), GetFieldPositions() could actually return multiple items because you can technically have more than one field with the same name and 2), the original array method required knowing "magic array numbers" to find what was what. All of the code that you saw pretty much assumed that GetFieldPositions() only returned a single item, which is true 99% of the time. Instead of working with indexes you can now work with normal properties.
So the code from the link that you posted:
float[] fieldPosition = null;
fieldPosition = fields.GetFieldPositions("fieldNameInThePDF");
left = fieldPosition[1];
right = fieldPosition[3];
top = fieldPosition[4];
bottom = fieldPosition[2];
if (rotation == 90)
{
left = fieldPosition[2];
right = fieldPosition[4];
top = pageSize.Right - fieldPosition[1];
bottom = pageSize.Right - fieldPosition[3];
}
Should be converted to:
IList<AcroFields.FieldPosition> fieldPositions = fields.GetFieldPositions("fieldNameInThePDF");
if (fieldPositions == null || fieldPositions.Count <= 0) throw new ApplicationException("Error locating field");
AcroFields.FieldPosition fieldPosition = fieldPositions[0];
left = fieldPosition.position.Left;
right = fieldPosition.position.Right;
top = fieldPosition.position.Top;
bottom = fieldPosition.position.Bottom;
if (rotation == 90)
{
left = fieldPosition.position.Bottom;
right = fieldPosition.position.Top;
top = pageSize.Right - fieldPosition.position.Left;
bottom = pageSize.Right - fieldPosition.position.Right;
}