zoukankan      html  css  js  c++  java
  • 可拖拽的ListBox

      之前在写播放器的时候,遇到了一个问题,现在播放器无论是千千,KuGoo还是比较原始的MediaPlayer,它们的播放表都是可以拖拽的,直接把文件拖到播放表实现歌曲的添加那个先暂且不说,光是播放表里面的歌曲次序也可以通过拖拽来调整。但是VS提供的ListBox没能直接通过设定某个属性实现这个拖拽排序,于是俺就开始了实现这功能的探索,无意中还找到了ListBox与ListBox之间元素的拖拽,于是一并实现了,遂述此文以记之。

      其实无论是ListBox里的拖拽排序,还是ListBox间的拖动,都是通过三个事件来实现的:DragDrop,DragOver和MouseDown,对于整个拖拽的过程来说,三个事件的触发顺序是MouseDown->DragOver->DragDrop。对于拖拽排序和控件间的拖动,代码会有所差异。下面则一分为二的说说各自的处理,由于我这里是扩展控件的,直接重写ListBox类的Onxxx方法。如果直接使用ListBox控件的话,就要在这三个事件绑定的方法里面写了。

      拖拽排序  

            protected override void  OnMouseDown(MouseEventArgs e)
            {
                base.OnMouseDoubleClick(e);
    
                if (this.Items.Count == 0 || e.Button != MouseButtons.Left || this.SelectedIndex == -1 || e.Clicks == 2)
                    return;
                
                int index = this.SelectedIndex;
                object item = this.Items[index];
                DragDropEffects dde = DoDragDrop(item,
                    DragDropEffects.All);
            }

    首先要判断一下当前的ListBox有没有元素,还有鼠标有没有点中元素。接着到拖拽的过程

            protected override void OnDragOver(DragEventArgs drgevent)
            {
                base.OnDragOver(drgevent);
    
                drgevent.Effect = DragDropEffects.Move;
            }

    最后到拖放结束,鼠标按键松开的时候触发

            protected override void OnDragDrop(DragEventArgs drgevent)
            {
                base.OnDragDrop(drgevent);
    
                object item = dragSource.SelectedItem;
    
                    int index = this.IndexFromPoint(this.PointToClient(new Point(drgevent.X, drgevent.Y)));
                    this.Items.Remove(item);
                    if (index < 0)
                        this.Items.Add(item);
                    else
                        this.Items.Insert(index, item);
            }

    主要是获取那个被选中(后来就被拖动)的那个元素,然后把它从ListBox先移除,从鼠标当前的坐标来获取到所在元素的索引值,那个位置,那个索引就是被拖拽的元素的新位置,用Insert把它插进去。

      ListBox间的拖动

      这个就要先知道各个方法究竟是那个控件的事件触发时调用的。其余大体上跟上面的是一致的。

      举个例子,现在有两个ListBox lst1,lst2。我把lst1的一个元素拖到lst2中去,事件触发的队列是这样的

      Lst1.MouseDown=>lst1.DragOver=>lst1.DragOver=>….lst1.DragOver=>lst2.DragOver=>lst2.DragOver=>…..=>lst2.DragOver=>lst2.DragDrop

    由于整个流程涉及到两个控件,最后元素的添加与元素的删除分别是两个控件的事,于是我这里就另外声明多一个静态字段来存放那个lst1。记录来源的ListBox只能在MouseDown记录了。

    public static ListBox dragSource;
    
            protected override void  OnMouseDown(MouseEventArgs e)
            {
                base.OnMouseDoubleClick(e);
    
                if (this.Items.Count == 0 || e.Button != MouseButtons.Left || this.SelectedIndex == -1 || e.Clicks == 2)
                    return;
                dragSource = this;
                
                int index = this.SelectedIndex;
                object item = this.Items[index];
                DragDropEffects dde = DoDragDrop(item,
                    DragDropEffects.All);
            }

    除了dragSource = this;外,其余都与拖拽排序的一样。

            protected override void OnDragOver(DragEventArgs drgevent)
            {
                base.OnDragOver(drgevent);
                drgevent.Effect = DragDropEffects.Move;
            }

    这个可以说跟拖拽排序的一模一样了。

            protected override void OnDragDrop(DragEventArgs drgevent)
            {
                base.OnDragDrop(drgevent);
    
                object item = dragSource.SelectedItem;
    
                if ( dragSource != this)
                {
                    dragSource.Items.Remove(item);
                    this.Items.Add(item);
                }
                
            }

      因为是ListBox间的拖动,所以源ListBox和目标ListBox不能一样,处理还更简单,从源ListBox把元素删掉,然后增加到当前的ListBox中来。 

      如果想要既要控件间的拖动,拖动后又要按位置插入,那就把两个处理融合一下咯,本文末尾有我拓展控件的整份源码。需要的园友可以展开来看一下。

      

      交替颜色

      下面还介绍我另外一个拓展,就是单双行的交替颜色。记得以前的千千的播放表是有交替颜色的,现在的不知道,太久没用了,KuGoo现在的没有了,MediaPlayer12的也没有。

      我这里是重写OnDrawItem,直接拖控件的可以用DrawItem时间,接下来就是GDI+的内容了。

            protected override void OnDrawItem(DrawItemEventArgs e)
            {
                if (this.Items.Count < 0) return;
                if (e.Index < 0) return;
                bool selected = (e.State & DrawItemState.Selected) == DrawItemState.Selected;
                if(selected)
                    e.Graphics.FillRectangle(selectRowBursh, e.Bounds);
                else if (e.Index % 2 != 0)
                    e.Graphics.FillRectangle(OddRowBursh, e.Bounds);
                else
                    e.Graphics.FillRectangle(EvenRowBursh, e.Bounds);
    
                if(selected)
                {
                    e.Graphics.DrawString(this.GetItemText(e.Index), e.Font,
                                selectFontBursh, e.Bounds);
                    
                }
                else
                {
                    e.Graphics.DrawString(this.GetItemText(e.Index), e.Font,
                                normalFontBursh, e.Bounds);
                }
                e.DrawFocusRectangle();
                base.OnDrawItem(e);
            }

      值得一提的是这里判断选中的不是用e.Index==this.SelectedIndex,而是用(e.State & DrawItemState.Selected) == DrawItemState.Selected,当ListBox的选择模式用了多选而不是单选的时候,调用Select属性会报错,这个也是上面拖拽的局限性,当ListBox是多选的时候,上面的拖拽就会抛异常了,而且如果单纯用e.Index==this.SelectIndex的话,选择了一个元素,当在选择另一个元素的时候,之前选择过的元素的高亮状态不会消失,这个是什么原因我也没搞懂。如果有哪位园友知道的,麻烦指点一下。

      最后附上整个控件的源码

      1     public class DragableListBox:ListBox
      2     {
      3         #region 字段
      4         private bool isDraw; //是否执行绘制
      5         SolidBrush evenRowBursh ;
      6         SolidBrush oddRowBursh;
      7         Brush normalFontBursh=SystemBrushes.ControlText;
      8         Brush selectFontBursh = SystemBrushes.HighlightText;
      9         Brush selectRowBursh =  SystemBrushes.Highlight;
     10         private bool dragAcross;
     11         private bool dragSort;
     12 
     13         public static ListBox dragSource;
     14         #endregion
     15 
     16         public DragableListBox()
     17         {
     18             this.DoubleBuffered = true;
     19             this.OddColor = this.BackColor;
     20         }
     21 
     22         #region 外放成员
     23 
     24         #region 属性
     25 
     26         [Description("跨ListBox拖放元素"), Category("行为")]
     27         public bool DragAcross 
     28         {
     29             get { return (dragAcross&&AllowDrop&&SelectionMode== System.Windows.Forms.SelectionMode.One); }
     30             set 
     31             {
     32                 dragAcross = value;
     33                 if (value) this.AllowDrop = true;
     34             }
     35         }
     36 
     37         [Description("元素拖动排序"),Category("行为")]
     38         public bool DragSort
     39         {
     40             get { return dragSort && AllowDrop && SelectionMode == System.Windows.Forms.SelectionMode.One; }
     41             set
     42             {
     43                 dragSort = value;
     44                 if (value) this.AllowDrop = true;
     45             }
     46         }
     47 
     48         private Color oddColor;
     49         [Description("单数行的底色"), Category("外观")]
     50         public Color OddColor
     51         {
     52             get { return oddColor; }
     53             set 
     54             {
     55                 oddColor = value;
     56                 isDraw = oddColor != this.BackColor;
     57                 if (isDraw) DrawMode = System.Windows.Forms.DrawMode.OwnerDrawFixed;
     58                 else DrawMode = System.Windows.Forms.DrawMode.Normal;
     59             }
     60         }
     61 
     62         #endregion
     63 
     64         #region 事件
     65 
     66         [Description("跨ListBox拖拽完成后触发"),Category("行为")]
     67         public event DraggdHandler DraggedAcross;
     68 
     69         [Description("拖拽排序后触发"), Category("行为")]
     70         public event DraggdHandler DraggedSort;
     71 
     72         #endregion
     73 
     74         #endregion
     75 
     76         #region 重写方法
     77 
     78         #region 拖拽
     79 
     80         protected override void OnDragDrop(DragEventArgs drgevent)
     81         {
     82             base.OnDragDrop(drgevent);
     83             if (!DragAcross && !DragSort) return;
     84 
     85             object item = dragSource.SelectedItem;
     86 
     87             if (DragAcross && !DragSort && dragSource != this)
     88             {
     89                 dragSource.Items.Remove(item);
     90                 this.Items.Add(item);
     91                 if (DraggedAcross != null)
     92                     DraggedAcross(this, new DraggedEventArgs() { DragItem=item, SourceControl=dragSource });
     93             }
     94             else if (DragSort &&(( dragSource == this&&! DragAcross)||DragAcross))
     95             {
     96                 int index = this.IndexFromPoint(this.PointToClient(new Point(drgevent.X, drgevent.Y)));
     97                 dragSource.Items.Remove(item);
     98                 if (index < 0)
     99                     this.Items.Add(item);
    100                 else
    101                     this.Items.Insert(index, item);
    102                 if (DragAcross && DraggedAcross != null)
    103                     DraggedAcross(this, new DraggedEventArgs() { DragItem=item,SourceControl=dragSource });
    104                 if (DraggedSort != null)
    105                     DraggedSort(this, new DraggedEventArgs() { DragItem=item,SourceControl=dragSource, DestineIndex=index });
    106             }
    107             
    108         }
    109 
    110         protected override void OnDragOver(DragEventArgs drgevent)
    111         {
    112             base.OnDragOver(drgevent);
    113             if (!DragAcross&&!DragSort) return;
    114 
    115             //dragDestince=this;
    116             drgevent.Effect = DragDropEffects.Move;
    117         }
    118 
    119         protected override void  OnMouseDown(MouseEventArgs e)
    120         {
    121             base.OnMouseDoubleClick(e);
    122             if (!DragAcross && !DragSort ) return;
    123 
    124             if (this.Items.Count == 0 || e.Button != MouseButtons.Left || this.SelectedIndex == -1 || e.Clicks == 2)
    125                 return;
    126             dragSource = this;
    127             
    128             int index = this.SelectedIndex;
    129             object item = this.Items[index];
    130             DragDropEffects dde = DoDragDrop(item,
    131                 DragDropEffects.All);
    132         }
    133 
    134         #endregion 
    135 
    136         #region 绘制
    137 
    138         protected override void OnDrawItem(DrawItemEventArgs e)
    139         {
    140             if (this.Items.Count < 0) return;
    141             if (!isDraw) return;
    142             if (e.Index < 0) return;
    143             bool selected = (e.State & DrawItemState.Selected) == DrawItemState.Selected;
    144             if(selected)
    145             //if (e.Index == this.SelectedIndex)
    146                 e.Graphics.FillRectangle(selectRowBursh, e.Bounds);
    147             else if (e.Index % 2 != 0)
    148                 e.Graphics.FillRectangle(OddRowBursh, e.Bounds);
    149             else
    150                 e.Graphics.FillRectangle(EvenRowBursh, e.Bounds);
    151 
    152             //if (e.Index == this.SelectedIndex )
    153             if(selected)
    154             {
    155                 e.Graphics.DrawString(this.GetItemText(e.Index), e.Font,
    156                             selectFontBursh, e.Bounds);
    157                 
    158             }
    159             else
    160             {
    161                 e.Graphics.DrawString(this.GetItemText(e.Index), e.Font,
    162                             normalFontBursh, e.Bounds);
    163             }
    164             e.DrawFocusRectangle();
    165             base.OnDrawItem(e);
    166         }
    167 
    168         protected override void Dispose(bool disposing)
    169         {
    170             base.Dispose(disposing);
    171             if (oddRowBursh != null) oddRowBursh.Dispose();
    172             if (evenRowBursh != null) evenRowBursh.Dispose();
    173         }
    174 
    175         #endregion
    176 
    177         #endregion
    178 
    179         #region 私有方法和属性
    180 
    181         private SolidBrush EvenRowBursh
    182         {
    183             get 
    184             {
    185                 if(evenRowBursh==null)
    186                 {
    187                     evenRowBursh = new SolidBrush(this.BackColor);
    188                     return evenRowBursh;
    189                 }
    190                 if ( evenRowBursh.Color == this.BackColor)return evenRowBursh;
    191                 evenRowBursh.Dispose();
    192                 evenRowBursh = new SolidBrush(this.BackColor);
    193                 return evenRowBursh;
    194             }
    195             set 
    196             {
    197                 if(evenRowBursh!=null) evenRowBursh.Dispose();
    198                 evenRowBursh = value;
    199             }
    200         }
    201 
    202         private SolidBrush OddRowBursh
    203         {
    204             get 
    205             {
    206                 if (oddRowBursh == null)
    207                 {
    208                     oddRowBursh = new SolidBrush(this.OddColor);
    209                     return oddRowBursh;
    210                 }
    211                 if (oddRowBursh.Color == this.OddColor) return oddRowBursh;
    212                 oddRowBursh.Dispose();
    213                 oddRowBursh = new SolidBrush(this.OddColor);
    214                 return oddRowBursh;
    215             }
    216             set 
    217             {
    218                 if (oddRowBursh != null) oddRowBursh.Dispose();
    219                 oddRowBursh = value;
    220             }
    221         }
    222 
    223         private string GetItemText(int index)
    224         {
    225             try
    226             {
    227                 object item = this.Items[index];
    228                 if (string.IsNullOrEmpty(this.DisplayMember) || string.IsNullOrWhiteSpace(this.DisplayMember))
    229                     return item.ToString();
    230                 PropertyInfo proInfo = item.GetType().GetProperty(this.DisplayMember);
    231                 return proInfo.GetValue(item, null).ToString();
    232             }
    233             catch { return this.Name; }
    234         }
    235 
    236         #endregion
    237 
    238         public class DraggedEventArgs:EventArgs
    239         {
    240             public ListBox SourceControl { get; set; }
    241 
    242             public object DragItem { get; set; }
    243 
    244             public int DestineIndex { get; set; }
    245 
    246             public DraggedEventArgs()
    247             {
    248                 DestineIndex = -1;
    249             }
    250         }
    251 
    252         public delegate void DraggdHandler(object sender, DraggedEventArgs e);
    253     }
    DragableListBox
  • 相关阅读:
    IXmlSerializable With WCFData Transfer in Service Contracts
    Difference Between XmlSerialization and BinarySerialization
    Using XmlSerializer (using Attributes like XmlElement , XmlAttribute etc ) Data Transfer in Service Contracts
    Introducing XML Serialization
    Version Tolerant Serialization
    Which binding is bestWCF Bindings
    Data Transfer in Service Contracts
    DataContract KnownTypeData Transfer in Service Contracts
    Using the Message ClassData Transfer in Service Contracts
    DataContract POCO SupportData Transfer in Service Contracts
  • 原文地址:https://www.cnblogs.com/HopeGi/p/3300276.html
Copyright © 2011-2022 走看看