Link to home
Start Free TrialLog in
Avatar of Hawkvalley1
Hawkvalley1Flag for United States of America

asked on

Drag items that scroll to more panels in autoScroll panel.

Ok, two part question, I have a FLP with controls that are added at runtime, I have the dragDrop working,  but not able to drag items to controls that are below FLPs visible area - vertical scrollbar present. Also still working on the scrollbar which is close. This is for a touch screen app(fat vsbar).

Thanks
Private Sub vsFLP_ValueChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles vsFLP.ValueChanged
       vsFLP.Maximum = vsFLPmax      ' variable that counts as controls are added
       flpUnitPanel.VerticalScroll.Value = vsFLP.Value 
End Sub

Open in new window

Avatar of Bob Learned
Bob Learned
Flag of United States of America image

I have no idea what you are talking about...
Avatar of Hawkvalley1

ASKER

I have a FlowLayoutPane(FLP1) that during runtime my UserControls(UC) are added - the UC contains a FLP(FLP2) with buttons, I need to drag the buttons from one UC to another UC in FLP1 - at some point there are enough UCs in FLP1 that some of the UCs are below the visible area in FLP1, but I need to drag the buttons from the visible UCs to the ones below - this is where I can't get the FLP1 that holds these UCs to scroll down while I am dragging.  Here are the Subs that handles drag the operation, I have tried adding the DragOver event but it does not fire(checked during debug), according to MSDN this should fire as long as the dragging is in the same container. Hope this is clearer.

Thanks for looking.

 Private Sub FLP_DragEnter(ByVal sender As Object, ByVal e As DragEventArgs) 
        If e.Data.GetDataPresent("myObject") Then
            e.Effect = DragDropEffects.All
            Dim flp As FlowLayoutPanel = CType(sender, FlowLayoutPanel)
            flp.BackColor = Color.Yellow
            If flp.Name.StartsWith("pl") Then
                Label5.ForeColor = Color.Yellow
            End If
        End If
    End Sub
    Private Sub FLP_DragOver(ByVal sender As Object, ByVal e As DragEventArgs) 
        If e.Data.GetDataPresent("myObject") Then
            
    End Sub
    Private Sub FLP_DragDrop(ByVal sender As Object, ByVal e As DragEventArgs) 
        If e.Data.GetDataPresent("myObject") Then
            e.Effect = DragDropEffects.All
            Dim flp As FlowLayoutPanel = CType(sender, FlowLayoutPanel)
            Dim btn As Button = CType(e.Data.GetData("myObject"), Button)
            btn.Location = flp.PointToClient(New Point(e.X, e.Y))
            flp.Controls.Add(btn)
            flp.BackColor = Color.MidnightBlue
            If flp.Name.StartsWith("pl") Then
                Label5.ForeColor = Color.Black
            End If
        End If
    End Sub
    Private Sub FLP_DragLeave(ByVal sender As Object, ByVal e As EventArgs)
        Dim flp As FlowLayoutPanel = CType(sender, FlowLayoutPanel)
        flp.BackColor = Color.MidnightBlue
        If flp.Name.StartsWith("pl") Then
            Label5.ForeColor = Color.Black
        End If
    End Sub

Open in new window

I see where you are setting e.Effect to "all" in the DragDrop event handler, but I believe that you need to set it in the DragOver event (which I don't see).
Ok I set .All in the DragOver and took the others out, but it is not scrolling. The FLP does have the .AutoScroll property set to True.
I set up a small test, and I do see that it doesn't scroll with the DragOver set to DragDropEffects.All.  But I started to think that if you are adding controls to a FlowLayoutPanel, you can scroll the control into view with ScrollControlIntoView(control).
This is my DataObject class, and each button that is created get a addhandler to the MyMouseDown Event.

MOst of the code comes from EE, I believe Idle_Mind  or yourself - many thanks of course...

Private Class myObject
        Inherits DataObject
   Private Sub New()
   End Sub
   Public Sub New(ByVal btn As Button)
      Me.SetData("myObject", False, btn)
   End Sub
End Class
 
Private Sub MyMouseDown(ByVal sender As Object, ByVal e As MouseEventArgs)
   DoDragDrop(New myObject(sender), DragDropEffects.All)
End Sub

Open in new window

I did find that method, not sure if I was using it correctly. I would need the currently focused one(during dragOver) + the next indexed UC, right?
If this is the DragDrop event handler:

Private Sub FLP_DragDrop(ByVal sender As Object, ByVal e As DragEventArgs)
        If e.Data.GetDataPresent("myObject") Then
            e.Effect = DragDropEffects.All
            Dim flp As FlowLayoutPanel = CType(sender, FlowLayoutPanel)
            Dim btn As Button = CType(e.Data.GetData("myObject"), Button)
            btn.Location = flp.PointToClient(New Point(e.X, e.Y))
            flp.Controls.Add(btn)
            flp.BackColor = Color.MidnightBlue
            If flp.Name.StartsWith("pl") Then
                Label5.ForeColor = Color.Black
            End If
        End If
    End Sub

then, once you add the 'btn' control to the FlowLayoutPanel, then you should be able to scroll the control into view.

            flp.Controls.Add(btn)
            flp.ScrollControlIntoView(btn)
Not working, I do have an API I was trying to wire up, I need to activate it when the screen points are < or > a certain point in the FLP

Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As IntPtr, ByVal wMsg As Integer, ByVal wParam As Integer, ByRef lParam As Integer) As Integer
Dim vsFLPmax As Integer = 0
Private mintScrollDirection As Integer
Private Sub flp1_ControlAdded(ByVal sender As Object, ByVal e As System.Windows.Forms.ControlEventArgs) Handles flp1.ControlAdded
        vsFLPmax = vsFLPmax + 1
        If flp1.Controls.Count > 8 Then vsFLP.Visible = True
End Sub
Private Sub tmrLVScroll_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles tmrVScroll.Tick
        ScrollControl(flp1, mintScrollDirection)
End Sub
Private Sub ScrollControl(ByRef objControl As Control, ByRef intDirection As Integer)
        ' This function enables a control to scroll
        ' during a drag-and-drop operation.
        ' For lngDirection, a value of 0 scrolls up; a value of 1 scrolls down.
        Const WM_VSCROLL As Integer = &H115
        SendMessage(objControl.Handle, WM_VSCROLL, intDirection, 0)
End Sub

Open in new window

Here is a screenshot of the flp1 holding UC labeled CR-1 thru CR-10, flp2 is the FLP in the UC which is transparent but lives b/t the two labels i.e. CR-1 and "1" at the end.

MyFLP.jpg
I am ok with coming up with a diff set of controls, if this is current plan will not work. Any ideas will be considered.

Thanks TheLearnedOne for your help thus far.
What is the nature of the requirement?  What does the screen need to do?
The UC  is a collection of items that can be created during runtime. At some point items need to be moved from one container to a diff container, and at times I add/remove them. Containers worked well, I even had a FLP where if you dropped the item it would remove it.  Like managing items at diff locations, but be able to view them all on one screen - scrolling when needed.
This is also a touch screen app, so somewhat larger size controls. Each container will only hold 4-5 items, but don't want to limit this.
If I use a loop like(below) I can get the FLP to scroll down and if repaints the child controls, but it will not let me drop the item during or after the loop (move the cursor out of the bounds of the loops). Is there something here we can use?

x = Cursor.Position 
    Do While x.Y < 200 'near the top of FLP1
       flp1.VerticalScroll.Value -= 3
       flp1.Refresh()
    Loop
    Do While x.Y > 690 'near the bottom of FLP1
       flp1.VerticalScroll.Value += 3
       flp1.Refresh()
    Loop

Open in new window

I set up a small test:

1) FlowLayoutPanel

        '
        'FlowLayoutPanel1
        '
        Me.FlowLayoutPanel1.AllowDrop = True
        Me.FlowLayoutPanel1.AutoScroll = True
        Me.FlowLayoutPanel1.BackColor = System.Drawing.SystemColors.ControlLight
        Me.FlowLayoutPanel1.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D
        Me.FlowLayoutPanel1.Location = New System.Drawing.Point(71, 86)
        Me.FlowLayoutPanel1.Name = "FlowLayoutPanel1"
        Me.FlowLayoutPanel1.Size = New System.Drawing.Size(150, 94)
        Me.FlowLayoutPanel1.TabIndex = 0

2) Dragged and dropped files from the Windows Explorer.

3) After each file is dropped on the form, a Label is created, and scrolled into view.
    Private Sub FlowLayoutPanel1_DragOver(ByVal sender As System.Object, ByVal e As System.Windows.Forms.DragEventArgs) Handles FlowLayoutPanel1.DragOver
        e.Effect = DragDropEffects.All
    End Sub
 
    Private Sub FlowLayoutPanel1_DragDrop(ByVal sender As System.Object, ByVal e As System.Windows.Forms.DragEventArgs) Handles FlowLayoutPanel1.DragDrop
        For Each name As String In e.Data.GetData(DataFormats.FileDrop)
            Dim label As New Label
            label.AutoSize = True
            label.Location = New Point(e.X, e.Y)
            label.Text = IO.Path.GetFileName(name)
            Me.FlowLayoutPanel1.Controls.Add(label)
            Me.FlowLayoutPanel1.ScrollControlIntoView(label)
        Next name
    End Sub

Open in new window

That makes sense, but I am dragging a control from a UC's Flp to a diff. UC's FLP inside of the same larger FLP which holds all the UCs. The reason I am using a FLP for the main container is the stacking effect they have. Here is a screenshot of the form again with the FLPs in the UCs highlighted lightBlue. As you see on the top there is where I create an item ->type into the textbox -> then click the add button -> there is a container just right of the button -> then drag this control to a UC's FLP - not the large FLP that holds the UCs - at times there will be more UCs in the Large FLP than that control can show. So I can't drop something into a UCs FLP if I can't see it on the screen (out of the visble area) so while dragging I need the Large FLP to scroll while I am dragging - like other controls (listview/treeview) I've seen. I made the Main FLPs DragOver Event in the designer, and is diff than the custom DragOver sub for the runtime generated FLPs that are in the UCs. I am just trying to reiderate - I know how hard it can be to understand the exact problem when reading a post. Thanks again...

The Saga continues...

MyFlp2.jpg
Ok, I'm a' getting close a' now. If I use the timer it does the job (a little rough right now) and let me drop the item as it is scrolling (yeah!) as the Do Loop freaks out the program. Help me smooth this out and we are done my friend. This will get the FLP to scroll down but not up (I have checked the coords), and when scrolling down it bounces but will not stay at the bottom - weird. And also if I drag the FLP's normal vertical scrollbar it will not stay where I put it - more weirdness.

' DragOver Event...
Try
If e.Data.GetDataPresent("myObject") Then
   Dim x As Point = Cursor.Position
   If x.Y < 110 Then
      isPositive = False
      tmrVScroll.Enabled = True
   Else
      tmrVScroll.Enabled = False
   End If
   If x.Y > 570 Then
      isPositive = True
      tmrVScroll.Enabled = True
   Else
      tmrVScroll.Enabled = False
   End If
End If
Catch
End Try
 
Private Sub tmrLVScroll_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles tmrVScroll.Tick
Try
   If isPositive = True Then
      flp1.VerticalScroll.Value += 10
   ElseIf isPositive = False Then
      flp1.VerticalScroll.Value -= 10
   End If
Catch
End Try
End Sub

Open in new window

Ok, I think I know what the bouncing is from, it is trying to refocus on the last control location to keep it visible, so how do I stop this behavior - I have a setting to stop the timers when it reaches minimum or maximum depending on which one is running? Also I am using 2 timers one for up and one for down this is working better.
You have a confusing array of events, and actions, and I don't have anything to test with.  If you could create a small test form that would highlight your problem, I could probably find a way through your problems.
It seems to be a pure focus problem, I imagine in the mouseDown event the button is selected/has focus then when this control is dragged and it is starting to leave the visible area of the large FLP the scroll tries to put it back into view. Is there something I can add in the FLP.Scroll event to prevent this, or do you know any properties that might be activating this. Can I unfocus this button? Or is there a way to just copy the data then delete this button - I would then have to worry about when the dragDrop was a non-viable location. Ideas?  
ASKER CERTIFIED SOLUTION
Avatar of Bob Learned
Bob Learned
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
OK, victory is mine, so all I had to do was reset the focus in the MouseDown Event. I simply called flp1.select() and viola.
This has been by far my hardest challenge to date, it is always hard to completely understand what each of us are up to, was I clear, clear as mud, not like I didn't try and give all the code - some vivacious screenshot, and in the end 1 line of code fixed it, sheees.
I know you didn't provide the answer, but you spent a lot of time and were a great sounding board for my crazy thought.
I will work on my description technique, in hopes you will continue to help me. You are one of the masters here, and I have found many of your answers for others and my own. Many thanks for your time. Don