I have a panel (with autoscrolling) that contains randomly placed UserControls, I want to save the locations of these controls and load them back at a later time so they are placed exactly where they were before.
What's the proper way to do this in .NET? At the moment this is what I'm saving to the database as X,Y:
X: Math.Abs(panel.AutoScrollPosition.X) + control.Location.X;
Y: Math.Abs(panel.AutoScrollPosition.Y) + control.Location.Y;
And when I load the control I do:
control.Location = new System.Drawing.Point(X, Y);
But I think I'm missing something, because of the way the AutoScroll behaves in .NET. Sometimes I find the controls misplaced (unlike their old position) after loading.
Been boggling my mind for a while now, I really hope I'd find some information here.
Not sure on all the configuration you are using, but make sure the incremental steps for the scroll bars are whole numbers. Next make sure that the controls are getting added back to the panel control tree instead of the parent form and set the location.
You could use a app.config file to save those settings, so when you need them back you just make a call to the settings for the key inside app.config.
I think there is not a proper way, whatever you feel better it works, but if you are going to have dynamically created controls you could have a database as you have now. But, if there are going to be just a few of them, a app.config file will work better.
I presume you want to restore the controls to their current visual position after scrolling and that is why you take account of the auto-scroll? When you say the controls are misplaced, have they moved relative to each other, or are the whole lot 'scrolled' to the wrong position?
Are you sure about the Math.Abs? This seems somewhat odd; I would try with just adding Location.X and AutoScrollPosition.X (or use -AutoScrollPosition.X)
I would also check on restore that the AutoScrollPosition is currently 0.
Related
I made this program and it worked until it didn't... I was adding labels with text onto a form and setting label.Location = new Point(0, yPos); and then doing yPos += labelHeight;
It didn't make sense to me why at first my labels were fine and then I saw huge gaps between then, turns out yPos overflowed, so I can't use this method, is there some sort of container I can use to add labels one after another without setting label location? Also my labels can be of any height and there can be a lot of them.
I was adding these labels as controls of TabPage.
You're ignoring the main problem which is that you are somehow overflowing the yPos value. So either your logic for setting the y position is flawed or you are displaying WAY too much data in one form. My large 32-inch monitor runs at a resolution of 2,500 X 1,600. The maximum value for int (and thus the maximum y value) is 2,147,483,647. Even a scrollable form that's over 1.3 Million "pages" of data at that resolution. If I could process one "screen" of data per second it would take me 373 hours (15.5 days) to consume all of the labels in that form.
So the problem is not which control to use - it how to reduce the amount of data in one form to a manageable amount. You need to look at filtering, searching, sorting, paging, etc. to get the amount of data to a manageable level. Otherwise it's write-only memory. You are displaying it but noe one is reasonably able to use it.
(Looking past the fact that you may be trying to add too many labels to begin with)
You might want to use TableLayoutPanel for adding multiple controls.
https://blogs.msdn.microsoft.com/jpricket/2006/04/05/winforms-autolayout-basics-tablelayoutpanel/
I believe this is a method you can run on something like that
Table.Controls.Add(new Label() { Text = "textHere", Anchor = ... etc};
That way you don't have to explicitly position everything within the panel, only the panel itself.
There are probably a few ways of doing what you're asking. A little bit of research on my part found that this method is generally the right way to go.
Unfortunately I am unable to test this at the moment, but it may put you on the right track.
Turns out when you add things to a form, that has AutoScroll set to true, you should always do:
this.AutoScrollPosition = new Point(0,0);
This worked, thanks to Hans Passant.
I am working with Visual Studio 2010 ReportViewer WinForms.
I have been unable to figure out how to fix the rectangle height in a report. I've tried using a table within the rectangle, also a table in a sub report that is placed in the rectangle of the main report with no success.
Basically, I am setting up an invoice-type report that must keep its' form and should not be allowed to grow so that elements are pushed onto a second page.
Both rectangle and tables will always grow vertically based on the content. There is no way to really stop this.
There are a couple of properties that might be able to help you get the correct page breaking in place:
KeepTogether indicates whether to keep all sections of the data region together on pane page.
When set on true and the region is to large to fit the page, this will add a page-break before the start of the region to try and fit as much as possible on a single page.
So if you wish for the region to start at the initial location but break afterwards, make sure this is to false.
PageBreak has the parameter BreakLocation which can be used to determine a fixed place to add a page-break. You can set it on Start, End, StartAndEnd or Between.
You could split your report in fixed pages and use these to add standard page-breaks in the desired (fixed) locations.
These properties alone might not be enough to get your desired result. Especially when working with tables it is hard to add a page-break after a fixed amount of rows.
It is hard to give you a detailed description of a possible approach with the amount of information you gave me, but here is some general advice.
You should split your data in the correct intervals before sending the datasource to the reporter. You can for example use grouping to place them in the correct intervals and add page-breaks based on the grouping.
Another solution is to add them in separate containers, this will require you to have enough spare data regions at your disposal. If there are too many you can always hide the empty ones based on an expression set for the Hidden property.
It won't be easy to set this up correctly so that it can dynamically grow. It takes a lot of puzzling from your end but pretty much any layout should be possible to achieve.
I wish I could give you a more specific solution to your problem and am willing to help you further if you give me an example to work with. But ultimately this is something you should be able to achieve on your own.
Nothing much to it, just a general question. I've searched for ages on the web but I can't find anything that answers my question.
is this possible? I want to parent one picturebox to another (which is below the one I want to parent) to allow the transparency to work properly for the top picturebox. But the picturebox's location changes off to somewhere off screen which is what I don't want.
If there is nothing like that, then are there any suggestions?
Currently I'm working with very small pictureboxes and I've tried everything to get the top image to be in the same place, including things like this code:
Btn_Close2.Location = New Point(Btn_Close2.Location.X - Btn_Close.Left, Btn_Close2.Location.Y - Btn_Close.Top)
But the top picturebox just wonder's off somewhere.
i designed a game in c# and finished it... but i tried it on my friend's laptop with different screen size and resolution, all my design was in a total mess!!
if there is a way to keep everything (panels, picturebox,buttons,labels,...) in their positions despite the size and resolution of screen!?!?
really need help, my project's deadline is on Monday :(
Use anchors on your controls:
I assume this is a windows form application? If so, you can use docking to maintain positions. Also, the positions should stay the same anyway unless the form is not a fixed size.
So use docking or a fixed sized form.
Also, please make sure to specify what type of GUI framework you're using next time. My answer is incredibly wrong if you're using something other than windows forms.
Aside from docking, another option would be to place all of your objects within a panel, and then center it horizontally and vertically on your resize event. e.g.
panel1.Left = this.Width/2 + panel1.Width/2;
panel1.Top = this.Height/2 + panel1.Height/2;
This will ensure that your applications static contents are always centered, regardless of resolution.
I have some Label controls sitting on Panel controls on a Form. I want to get the labels' positions relative to the form's origin so that at run time I can hide the panel and the labels and draw some other text in their place directly onto the form.
Basically, I'm doing the following calculation: Get the absolute screen position of a label with Control.PointToScreen() and convert it back to a relative position with Control.PointToClient(), so either:
Dim newloc As Point = Me.PointToClient(ctl.PointToScreen(Point.Empty))
or
Dim newloc As Point = Me.PointToClient(ctl.Parent.PointToScreen(ctl.Location))
I have found that the two methods sometimes give me different results - putting my new point out of the visible area with negative values! - but haven't been able to determine why. I would have thought they should be identical (and they are, most of the time).
Reading the docs didn't help the first time around, but perhaps I skipped over something... Anyway, I'd be thankful for any help before I start tearing my hair out.
Or, on the other hand, is there a better way to do this?
Edit: Sample results
So, here's a real example.
Label1 at {X=4,Y=6} on Panel1; Label2 at {X=163,Y=6} on the same parent, Panel1. Obviously I'm expecting different X-positions, but Y should be identical for both.
When I run the project both ctl.PointToScreen(Point.Empty) and ctl.Parent.PointToScreen(ctl.Location) give me the same screen location for Label1 at {X=959,Y=119} (the absolute values here can vary, of course, depending on the position of the form itself) and therefore the correct location relative to the form when Me.PointToClient is applied (at {X=5,Y=32}).
The very next lines do the same calculations for Label2 (remember, same Parent, same Y-value within the parent (6)), but the results are totally off: ctl.Parent.PointToScreen() gives me {X=1114,Y=63}. X is almost correct (959-4+163=1118), but Y is nowhere near the 119 I got for Label1. And then ctl.PointToScreen() gives me {X=166,Y=29} - translated back to Form-Coordinates (Me.PointToClient) {X=-784,Y=-2}.
These numbers are calculated and printed to the debug window directly after each other, without moving anything around... Madness.
OK, this is getting rather messy, but I still hope someone has a simple explanation. Thanks!
OK, I found the solution.
I happened to be calling Control.PointToScreen before the control was created: Control.IsHandleCreated = False.
If I ensure that the control is created first (Control.CreateControl) both methods work equally well.
The reason I had differing results on subsequent calls is that the first call to Control.PointToScreen also causes the control to be created (and therefore its parent and any other controls sited on the parent), meaning the second succeeds.
Well, I'm sure glad to be done with this :-)
I think it's the sleep. :) Instead of:
ctl.PointToScreen(Point.Empty)
ctl.Parent.PointToScreen(ctl.Location)
try:
ctl.PointToScreen(Point.Empty)
ctl.PointToScreen(ctl.Location) // Note no .Parent!
instead and you'll see the difference in the x/y coordinates.
Also, try using Control.TopLevelControl or Control.FindForm() to get the outermost Form when doing your PointToScreen math.