Saving scrollbars state/location - c#

I have a panel where I dynamically add custom controls to it. If controls go out of the panels bounds, Horizontal/Vertical scrollbars automatically shows (AutoScroll == true) and scrollbars will follow the control via the following code:
if(panelDiagram.VerticalScroll.Visible || panelDiagram.HorizontalScroll.Visible) {
panelDiagram.ScrollControlIntoView(tempNode);
}
This way, while moving the tempNode around, scrollbars will follow it.
Is there any way to preserve the state of the scrollbars when I load everything again from the database? I tried a lot of things like ScrollControlIntoView(lastAddedControl) but nothing is working. Maybe I have to turn off AutoScroll and manage everything by my hand?

Panel is derived from ScrollableControl which exposes a few properties you might find useful:
AutoScrollPosition
VerticalScroll
HorizontalScroll
It looks like autoScrollPosition is what you're after; it's a Point instance that contains the current X and Y scroll coordinates for each scrollbar. X will be zero if you're only doing vertical scrolling.
Save it like so:
public override void OnLoad(Object sender, EventArgs e) {
this.panel1.AutoScrollPosition = GetSavedScrollPoint();
}
public override void OnFormClosing(Object sender, EventArgs e) {
SavePointSomewhere( this.panel1.AutoScrollPosition );
}

Related

Non-Clipped Overlapped Image

I would like a transparent overlapped non-clipped image. I have one PictureBox overlapping another, as shown in this SO thread.
The solution, which makes sense, sets the parent of the top image to the bottom image. The top image is then set to have a transparent background. The technique works perfectly, just setting the parent of the top image to that of the bottom clips the top image to the area of the bottom image.
Top Image Parent Property NOT Set to the Bottom Image
Now, here is what happens if the top image parent property gets set to the bottom image.
I do not want the top image clipped.
I would volunteer the entire Visual Studio 2019 (VS2019) project, but not sure how to post it.
Here is the code:
using System;
using System.Drawing;
using System.Windows.Forms;
namespace ImageOverlap
{
public partial class FrmMain : Form
{
public FrmMain()
{
InitializeComponent();
}
private void FrmMain_Load(object sender, EventArgs e)
{
this.ImgTop.Parent = this.ImgBottom;
this.ImgTop.BackColor = Color.Transparent;
//this.ImgTop.BringToFront();
this.ChangeX.Value = 430;
this.ChangeY.Value = 15;
}
private void ChangeX_ValueChanged(object sender, EventArgs e)
{
this.ImgTop.Left = (int)this.ChangeX.Value;
}
private void ChangeY_ValueChanged(object sender, EventArgs e)
{
this.ImgTop.Top = (int)this.ChangeY.Value;
}
}
}
I put 2 NumericUpDown controls to better adjust the position of the finger pointer.
The call to method BringToFront() can be deleted, as does nothing, just above as mentioned in a couple of answers and used for testing.
UPDATE
I do NOT want to stretch the bottom image. I want to see the form background.
I also realize that the hand pointer is out of bounds of the bottom (parent) image. As such, the hand pointers gets clipped, cut off.
I want to the entirety of the top image to show, just the part of the top image, which overlaps the bottom image to be transparent.
Using what has got to be the world's best app, Paint.Net, here is what I want, also in a nice reusable code format.
My thought towards a solution is at the moment to make a programmatic copy of the hand pointer and overlay that using onto the form just clipping the left portion, which overlaps the bottom image. I think this idea might work, will post as answer if it works.
This answer can probably be optimized and made more reusable, but it works.
I created a copy of the top control. I then used this updated code, which includes a reusable method.
using System;
using System.Drawing;
using System.Windows.Forms;
namespace ImageOverlap
{
public partial class FrmMain : Form
{
public FrmMain()
{
InitializeComponent();
}
private void FrmMain_Load(object sender, EventArgs e)
{
this.ImgTop.Parent = this.ImgBottom;
this.ImgTop.BackColor = Color.Transparent;
this.ImgTop.BringToFront();
this.ChangeX.Value = 430;
this.ChangeY.Value = 15;
}
private void ChangeX_ValueChanged(object sender, EventArgs e)
{
this.SetOverlayImageLocation((int)this.ChangeX.Value, this.ImgTop.Top);
}
private void ChangeY_ValueChanged(object sender, EventArgs e)
{
this.SetOverlayImageLocation(this.ImgTop.Left, (int)this.ChangeY.Value);
}
private void SetOverlayImageLocation(int newX, int newY)
{
this.ImgTop.Left = newX;
this.ImgTop.Top = newY;
Point ptImageAtParent = new Point(this.ImgTop.Left + this.ImgBottom.Left, this.ImgTop.Top + this.ImgBottom.Top);
this.ImgTopCopy.Location = ptImageAtParent;
this.ImgTopCopy.SendToBack();
}
}
}
I am thinking that .Net probably has a nice method/property to get the point relative to the parent. I did that in a brute force method. I then set the copy to the back. The location of the copy is set relative to the parent. The trick is that the copy has the parent property set to the main control.
Here is the runtime visual that I got, no Paint.Net involved; looks identical, which is the objective.
The nice part is that the NumericUpDown controls work flawlessly moving the combined image, which to the user appears as one image.
You want the entire image render on bottom image, if yes it means your problem is calculation of top image position.
this.ImgTop.Parent = this.ImgBottom;
this.ImgTop.BackColor = Color.Transparent;
this.ImgTop.BringToFront();
this.ImgTop.Top = 0;
this.ImgTop.Left = ImgBottom.Width - ImgTop.Width;
I see your replay to Reza, sorry for misunderstood. you set the parent of top image to bottom image. the control can't do any more actions outside of parent area after this. if you want to do that you can dynamically split your image into to separate image controls, one of theme inside the bottom image and another outside and control position of both of theme or implement own control maybe by the help of polygons.

Changing width of vertical scroll bar in dataGridView

I am developing an App for a touchscreen. I have been asked to make the size of the scroll bars bigger so the users can use them. So far I have not been able to get this sorted. I read that if you increase the width of MainForm window scroll bar then dataGridView will inherit it. I have tried a few things but so far have failed to get it to work.
The two closest ways I tried are
1) When I build the grid I add the following
foreach (Control ctrl in dataGridView1.Controls)
if (ctrl.GetType() == typeof(VScrollBar))
ctrl.Width = 86;
Unfortunately this seems to get the Width of 17 but not able to override it with this new value of 86.
Next I put this into where I build the MainForm still no good the vertical scroll bar still looks the same.
2) I find that I could add a scroll bar from the tool box. A bit of progress here until I try to connect to dataGridView. This I cannot do. I have an event so everytime it is moved I should be able to move the grid. Below commented out are a few items that I use to make sure I am getting a value.
private void vScrollBar1_Scroll(object sender, ScrollEventArgs e)
{
//MessageBox.Show(vScrollBar1.Value.ToString());
// MessageBox.Show(SystemInformation.VerticalScrollBarWidth.ToString());
// CalculateVerticalScrollbarWidth() * 4;
}
So I thought I would ask the audience of higher intelligence than me as someone may have solved this and will share the answer with me.
You can turn off the DGV's vertical scroll bar:
dataGridView1.ScrollBars = ScrollBars.Horizontal;
And add a VerticalScrolllBar Control instead. Make sure to keep its size in snych and also its Maximum:
vScrollBar1.Maximum = dataGridView1.RowCount;
To scroll in synch code both Scroll events:
private void dataGridView1_Scroll(object sender, ScrollEventArgs e)
{
vScrollBar1.Value = e.NewValue;
}
private void vScrollBar1_Scroll(object sender, ScrollEventArgs e)
{
dataGridView1.FirstDisplayedScrollingRowIndex = e.NewValue;
}

Mouse up event doesn't get triggered

I have the following problem: I have a panel which has a specific color, say red.
When the user presses his mouse, the color of this panel gets stored in a variable. Then the user moves, his mouse still pressed, over to another panel. When he releases the mouse there, this panel should get the background color of the first that had been stored in the variable. My code looks something like this:
public Color currentColor;
private void ColorPickMouseDown(object sender, MouseEventArgs e)
{
Panel pnlSender = (Panel)sender;
currentColor = pnlSender.BackColor;
}
private void AttempsColorChanger(object sender, MouseEventArgs e)
{
Panel pnl = (Panel)sender;
pnl.BackColor = currentColor;
}
I need to identify the sender first because there are many possible panels that can trigger this event. The first MouseDown method works totally fine, the color is stored nicely in the variable. The secon one however doesn't even get triggered when the user does what I described above. When the ser clicks on the second panel, it works (there is an MouseUp part in a click aswell I guess).
What's wrong here? Why is the event not triggered when the user holds the mouse key down before?
(This answer assumes you are using Windows Forms.)
It could be that you need to capture the mouse by setting this.Capture = true in the MouseDown of the source control. (See Control.Capture)
If you did that, the source window would get the MouseUp event, and it would be the source window that had to determine the destination window under the mouse coords. You can do that using Control.GetChildAtPoint() (see this answer on Stack Overflow).
Use Windows Forms Drag and Drop Support Instead! <- Click for more info
I'm going to suggest you bite the bullet and use the .Net Drag and Drop methods to do this. It requires some reading up, but it will be much better to use it.
You start a drag in response to a MouseDown event by calling Control.DoDragDrop().
Then you need to handle the Control.DragDrop event in the drop target control.
There's a few more things you might need to do to set it up; see the Control.DoDragDrop() documentation for an example.
(For WPF drag and drop support, see here.)
when your mouse enter the target control , mouse down triggerd ang get target BackColor! you need add an boolean flag to your code :
public Color currentColor;
bool flag=false;
private void ColorPickMouseDown(object sender, MouseEventArgs e)
{
if(flag==false)
{
flag=true
Panel pnlSender = (Panel)sender;
currentColor = pnlSender.BackColor;
}
}
//assume mouse up for panles
private void AttempsColorChanger(object sender, MouseEventArgs e)
{
if(flag==true)
{
Panel pnl = (Panel)sender;
pnl.BackColor = currentColor;
flag=flase;
}
}
and also you need change your flag in mouseMove( if )
As I mentioned in my comment Mouse Events are captured by the originating control, You would probably be better off using the DragDrop functionality built into Windows Forms. Something like this should work for you. I assigned common event handlers, so they can be assigned to all of your panels and just work.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void panel_MouseDown(object sender, MouseEventArgs e)
{
((Control)sender).DoDragDrop(((Control)sender).BackColor,DragDropEffects.All);
}
private void panel_DragDrop(object sender, DragEventArgs e)
{
((Control)sender).BackColor = (Color)e.Data.GetData(BackColor.GetType());
}
private void panel_DragEnter(object sender, DragEventArgs e)
{
e.Effect = DragDropEffects.Copy;
}
}
I know it's an old question but I had the same issue and none of the above answers worked for me. In my case I had to handle the MouseMove event in the target control and check for the mouse to be released. I did set 'BringToFront' on my target panel just in case that helped at all.
public Color currentColor;
private void ColorPickMouseDown(object sender, MouseEventArgs e)
{
Panel pnlSender = (Panel)sender;
currentColor = pnlSender.BackColor;
}
private void panelTarget_MouseMove(object sender, MouseEventArgs e)
{
//the mouse button is released
if (SortMouseLocation == Point.Empty)
{
Panel pnl = (Panel)sender;
pnl.BackColor = currentColor;
}
}

Draw an image out of a control

I have a control. It's a text box. I want to draw an image at the left of the control. The image should be painted outside the control. I could paint it one but inside.
Here is the code:
private static Image requiredIcon = Resources.Icon_required;
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
if (base.Enabled && string.IsNullOrEmpty(base.Text))
{
e.Graphics.DrawImage(requiredIcon, 0, 0);
}
}
Instead of drawing the image, you could create an appropriate control, e.g. PictureBox, with it's Image property set to the appropriate image resource.
It may be easier to do this at design time rather than run time. If the image should not be shown intitially, set it's Visible property to false at design time and set it to true at run time when the image should be shown.
Create a user control composed of a TextBox and a PictureBox. Then in the OnPaint event of your user control you will be able to draw outside the textbox (in the PictureBox control).
Here's a picture of what the UserControl could look like. It contains a PictureBox and a TextBox.
If you just want to draw an icon you just have to assigned it to the PictureBox. So the OnPaint may not be necessary in your case.
Instead of overloading the TextBox.OnPaint method, you have to overload the Form's (or whatever is the parent component of the TextBox) OnPaint method, and paint the Image at the left hand side of the TextBox. You can't have the TextBox draw to an area outside its own bounds.
I can get a parent and use it for painting.
protected override void OnParentChanged(EventArgs e)
{
base.OnParentChanged(e);
base.Parent.Paint += new PaintEventHandler(Parent_Paint);
}
private void Parent_Paint(object sender, PaintEventArgs e)
{
if (base.Enabled && string.IsNullOrEmpty(base.Text))
{
e.Graphics.DrawImage(requiredIcon, 0, 0);
}
}

Catching mouse move

Situation :
I'm currently working a project where the aim is to develop a VS-like IDE, where users can drap/drop new controls to a design surface, and modify properties of these controls.
So i implemented IDesignerHost, IServiceContainer, IContainer, IComponentChangeService, and some others useful interface, made to design that.
Everything works fine, i've my toolbox, my design surface, and my propertyGrid working just fine.
Problem is :
Attached to the drag'n'droped controls is a label, which has to follow the control while the user move it with his mouse.
I tried to use the LocationChanged event of the controls, to move the label when the control move. But this event occurs only one time, after the control has moved so the label doesn't move while the control move.
I'm not able to find a way for make this work. Does anyone have any good ideas please ?
Thank you
Edit :
I use a custom class, implementing IDesignerHost. Controls on this design surface doesn't fire events Mouse----- (e.g. : MouseDown, MouseMove).
I finally found how to do it :
I implemented ISelectionService and in the SetSelectedComponents function, I managed to select the label control associated with any selected control.
I overrided the designer of the label, so that no border/resize-rectangle would show when the label is selected.
This is a not very elegant solution, but it works well =).
Every Control has a ControlDesigner, provides additional methods to support extending and altering the behavior of an associated Control at design time.
In the ControlDesigner, you have a BehaviorService, which is responsible to control on DesignSurface behavior of the control.
BehaviorService has multiple Glyphs and Adorners which are like UI decorators for the control. The control re-size rubber-band like rectangle is a Glyph, called System.Windows.Forms.Design.Behavior.SelectionBorderGlyph a private class to .Net 2.0.
This links might be of help:
http://msdn.microsoft.com/en-us/library/ms171820.aspx
http://msdn.microsoft.com/en-us/library/bb514670%28VS.90%29.aspx
You should be able to add your custom Glyph which has a Label attached with the Control.
HTH
Form2 contains a panel1, label1
panel1.MouseMove += panel1_MouseMove
panel1.MouseDown += panel1_MouseDown
when MouseDown+Left Button clicked -> save initial mouse position
when MouseMove+Left Button clicked -> move (panel1+label1) by the difference between current mouse position and the saved initial position.
it's done.
public partial class Form2 : Form
{
private int _x, _y;
public Form2()
{
InitializeComponent();
}
private void panel1_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
panel1.Location = new Point(panel1.Location.X + (e.X - _x), panel1.Location.Y + (e.Y - _y));
label1.Location = new Point(label1.Location.X + (e.X - _x), label1.Location.Y + (e.Y - _y));
}
}
private void panel1_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
_x = e.X;
_y = e.Y;
}
}
}

Categories

Resources