Programmatically Scrolling is not working C# WinForm - c#

i have one panel and i put a flow layout panel in the main panel and flow layout panel has many images. my UI looks like this
now i got a code which scroll the container in the panel. i mean the flow layout will scroll in main panel when i will place my mouse at the left or right most area on the main panel. their code is working i checked but when i place their code in my project then that is not working, i means scrolling is not working when i place my mouse at the left or right most area on the main panel.
here i am attaching main code which causes to scroll the flow layout panel inside in main panel
protected override CreateParams CreateParams
{
get
{
CreateParams cp = base.CreateParams;
cp.ExStyle |= 0x02000000; // Turn on WS_EX_COMPOSITED
return cp;
}
}
int _myval = 5;
protected override void OnMouseMove(MouseEventArgs e)
{
base.OnMouseMove(e);
if (e.Y < metroPanel1.Top || e.Y > metroPanel1.Top + metroPanel1.Height) return;
if (e.X <= metroPanel1.Left && e.X >= metroPanel1.Left - 40)
{
if (metroPanel1.HorizontalScroll.Value <= _myval)
{
metroPanel1.HorizontalScroll.Value = _myval;
}
else
{
metroPanel1.HorizontalScroll.Value -= _myval;
}
}
if (e.X <= (metroPanel1.Left + metroPanel1.Width + 40) && e.X >= (metroPanel1.Left + metroPanel1.Width))
{
metroPanel1.HorizontalScroll.Value += _myval;
}
}
i just do not understand this value 40 used here if (e.X <= metroPanel1.Left && e.X >= metroPanel1.Left - 40)
i guess i need to use different value rather than 40 but i used 10 & 20 but did not work.
here is my full project link from where anyone can download and see what is wrong in my routine which prevent the scrolling. here is the link https://onedrive.live.com/embed?cid=C4A6F16F34D7540A&resid=C4A6F16F34D7540A%21134&authkey=AM5Fq2gcFLtcw_A
so it is my request that please some one see my code and guide me what i need to change in code and why. thanks

When you want to scroll dont use
metroPanel1.HorizontalScroll.Value -= _myval;
or
metroPanel1.HorizontalScroll.Value += _myval;
but instead
_myval -= 5;
or _myval += 5;
metroPanel1.HorizontalScroll.Value = _myval;
metroPanel1.Refresh();
valter

Yes.
Yes, programmatically scrolling a FlowLayoutPanel is not working, if the Scrollbars are not shown, due to its AutoScroll being off.
Neither setting HorizontalScroll.Value (in any way) nor using
[DllImport("user32.dll")]
static extern int SetScrollPos(IntPtr hWnd, int nBar, int nPos, bool bRedraw);
will do anything.
Not even doing this has any effect:
flowLayoutPanel1ScrollControlIntoView(someControlThatsOutOfSight);
So, as far as I can tell: Without active Scrollbar(s) no scrolling a FlowLayoutPanel!
The containing Panel can however indeed be scrolled the way valter shows. However my first tests showed even when using a double-buffered Panel subclass a terrible flicker..
Update:
I can't get the Panel to scroll reliably. I have checked up on the link and found that the behaviour is really much simpler than anything I had written: No up down scrolling, no edge detection, no speed detection, no direction detection. In fact there are two scroll zones and when the mouse is in one, it scrolls.. It also relies on the 'constant firing of the mousemove event bug', which only works for me when I don't want it..!
So, here is a solution that implements this behaviour and is, of course much shorter, than the original code.
I include a screenshot to show you the layout: You need two Panels and the FlowLayoutPanel.
The outer Panel is a little wider so that its right and left part work as the scroll zones.
The inner Panel contains the FLP; the FLP has AutoSize=true.
There is a timer scrollTimer with a fast Intervall of 5-10ms.
Here is the code:
int speed = 10;
int delta = 0;
private void panOuter_MouseMove(object sender, MouseEventArgs e)
{
delta = e.X < panOuter.Width / 2 ? speed : -speed;
scrollTimer.Start();
}
private void panOuter_MouseLeave(object sender, EventArgs e)
{
scrollTimer.Stop();
}
private void scrollTimer_Tick(object sender, EventArgs e)
{
int newLeft = FLP.Left + delta;
int alpha = panInner.ClientRectangle.Width - FLP.ClientRectangle.Width;
if (newLeft > 0) { newLeft = 0; scrollTimer.Stop(); }
else if ( newLeft < alpha)
{ newLeft = alpha; scrollTimer.Stop(); }
FLP.Left = newLeft;
}
That's practically all you need. Only in case you Dock or Anchor the outer Panel you should script the Resize event to keep the inner Panel centered!

Related

Getting mouse enter event on full panel c#

So what i have is a panel that's programmatically filled with custom controls using DockStyle.Top.
What i need is for the panel to get focus somehow when mouse cursor enters the panel so that the user can use mousewheel to scroll the panel.
I don't really want to give each control a handler because there could be hundreds of controls.
One way could be checking for mouse position and check if the panel contains it, which would probably require an extra thread or mousehook but perhaps there's a better way?
You may implement the MouseDetector class posted by Amen Ayach as an answer to a similar question and activate the form when the mouse hovers it:
void m_MouseMove(object sender, Point p)
{
Point pt = this.PointToClient(p);
if (this.ClientSize.Width >= pt.X &&
this.ClientSize.Height >= pt.Y &&
pt.X > 0 && pt.Y > 0)
{
this.Activate();
}
}
You should also set the Panel's AutoScroll value to true.
panel.AutoScroll = true;

Scrolling in a flowlayoutpanel while dragging?

I have a Windows Forms application which is using a FlowLayoutPanel control to display a Picture boxes that are built dynamically. I have enabled the drag drop effect as they may want to reorder them, this works fine with only a few picture boxes (right now the screen shows about 6) but if there are more you try to drag an item below the control it will not scroll, so you cannot put an image that is currently on the screen (say image 4) to an image that is below what is visible (say image 13).
I have seen several posts where the ScrollControllIntoViewMethod should be used, I have tried in a few spots unsuccessfully.
Thanks!
Here is what I ended up doing.
Create the event on the DragLeave event
Getting the position of the control
Calculating the height of the control to get the lower boundary.
check the mouse position and if above the bounds, change the vertical scroll (or horizontal scroll) by a value in a Constant..
private void thumbFlow_DragLeave(object sender, EventArgs e)
{
int BegY_ThumbFlow = this.thumbFlow.FindForm().PointToClient(this.thumbFlow.Parent.PointToScreen(this.thumbFlow.Location)).Y;
int thumbFlowBound_Y = this.thumbFlow.Height + BegY_ThumbFlow;
int mouseY = this.thumbFlow.FindForm().PointToClient(MousePosition).Y;
while (mouseY >= thumbFlowBound_Y)
{
thumbFlow.VerticalScroll.Value = thumbFlow.VerticalScroll.Value + DRAG_DROP_SCROLL_AMT;
mouseY = thumbFlow.FindForm().PointToClient(MousePosition).Y;
thumbFlow.Refresh();
}
while (mouseY <= BegY_ThumbFlow)
{
thumbFlow.VerticalScroll.Value = thumbFlow.VerticalScroll.Value - DRAG_DROP_SCROLL_AMT;
mouseY = thumbFlow.FindForm().PointToClient(MousePosition).Y;
thumbFlow.Refresh();
}
}
Hope this helps others.

Table layout panel cell bounds and control collision

I've just finished building a portion of a program which deals with a UI in a table layout panel. This has worked so far but i've noticed that, before i could try my controls (functionality i added) at runtime around the form, but now it is in cells, they can't be moved outside of their container cell. HOWEVER, this is great and exactly what i needed, but im finding that the controls (for example a button) will be correctly contained in the cell on the left, and top boundaries of the cell, but the bottom and right boundaries allow the control to disappear off of it. Heres some screenshots to demonstrate:
Here we see that the button control cannot move past the top and left bounds of the cell.
However here it seems to be able to move past the bottom and right bounds of the cell.
Looking back at how i allow my controls to move, i came across a section where i had set up some variables, shown below:
public static void MouseMove(object sender, MouseEventArgs e)
{
Control control = sender as Control;
Control container = sender as Control;
if (control != null)
{
if (Dragging)
{
if (direction != Direction.Vertical)
{
container.Left = Math.Max(0, e.X + container.Left - DragStart.X);
}
if (direction != Direction.Horizontal)
{
container.Top = Math.Max(0, e.Y + container.Top - DragStart.Y);
}
}
}
}
I figured here i'm not setting a bottom and right container bounds, which would make sense, however upon exploring the intelisense, i can't seem to get container.right and container.bottom as they come with the following tooltip:
"gets the distance, in pixels, between the right edge of the control, and the left edge of it's container's client area"
and the bottom does the same, only for the bottom of the control and top of the container area.
Is there away around this? perhaps an option somewhere which connects the bottom of the control to the bottom bound of the cell, and the same for the right?
edit 1: alternatively perhaps i need to alter my mousemove event to handle collision better, so if anyone has any ideas on this too, that'd be great, i've not really looked at much collision detection before, especially in winforms.
Control.right is a read only property. Try setting
if (direction != Direction.Vertical)
{
container.Left = Math.Max(0, e.X + container.Left - DragStart.X);
container.Left = Math.Min(container.Left, container.Parent.Width - container.Width;
}
if (direction != Direction.Horizontal)
{
container.Top = Math.Max(0, e.Y + container.Top - DragStart.Y);
container.Top = Math.Min(container.Top, container.Parent.Height - container.Height;
}

User Drawn Controls: the MSN chat window

I'm wondering about the famous MSN chat clients conversation windows! I'm sure there must be a lot of different aspects but I'd like to focus on those little sliding panes. For instance where the pictures of the people in the conversation are displayed. When you click the collapse button the pictures disappear and the panel gracefully slides in, and when you click it again to expand, it slides out and the pictures are smoothly faded in.
How would one go about customly drawing a control in WinForms that had similar behaviour?
This should give you an idea how animate your width.
int _collapsedWidth;
int _fullWidth;
float _speed;
float _acurateWidth;
System.Diagnostics.Stopwatch _stopwatch = new Stopwatch ();
int _animationDirection;
AnimatedControl (){
Application.Idle += ApplicationIdle;
}
void Expand (){
_animationDirection = 1;
_stopwatch.Start();
}
void ApplicationIdle (object sender, EventArgs e){
if (_animation.Direction == 0)
return;
float delta = _stopwatch.Elapsed.TotalMilliseconds * _speed;
_acurateWidth += delta;
if (_acurateWidth < _collapsedWidth)
{
_animationDirection = 0;
_acurateWidth = _collapsedWidth;
_stopwatch.Stop();
}
else if (_acurateWidth > _fullWidth)
{
_animationDirection = 0;
_acurateWidth = _fullWidth;
_stopwatch.Stop();
}
_stopwatch.Reset();
this.Width = (int)System.Math.Round(_acurateWidth , MidpointRounding.AwayFromZero);
this.Invalidate (); // May not need this
}
and for the pictures, somthing similar but using translucent images, you might want to make a new control with a transparent background color for them as well depending how you want to paint things.
You can then put this control into one of the LayoutPanel controls to move your other controls around in the form to match the width.

Snap-To lines when aligning controls at Runtime

I have an app where users can drag controls around on a Form. But they
re asking me for Snap-To lines to make the alignment of controls easier. I have no idea about the snep-to lines and how to implement them - I have looked at:
http://msdn.microsoft.com/en-us/library/ms752100.aspx Adorner's, but it says it's only for WPF. And I tried it in WinForms but (as expected) didn't work.
How can I get snap-to lines (something like the ones in VS) in my app?
Thank you
Bael
Have you seen this article on CodeProject:
Form Designer
It features snap-to to the grid on the design surface.
In your move control you could adjust the Left and Top by dividing and then multiplying by the width of your lines:
left = (left/10)*10;
top = (top/10)*10;
It's not perfect but it it simple. Of course since controls don't have a MoveEnd event you'll have to track the MouseButton state or something similiar.
Edit: A better implementation would properly round the division results so 134 = 130 and 136 = 140.
I had the same issue, I'm still looking for a solution ; here is what I did so far, it could be a solution for you
const grid = 12;
private void MyControl_LocationChanged(object sender, EventArgs e)
{
if (this.Left % grid != 0)
this.Left -= this.Left % grid;
if (this.Top % grid != 0)
this.Top -= this.Top % grid;
}
or in a usercontrol
protected override void OnMove(EventArgs e)
{
if (this.Left % grid != 0)
this.Left -= this.Left % grid;
if (this.Top % grid != 0)
this.Top -= this.Top % grid;
}
My current challenge is the drawing activity; my controls are hosted in a panel, I am looking for a way to lock and unlock that panel drawing when necessary; for example: only after left or top changed

Categories