Question

I have a WinForm application using a FlowLayoutPanel that displays .TIFF files that have multiple pages. The FlowLayoutPanel displays all the pages in a ThumbNails View.

I have implemented the Drag Drop Logic which works fine for individual items. Now, I would now like to change it to allow the user to select multiple thumbnails (using the CTRL or the Shift Key) and drag drop to a different spot.

//** Logic after each thumbnail is generated:
PictureBox thumb = new myProject.utility.PictureBox(pageNum);

thumb.Image = doc.getThumb(pageNum);  //since we pre loaded, we won't stall the gui thread.
thumb.Click += new System.EventHandler(
    (thumbSend, thumbEvent) =>
    {
        highLightThumb(thumb.getPage());
    }
);
thumb.DoubleClick += new System.EventHandler(
    (thumbSend, thumbEvent) =>
    {
        selectedDoc = thumb.getPage();
        me.Visible = false;
    }
);
thumbFlow.Controls.Add(thumb);
if (selectedDoc == pageNum)
    highLightThumb(pageNum);



//** Highlight Methods
private void highLightThumb(int page)
{
   //clear highlight
    foreach (Control c in thumbFlow.Controls)
    {
        if (c is PictureBox)
        {
            ((PictureBox)c).highlight = false;
         }
    }

    //apply highlight
    foreach (Control c in thumbFlow.Controls)
    {
        if (c is PictureBox)
        {
            PictureBox thumbFrame = (PictureBox)c;
            if (page == thumbFrame.getPage())
                thumbFrame.highlight = true;
        }
    }

}

Below is the existing drag drop logic.

//**********************//
//** Drag/Drop Events **//
//**********************//
private void thumbFlow_DragDrop(object sender, DragEventArgs e)
{
    PictureBox data = (PictureBox)e.Data.GetData(typeof(PictureBox));
    FlowLayoutPanel _destination = (FlowLayoutPanel)sender;

    Point p = _destination.PointToClient(new Point(e.X, e.Y));
    var item = _destination.GetChildAtPoint(p);
    if (item == null)
    {
        p.Y = p.Y - 10;
        item = _destination.GetChildAtPoint(p);
    }
    int index = _destination.Controls.GetChildIndex(item, false);
    if (index < 0)
        return;

    _destination.Controls.SetChildIndex(data, index);
    _destination.Invalidate();

}

private void thumbFlow_DragEnter(object sender, DragEventArgs e)
{
    //apply/clear highlight
    foreach (Control c in thumbFlow.Controls)
    {
        if (c is PictureBox)
        {
            PictureBox thumbFrame = (PictureBox)c;
            if (thumbFrame == ActiveControl)
            {
                thumbFrame.highlight = true;
            }
            else
            {
                ((PictureBox)c).highlight = false;
            }
        }
    }
    e.Effect = DragDropEffects.Move;
    if (dragDropOccurred == false)
    {
        dragDropOccurred = true;
    }
}

//** Scroll when user drags above or below the window object  **//
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();
    }

}

An option I am looking at would be change the highLightThumb method to check if the CTRL or Shift Key is selected and not disable the highlights

 if (Control.ModifierKeys != Keys.Control)
 //**
 if (Control.ModifierKeys != Keys.Shift)

Then change the DragDrop DragEnter Routine. Any Help would be greatly appreciated.

Was it helpful?

Solution

Here is what I ended up doing..

After the thumbnail is generated:

PictureBox thumb = new util.PictureBox(pageNum);
thumb.Image = doc.getThumb(pageNum);  //since we pre loaded, we won't stall the gui thread.
thumb.SizeMode = PictureBoxSizeMode.CenterImage;
thumb.BorderStyle = BorderStyle.FixedSingle;
thumb.Click += new System.EventHandler(
    (thumbSend, thumbEvent) =>
    {
        selectThumb(thumb);
    }
);
thumb.DoubleClick += new System.EventHandler(
    (thumbSend, thumbEvent) =>
    {
        selectedDoc = thumb.getPage();
        me.Visible = false;
    }
);
thumbFlow.Controls.Add(thumb);
if (selectedDoc == pageNum)
    selectThumb(thumb);

Now the Thumbnail Selection Code.
In the Picturebox logic, I put now have a variable titled pageIndex. it is initialized with the Page Number. The purpose of this is because as you will see later is when I spin though my objects, if I change the childindex value, it seems to occur right away and if I drag items 2,3,4 it will skip item 3 and only move item 2 & 4. So later when I rearrange the thumbs I first order by the pageIndex.

//*************************************//
//** Thumbnail Selection Processing  **//
//*************************************//
/// <summary>
/// Main Thumbnail selection area.  
///    If the Shift key is held down, look for a search between.  
///    If Ctrl key, do not clear selections as can select multiple.
/// </summary>
private void selectThumb(PictureBox _thumb)
{
    if (Control.ModifierKeys == Keys.Shift)
        if (SelectMultipleThumbs(_thumb.getPageIndex()))  //** if another thumb is selected, select all in between, then exit  **//
            return;

    if (Control.ModifierKeys != Keys.Control)
    {
        ClearAllSelections();
    }
    else
    {
        if (_thumb.IsSelected == true)
        {
            _thumb.IsSelected = false;
            return;
        }
    }

    _thumb.IsSelected = true;
}

/// <summary>
/// Check if there are other selected items.  If there is, select all between the start and end.
/// </summary>
private bool SelectMultipleThumbs(int _pageindex)
{
    //** Check if there are other objects that have been selected **/
    int? otherSelPageIndex = GetPageIndexOfThumbSelected(_pageindex);
    if (otherSelPageIndex != null)
    {
        ApplySelectionBetweenStartEndPageIndex(_pageindex, Convert.ToInt32(otherSelPageIndex));
        return true;
    }
    return false;
}

/// <summary>
/// Apply Selection if between start and end Pages
/// </summary>
private void ApplySelectionBetweenStartEndPageIndex(int _val1, int _val2)
{
    int startThumb = _val1;
    int endThumb = _val2;
    if (_val1 > _val2)
    {
        startThumb = _val2;
        endThumb = _val1;
    }

    foreach (PictureBox thumbFrame in thumbFlow.Controls.OfType<PictureBox>().OrderBy(si => si.pageIndex))
    {
        if (isBetween(thumbFrame.getPageIndex(), startThumb, endThumb))
            thumbFrame.IsSelected = true;
        else
            thumbFrame.IsSelected = false;
    }
}

/// <summary>
/// Clear All Highlight
/// </summary>
private void ClearAllSelections()
{
    foreach (PictureBox thumbFrame in thumbFlow.Controls.OfType<PictureBox>())
    {
        thumbFrame.IsSelected = false;
    }
}

/// <summary>
/// Check for any selected items prior
/// </summary>
private int? GetPageIndexOfThumbSelected(int _pageindex)
{
    foreach (PictureBox thumbFrame in thumbFlow.Controls.OfType<PictureBox>())
    {
        if (thumbFrame.IsSelected &&
            _pageindex != thumbFrame.getPageIndex())
        {
            return thumbFrame.getPageIndex();
        }
    }
    return null;
}

Now to the Processing of the Drag Drop.

private void thumbFlow_DragDrop(object sender, DragEventArgs e)
{
    FlowLayoutPanel _destination = (FlowLayoutPanel)sender;

    Point p = _destination.PointToClient(new Point(e.X, e.Y));
    var item = _destination.GetChildAtPoint(p);
    if (item == null)
    {
        p.Y = p.Y - 10;
        item = _destination.GetChildAtPoint(p);
    }
    int dropIndexValue = _destination.Controls.GetChildIndex(item, false);
    if (dropIndexValue < 0)
        return;

    //**************************************************//
    //**  Process multiple Select Drag / Drop   
    //**    If Drag From > Drag To, move after.
    //**    If Drag From < Drag To, move before.
    //**************************************************//

    //** First .. Find all items that are selected **//
    Boolean WasDragUp = false;
    int? firstDragIndexValue = null;
    int newIndexVal = dropIndexValue;
    foreach (PictureBox thumbFrame in thumbFlow.Controls.OfType<PictureBox>().Where(selVal => selVal.IsSelected))
    {
        if (firstDragIndexValue == null)
        {
            firstDragIndexValue = _destination.Controls.GetChildIndex(thumbFrame, false);
            if (firstDragIndexValue > dropIndexValue)
                WasDragUp = true;
        }
        thumbFrame.pageIndex = newIndexVal;
        newIndexVal++;
    }

    //** Second .. Find all items that are NOT selected **//
    if (WasDragUp)
    {
        newIndexVal = 0;
        foreach (PictureBox thumbFrame in thumbFlow.Controls.OfType<PictureBox>().Where(selVal => !selVal.IsSelected))
        {
            if (_destination.Controls.GetChildIndex(thumbFrame, false) == dropIndexValue)
                if (newIndexVal <= dropIndexValue)
                    newIndexVal = dropIndexValue + getThumbSelectedCnt();
            thumbFrame.pageIndex = newIndexVal;
            newIndexVal++;
        }
    }
    else
    {
        newIndexVal = 0;
        foreach (PictureBox thumbFrame in thumbFlow.Controls.OfType<PictureBox>().Where(selVal => !selVal.IsSelected))
        {
            thumbFrame.pageIndex = newIndexVal;
            if (_destination.Controls.GetChildIndex(thumbFrame, false) == dropIndexValue)
            {
                newIndexVal = dropIndexValue + getThumbSelectedCnt();
            }
            newIndexVal++;
        }
    }

    //** Third .. Set the Child Index value  **//
    newIndexVal = 0;
    foreach (PictureBox thumbFrame in thumbFlow.Controls.OfType<PictureBox>().OrderBy(si => si.pageIndex))
    {
        thumbFrame.pageIndex = newIndexVal;
        _destination.Controls.SetChildIndex(thumbFrame, thumbFrame.pageIndex);
        thumbFrame.IsSelected = false;
        newIndexVal++;
    }

    //** Finally, rebuild the screen  **//
    _destination.Invalidate();

}

private void thumbFlow_DragEnter(object sender, DragEventArgs e)
{
    //apply/clear highlight
    foreach (PictureBox thumbFrame in thumbFlow.Controls.OfType<PictureBox>())
    {
        if (thumbFrame == ActiveControl)
        {
            thumbFrame.IsSelected = true;
        }
    }

    e.Effect = DragDropEffects.Move;
    if (dragDropOccurred == false)
    {
        dragDropOccurred = true;
    }
}

/// <summary>
/// Scroll when user drags above or below the window object.
/// </summary>
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();
    }

}

Update the file

I would put my code in here but it really is more specific to each individual on what they plan on doing.. I basically rebuild the file and saved it.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top