2010-12-04 11 views

Respuesta

9

¡Claro, es posible! Probablemente esté tratando de complicar demasiado la solución. Básicamente, todo lo que tiene que hacer es crear una subclase del estándar TabControl y agregar algo de lógica a los manejadores de eventos del mouse. Solo deberá verificar qué forma está arrastrando el usuario y volver a ordenarla en la colección TabPages.

Hay un par de soluciones completas disponibles en línea:

1

TabPages reordenamiento con arrastrar y soltar-de Ludwig B.
inspirado por http://dotnetrix.co.uk/tabcontrol.htm#tip7

 private void tc_MouseDown(object sender, MouseEventArgs e) 
     { 
      // store clicked tab 
      TabControl tc = (TabControl)sender; 
      int hover_index = this.getHoverTabIndex(tc); 
      if (hover_index >= 0) { tc.Tag = tc.TabPages[hover_index]; } 
     } 
     private void tc_MouseUp(object sender, MouseEventArgs e) 
     { 
      // clear stored tab 
      TabControl tc = (TabControl)sender; 
      tc.Tag = null; 
     } 
     private void tc_MouseMove(object sender, MouseEventArgs e) 
     {   
      // mouse button down? tab was clicked? 
      TabControl tc = (TabControl)sender; 
      if ((e.Button != MouseButtons.Left) || (tc.Tag == null)) return; 
      TabPage clickedTab = (TabPage)tc.Tag; 
      int clicked_index = tc.TabPages.IndexOf(clickedTab); 

      // start drag n drop 
      tc.DoDragDrop(clickedTab, DragDropEffects.All); 
     } 
     private void tc_DragOver(object sender, DragEventArgs e) 
     { 
      TabControl tc = (TabControl)sender; 

      // a tab is draged? 
      if (e.Data.GetData(typeof(TabPage)) == null) return; 
      TabPage dragTab = (TabPage)e.Data.GetData(typeof(TabPage)); 
      int dragTab_index = tc.TabPages.IndexOf(dragTab); 

      // hover over a tab? 
      int hoverTab_index = this.getHoverTabIndex(tc); 
      if (hoverTab_index < 0) { e.Effect = DragDropEffects.None; return; } 
      TabPage hoverTab = tc.TabPages[hoverTab_index]; 
      e.Effect = DragDropEffects.Move; 

      // start of drag? 
      if (dragTab == hoverTab) return; 

      // swap dragTab & hoverTab - avoids toggeling 
      Rectangle dragTabRect = tc.GetTabRect(dragTab_index); 
      Rectangle hoverTabRect = tc.GetTabRect(hoverTab_index); 

      if (dragTabRect.Width < hoverTabRect.Width) 
      { 
       Point tcLocation = tc.PointToScreen(tc.Location); 

       if (dragTab_index < hoverTab_index) 
       { 
        if ((e.X - tcLocation.X) > ((hoverTabRect.X + hoverTabRect.Width) - dragTabRect.Width)) 
         this.swapTabPages(tc, dragTab, hoverTab); 
       } 
       else if (dragTab_index > hoverTab_index) 
       { 
        if ((e.X - tcLocation.X) < (hoverTabRect.X + dragTabRect.Width)) 
         this.swapTabPages(tc, dragTab, hoverTab); 
       } 
      } 
      else this.swapTabPages(tc, dragTab, hoverTab); 

      // select new pos of dragTab 
      tc.SelectedIndex = tc.TabPages.IndexOf(dragTab); 
     } 

     private int getHoverTabIndex(TabControl tc) 
     { 
      for (int i = 0; i < tc.TabPages.Count; i++) 
      { 
       if (tc.GetTabRect(i).Contains(tc.PointToClient(Cursor.Position))) 
        return i; 
      } 

      return -1; 
     } 

     private void swapTabPages(TabControl tc, TabPage src, TabPage dst) 
     { 
      int index_src = tc.TabPages.IndexOf(src); 
      int index_dst = tc.TabPages.IndexOf(dst); 
      tc.TabPages[index_dst] = src; 
      tc.TabPages[index_src] = dst; 
      tc.Refresh(); 
     } 
+1

Sí, ya he vinculado a la misma muestra en mi respuesta. Hace varios meses. –

6

encontré el solution Iniciado por @Cody gris a ser sobre todo lo que quería, pero no vi la necesidad de que sea tan complicado.

Esta es mi simplificación, implementado mediante la derivación de TabControl:

public class DraggableTabControl : TabControl 
{ 
    private TabPage m_DraggedTab; 

    public DraggableTabControl() 
    { 
     MouseDown += OnMouseDown; 
     MouseMove += OnMouseMove; 
    } 

    private void OnMouseDown(object sender, MouseEventArgs e) 
    { 
     m_DraggedTab = TabAt(e.Location); 
    } 

    private void OnMouseMove(object sender, MouseEventArgs e) 
    { 
     if (e.Button != MouseButtons.Left || m_DraggedTab == null) 
     { 
      return; 
     } 

     TabPage tab = TabAt(e.Location); 

     if (tab == null || tab == m_DraggedTab) 
     { 
      return; 
     } 

     Swap(m_DraggedTab, tab); 
     SelectedTab = m_DraggedTab; 
    } 

    private TabPage TabAt(Point position) 
    { 
     int count = TabCount; 

     for (int i = 0; i < count; i++) 
     { 
      if (GetTabRect(i).Contains(position)) 
      { 
       return TabPages[i]; 
      } 
     } 

     return null; 
    } 

    private void Swap(TabPage a, TabPage b) 
    { 
     int i = TabPages.IndexOf(a); 
     int j = TabPages.IndexOf(b); 
     TabPages[i] = b; 
     TabPages[j] = a; 
    } 
} 

La API de arrastrar y soltar realmente están destinados a arrastrar las cosas entre aplicaciones separadas, o por lo menos, controles separados. Usarlos en este caso es excesivo.

Asegúrate de votar la respuesta de Cody también si votaste la mía, ya que está basada en la suya.

+0

¡Buen trabajo! Esta es una solución realmente simple. –

1

Extendí la respuesta de Jacob Stanley un poco. De esta manera, el intercambio no ocurrirá con demasiada frecuencia. Esto es especialmente útil para pestañas de diferentes tamaños, en cuyo caso la solución anterior se intercambiaría muy seguido mientras se arrastraba.

La diferencia en la experiencia del usuario es que tiene que arrastrar un poco más para mover realmente la pestaña. Pero esto es similar al reordenamiento de pestañas en los navegadores.

También agregué un cursor de mano mientras arrastro y habilité el doble almacenamiento en el búfer.

using System; 
using System.Drawing; 
using System.Windows.Forms; 

namespace Controls 
{ 
    public class DraggableTabControl : TabControl 
    { 
     private TabPage draggedTab; 

     public DraggableTabControl() 
     { 
      this.MouseDown += OnMouseDown; 
      this.MouseMove += OnMouseMove; 
      this.Leave += new System.EventHandler(this.DraggableTabControl_Leave); 

      this.SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.AllPaintingInWmPaint, true); 
     } 

     private void OnMouseDown(object sender, MouseEventArgs e) 
     { 
      draggedTab = TabAt(e.Location); 
     } 

     private void OnMouseMove(object sender, MouseEventArgs e) 
     { 
      if (e.Button != MouseButtons.Left || draggedTab == null) 
      { 
       this.Cursor = this.DefaultCursor; 
       draggedTab = null; 
       return; 
      } 

      int index = TabPages.IndexOf(draggedTab);   
      int nextIndex = index + 1; 
      int prevIndex = index - 1; 

      int minXForNext = int.MaxValue; 
      int maxXForPrev = int.MinValue; 

      var tabRect = GetTabRect(index); 

      if (nextIndex < TabPages.Count) 
      { 
       var nextTabRect = GetTabRect(nextIndex); 
       minXForNext = tabRect.Left + nextTabRect.Width; 
      } 

      if (prevIndex >= 0) 
      { 
       var prevTabRect = GetTabRect(prevIndex); 
       maxXForPrev = prevTabRect.Left + tabRect.Width; 
      } 

      this.Cursor = Cursors.Hand; 

      if (e.Location.X > maxXForPrev && e.Location.X < minXForNext) 
      { 
       return; 
      } 

      TabPage tab = TabAt(e.Location); 

      if (tab == null || tab == draggedTab) 
      { 
       return; 
      } 

      Swap(draggedTab, tab); 
      SelectedTab = draggedTab; 
     } 

     private TabPage TabAt(Point position) 
     { 
      int count = TabCount; 

      for (int i = 0; i < count; i++) 
      { 
       if (GetTabRect(i).Contains(position)) 
       { 
        return TabPages[i]; 
       } 
      } 

      return null; 
     } 

     private void Swap(TabPage a, TabPage b) 
     { 
      int i = TabPages.IndexOf(a); 
      int j = TabPages.IndexOf(b); 

      TabPages[i] = b; 
      TabPages[j] = a; 
     } 

     private void DraggableTabControl_Leave(object sender, EventArgs e) 
     { 
      this.Cursor = this.DefaultCursor; 
      draggedTab = null; 
     } 
    } 
} 
Cuestiones relacionadas