Centering usercontrol in panel with anchor removes scrollbar? - c#

In my current project I have a problem when I add my usercontrol into the panel of splitcontainer. I managed to add it to the middle of the panel with the following code:
ucFactuur ucFactuur = new ucFactuur();
ucFactuur.Location = new Point(
splitContainer1.Panel2.ClientSize.Width / 2 - ucFactuur.Size.Width / 2,
splitContainer1.Panel2.ClientSize.Height / 2 - ucFactuur.Size.Height / 2);
ucFactuur.Anchor = AnchorStyles.None;
splitContainer1.Panel2.Controls.Add(ucFactuur);
But now my scrollbar is gone, it is there when I remove the AnchorStyles.None but then when I resize the window it doesn't stay in the middle (It's in a fixed position).
I'm uncertain how to resolve this problem, nor can I find any other way to dynamically center my usercontrol.
Thanks,
Thomas

Anchoring.None won't work in this situation since it only works when there are no scrollbars. But once you have scrollbars, you don't want the control centered anymore, you need it positioned against the scroll value.
In other words, I think you have to handle the resizing yourself:
private void DoResize(object sender, EventArgs e) {
splitContainer1.Panel2.AutoScrollMinSize = ucFactuur.Size;
if (ucFactuur.Width < splitContainer1.Panel2.ClientSize.Width) {
ucFactuur.Left = splitContainer1.Panel2.ClientSize.Width / 2 -
ucFactuur.Width / 2;
} else {
ucFactuur.Left = splitContainer1.Panel2.AutoScrollPosition.X;
}
if (ucFactuur.Height < splitContainer1.Panel2.ClientSize.Height) {
ucFactuur.Top = splitContainer1.Panel2.ClientSize.Height / 2 -
ucFactuur.Height / 2;
} else {
ucFactuur.Top = splitContainer1.Panel2.AutoScrollPosition.Y;
}
}
Then your setup would change to this:
ucFactuur ucFactuur = new ucFactuur();
ucFactuur.AutoSize = true;
ucFactuur.Resize += DoResize;
splitContainer1.Panel2.Resize += DoResize;
splitContainer1.Panel2.AutoScroll = false;
splitContainer1.Panel2.Controls.Add(ucFactuur);

Related

C# Winforms trouble centering a form over a control, can center it over other controls

I have an application which has multiple controls on multiple pages. I'm using the Telerik Winforms controls. One of those pages has a RadGridView in a UserControl, which is on a RadPageViewPage in a RadPageView, which in turn is nested in another RadPageViewPage in another RadPageView. The following code is basically just to handle a Loading spinner that is housed in its own transparent Form. It is always called on its own thread, of course.
private static void RunWaiting(Control c, string text)
{
wf = new WaitingForm();
wf.drwbieSpinnerFrame.Text = text;
wf.ShowInTaskbar = false;
wf.Left = c.Left + (c.Width / 2);
wf.Top = c.Top + (c.Height / 2);
wf.Width = c.Width;
wf.Height = c.Height;
wf.FormBorderStyle = FormBorderStyle.None;
wf.ControlBox = false;
wf.TopMost = true;
wf.StartPosition = FormStartPosition.Manual;
Application.Run(wf);
}
Clearly, I want the spinner (WaitForm) to appear over the center of a control on-demand. It's fine if I pass it the main UserControl that houses the RadGridView, and I can also pass it the parent of that control and center on the RadPageViewPage. If I pass this method the RadGridView, the spinner doesn't appear at all, even though the code is called and the attributes of "wf" are still set. Can anyone tell me what I'm missing?
Unfortunately, the time-consuming task itself is updating the UI and must exist on the UI thread for other reasons, but I was able to put together a solution by using a recursive class that got me the appropriate (x,y) coordinates to display a form in the middle of the control.
private static void RunWaiting(Control c, string text)
{
wf = new WaitingForm();
wf.drwbieSpinnerFrame.Text = text;
wf.ShowInTaskbar = false;
int[] tl = GetTopLefts(c);
wf.Top = (tl[0] + (c.Height / 2)) - (wf.Height / 2);
wf.Left = (tl[1] + (c.Width / 2)) - (wf.Width / 2);
wf.FormBorderStyle = FormBorderStyle.None;
wf.ControlBox = false;
wf.TopMost = true;
wf.StartPosition = FormStartPosition.Manual;
IsHolding = true;
Application.Run(wf);
}
And the method it calls to get the position data:
private static int[] GetTopLefts(Control c)
{
int top, left;
top = c.Top;
left = c.Left;
if (c.Parent != null)
{
int[] parentPoint = GetTopLefts(c.Parent);
top += parentPoint[0];
left += parentPoint[1];
}
return new int[] { top, left };
}
You could probably get through this just fine by making the final output of GetTopLefts() a Point, but something about this way felt arbitrarily more reliable.

Display Form on centre of screen for a dual monitor How to?

I am developing a Windows desktop application dual monitor where I need to display my form sometimes on primary screen and sometimes on secondary,
which works fine but when I display it on my secondary screen I want it to be displayed on centre of my screen which is not working.
Here is my code:
if (Screen.AllScreens.Length > 1)
myForm.Location = Screen.AllScreens[1].WorkingArea.Location;
myForm.StartPosition = FormStartPosition.Manual; // because i wrote manual it is displayed on Top left of my secondaryScreen which is ok
myForm.show();
but I want to diplay it on centre so I wrote
myForm.StartPosition = FormStartPosition.CentreScreen;
//it is not working again a form is displayed on Centre of PrimaryScreen..
Any idea why?
You cannot use StartPosition.CenterScreen because that picks the monitor on which the mouse is currently located. Usually desirable but not what you are asking for. You must use the form's Load event to move it where you want it. Using form's Load is important, you do not know the size of the window until after it is created and the user's preferences are applied and it is rescaled to match the video DPI.
Boilerplate code should look like this:
private void button1_Click(object sender, EventArgs e) {
var form = new Form2();
form.Load += CenterOnSecondMonitor;
form.Show();
}
private void CenterOnSecondMonitor(object sender, EventArgs e) {
var form = (Form)sender;
var area = Screen.AllScreens.Length > 1 ? Screen.AllScreens[1].WorkingArea : Screen.PrimaryScreen.WorkingArea;
form.Location = new Point((area.Width - form.Width) / 2, (area.Height - form.Height) / 2);
form.Load -= CenterOnSecondMonitor;
}
Or you put this code into the form itself, the more common choice:
protected override void OnLoad(EventArgs e) {
var area = Screen.AllScreens.Length > 1 ? Screen.AllScreens[1].WorkingArea : Screen.PrimaryScreen.WorkingArea;
this.Location = new Point((area.Width - this.Width) / 2, (area.Height - this.Height) / 2);
base.OnLoad(e);
}
look for the property of your winform named StartPosition then set it into Center Screen
You could write an extension method:
public static void MoveForm(this Form form, Screen screen = null)
{
if(screen == null)
{
//If we have a single screen, we are not moving the form
if(Screen.AllScreens.Length > 1) return;
screen = Screen.AllScreens[1];
}
var bounds = screen.Bounds;
form.Left = ((bounds.Left + bounds.Right) / 2) - (form.Width / 2);
form.Top = ((bounds.Top + bounds.Bottom) / 2) - (form.Height / 2);
}
private void CenterOnTheCurrentScreen()
{
Rectangle workingArea = Screen.FromControl(this).WorkingArea;
Point center = new Point((workingArea.Width - this.Width) / 2, (workingArea.Height - this.Height) / 2);
this.Location = new Point(workingArea.X + center.X, workingArea.Y + center.Y);
}

stuck x-axis scrollbar in MSChart Chart

[EDIT]
After a lot of trial and error, I realized a version of my tooltip code could scroll while the rest of the codes are unchanged. The only difference between the two tooltip usage is that the pos.x value is shifted, instead of being exactly where the mouse is.
Which means instead of
/*X-axis Tooltip*/
tooltip.Show(Math.Truncate(xValue * 1000) / 1000 + unit_Converter(), this.chart1, pos.X, pos.Y - 15);
I did this
/*X-axis Tooltip*/
tooltip.Show(Math.Truncate(xValue * 1000) / 1000 + unit_Converter(), this.chart1, pos.X - 70, pos.Y - 15);
That was all the difference. Now I can click and drag the X-axis scroll bar around. I suppose the reason why I always could scroll my Y-axis is it was shifted by 15 to begin with.
So if you set your tooltip position exactly where your mouse position is, then apparently you will be clicking on the tooltip itself, instead of the scrollbar when you attempt to scroll.
Answer provided by Josh W is equally valid, because using just "this" instead of "this.chart" automatically shifts the tooltip a little bit for some reason. thanks for the help!
[Original Question]
I have a chart that has Y-axis and X-axis scroll bar. For a while both my scrollbars worked. As my code grow, the X-axis scrollbar now won't move, while the Y-axis scrollbar moves just fine. I am puzzled. Any help would be appreciated.
I have referenced other answers such as
c# chart control, vertical scrolling problems with zoom ["Stuck Scroll bar"]
But X-axis scrollbar still stuck....
[EDIT]:
I realized that my tooltip on mouse move code is causing this. If I disable my call to my mouse move code, the X-axis scrollbar would be functional again. But how do I make it so that both can function? I don't really know how the crossair tooltip would disable scrolling on the X-axis only, but not the Y-axis...
void chart1_MouseMove(object sender, MouseEventArgs e)
{
var pos = e.Location;
_point.X = e.Location.X;
_point.Y = e.Location.Y;
try
{
if ((chart1.ChartAreas[0].AxisX.PixelPositionToValue(e.X) >= 0) && (chart1.ChartAreas[0].AxisX.PixelPositionToValue(e.X) <= max))
{
//Crossair
chart1.ChartAreas[0].CursorX.SetCursorPixelPosition(_point, true);
//Tooltips
double xValue = chart1.ChartAreas[0].AxisX.PixelPositionToValue(e.X);
/*X-axis Tooltip*/
tooltip.Show(Math.Truncate(xValue * 1000) / 1000 + unit_Converter(), this.chart1, pos.X, pos.Y - 15);
}
}
catch (Exception exception)
{
}
}
My code to set series settings:
var series = chart1.ChartAreas[chart1.Series[iname].ChartArea];
//Line thickness
chart1.Series[iname].BorderWidth = 2;
series.AxisX.Minimum = 0;
series.AxisX.Maximum = max;
series.AxisY.Minimum = 0;
series.AxisY.Maximum = checkedListBox1.CheckedItems.Count * 3 - 2;
series.AxisX.MajorGrid.Interval = time_of_cycle;
series.AxisX.MajorGrid.LineDashStyle = ChartDashStyle.DashDotDot;
series.AxisY.MajorGrid.Interval = 2;
series.CursorX.Interval = 0;
series.CursorY.Interval = 0;
series.AxisX.ScaleView.SmallScrollSize = time_of_cycle /100 ;
series.AxisY.ScaleView.SmallScrollSize = 1;
//Disables Y axis lable
series.AxisY.LabelStyle.Enabled = false;
series.AxisX.LabelStyle.ForeColor = Color.White;
series.AxisY.LabelStyle.ForeColor = Color.White;
series.AxisX.LabelStyle.Format = label_Style_Converter();
series.AxisX.LabelStyle.Interval = time_of_cycle * 2;
series.AxisX.MajorGrid.LineColor = Color.DimGray;
series.AxisY.MajorGrid.LineColor = Color.DimGray;
series.AxisX.ScrollBar.BackColor = Color.LightGray;
series.AxisY.ScrollBar.BackColor = Color.LightGray;
series.AxisX.ScrollBar.ButtonColor = Color.LightGray;
series.AxisY.ScrollBar.ButtonColor = Color.LightGray;
series.AxisX.ScrollBar.ButtonStyle = ScrollBarButtonStyles.SmallScroll;
series.AxisY.ScrollBar.ButtonStyle = ScrollBarButtonStyles.SmallScroll;
series.AxisX.ScrollBar.Enabled = true;
series.AxisY.ScrollBar.Enabled = true;
series.AxisX.ScrollBar.IsPositionedInside = false;
series.AxisY.ScrollBar.IsPositionedInside = false;
series.AxisX.IsMarginVisible = true;
series.AxisY.IsMarginVisible = false;
series.AxisX.Name = "µs";
series.AxisX.ScaleView.Size = max - time_of_cycle / 100;
series.AxisY.ScaleView.Size = (checkedListBox1.CheckedItems.Count * 3 - 2) + 1 ;
series.BackColor = Color.Black;
//crosshair
var cursor_Y = chart1.ChartAreas["ChartArea1"].CursorY;
var cursor_X = chart1.ChartAreas["ChartArea1"].CursorX;
cursor_Y.LineWidth = 1;
cursor_Y.LineDashStyle = ChartDashStyle.Solid;
cursor_Y.LineColor = Color.DarkRed;
cursor_Y.SelectionColor = Color.LightGray;
cursor_X.LineWidth = 1;
cursor_X.LineDashStyle = ChartDashStyle.Solid;
cursor_X.LineColor = Color.DarkRed;
chart1.MouseMove += new MouseEventHandler(chart1_MouseMove);
At first I thought maybe your call to .Show() was blocking the GUI thread, but some quick and dirty code didn't seem to have that issue. One odd thing I did notice with the tooltip though is that when you have something like your Chart subscribed to the MouseMove event, and your tool-tip is given a 'this.chart1' reference instead of just this, then if the tooltip is under your mouse, it continues to fire the event.
That is, even if the tooltip moves off the chart for example.
Here was some test code I just played with using a panel instead of a chart.
private int Counter = 0;
private void panel1_MouseMove(object sender, MouseEventArgs e)
{
Console.WriteLine(string.Format("X{0}, Y{1}\t Count = {2}", e.X, e.Y, Counter));
Counter++;
toolTip1.Show(
string.Format("X{0}, Y{1}\t Count = {2}", e.X, e.Y, Counter),
this.panel1,
e.X - 75,
e.Y -5);
}
First you should also get rid of that try/catch statement as you aren't doing anything with the error... either handle errors, or let them bubble up to crash something (so that you can 'fix' it). What you have there now might throw an error, but you'd never know, because you are catching it and ignoring it.
Second, the MouseMove event happens a LOT... perhaps use the MouseHover for showing the tooltip?
Other than that... it does not appear to be where your code is breaking, though it could be inside the unit_Converter() call or even on the math function... your try/catch may be hiding an exception on that line.

How can i set the Form to be in the Center of the Screen?

I'm using this code:
private void notifyIcon1_MouseDoubleClick(object sender, MouseEventArgs e)
{
this.Show();
this.WindowState = FormWindowState.Normal;
//this.Location = new Point(form1_location_on_x, form1_location_on_y);
//this.StartPosition = FormStartPosition.CenterScreen;
Either the line
this.Location = new Point(form1_location_on_x, form1_location_on_y);
or the line
this.StartPosition = FormStartPosition.CenterScreen;
are working when I'm on my original screen resolution 1920x1080, but once I'm changing the resolution to 1024x768, the Form is on the right bottom corner not hidden I see it all but it's not in the center.
form1_location_on_x and on_y are:
form1_location_on_x = this.Location.X;
form1_location_on_y = this.Location.Y;
The question is what should I do to make it work on any other resolution like 1024x768 or any others? I tried many changes but nothing worked so far.
Size screenSize = Screen.PrimaryScreen.WorkingArea.Size;
Location = new Point(screenSize.Width / 2 - Width / 2, screenSize.Height / 2 - Height / 2);
Make sure that you set StartPosition = FormStartPosition.Manual;
Tested and working with 1920x1080 and 1024 x 768
You could calculate the top and left position of your form using this formula:
int formWidth = yourForm.Width;
int formHeight = yourForm.Height;
int screenH = (Screen.PrimaryScreen.WorkingArea.Top +
Screen.PrimaryScreen.WorkingArea.Height) / 2;
int screenW = (Screen.PrimaryScreen.WorkingArea.Left +
Screen.PrimaryScreen.WorkingArea.Width) / 2;
int top = screenH - formWidth / 2;
int left = screenW - formHeight / 2;
yourForm.Location = new Point(top, left);
Of course, these days, you have the problem of dual monitors.
I don't know if you want your form to appear always on the primary screen or you want the form appear in the current screen (the one where the form is currently displayed). In this second case you need to find where your form is displayed
private void CenterForm(Form yuorForm)
{
foreach(var s in Screen.AllScreens)
{
if(s.WorkingArea.Contains(yourForm.Location))
{
int screenH = s.WorkingArea.Height / 2;
int screenW = s.WorkingArea.Width / 2;
int top = (screenH + s.WorkingArea.Top) - formWidth / 2;
int left = (screenW + s.WorkingArea.Left) - formHeight / 2;
yourForm.Location = new Point(top, left);
break;
}
}
}
EDIT: Thanks to #alex I will complete the answer with the information on SystemEvents class
If you want to be notified by the system when the user suddenly change the resolution of your screen you could subscribe to the event SystemEvents.DisplaySettingsChanged (using Microsoft.Win32; needed)
SystemEvents.DisplaySettingsChanged += new EventHandler(SystemEvents_DisplaySettingsChanged);
and then handle the reposition of your form in the event
// This method is called when the display settings change.
void SystemEvents_DisplaySettingsChanged(object sender, EventArgs e)
{
RecenterForm(yourForm);
}
try using one of these after the resize:
this.CenterToScreen();
or
this.CenterToParent();
You can use StartPosition property of Form objects. It determines the position of a form. Set it's value to CenterScreen if you want your form to open in the center of the screen

Selecting part of image on windows form

I'm making instrument to select part of image. I have PictrureBox, and simple way to make it :
void StartPanel(object sender, MouseEventArgs args)
{
xStart = args.X;
yStart = args.Y;
panelStarted = true;
pan.Location = new Point(xStart, yStart);
}
void FinishPanel(object sender, MouseEventArgs args)
{
xFinish = args.X;
yFinish = args.Y;
panelStarted = false;
}
void UpdatePanel(object sender, MouseEventArgs args)
{
if (panelStarted)
{
int x = args.X;
int y = args.Y;
int newxstart = xStart;
int newystart = yStart;
int neww = 0;
int newh = 0;
if (x >= xStart)
neww = x - xStart;
else
{
neww = xStart - x;
newxstart = x;
}
if (y >= yStart)
newh = y - yStart;
else
{
newh = yStart - y;
newystart = y;
}
pan.Size = new Size(neww, newh);
pan.Location = new Point(newxstart, newystart);
}
}
When I move mouse right and down, it is absolutely ok. But when I move it left or up I can see blinks at my area. So I have understood, that it is because when I move mouse left or up, my panel is redrawed, because Panel.Location is changed, and when I move mouse right and down, location is not changed, only size is changed, so it is not redrawed, just some pixels are added to panel. What is standart solution for this?
It's not easy trying to see what you are trying to do, but I guess you are using a panel as a draggable control to drag over the picturebox surface capturing the portion of image below (like a lens) - yes?
If so, then this is not the best way to do it. It is better to just draw a rectangle on the picturebox surface and "drag" that around - this is simple with just using the mouse events to sets the top left corner and use the onpaint to draw the unfilled rectangle over the image. Capturing the image when you are ready is simple too using whatever event you wish, then copy the image giving the same positions to the new bitmap.
Putting one control over another often causes flickers - even with double buffering. It also takes far more code.
Since you are describing a drawing issue when resizing the panel, probably the easiest fix is to replace the panel you are using with one that is double buffered and will invalidate on resize a event:
public class BufferedPanel : Panel {
public BufferedPanel() {
this.DoubleBuffered = true;
this.ResizeRedraw = true;
}
}

Categories

Resources