• 可拖拽的ListBox


    可拖拽的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     }
    复制代码
     
     
    分类: 控件使用
  • 相关阅读:
    MSI文件静默安装
    C#文本文件或其他文件新内容追加
    VS2015在线安装包
    Hive创建表时添加中文注释后乱码问题
    scala获取字符串首字符和尾字符
    kafka topic常用命令
    supervisord实例配置
    pandas写数据进入数据库
    supervisord初体验
    python3 安装impyla相关的包
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/3301056.html
Copyright © 2020-2023  润新知