WPF4.0 DataGrid 拖拽行 排序

写在前边:内容,如题。事由,音乐播放器,歌曲排序。非原创,但有自主更新。

最终效果

sss

好吧,从头开始。公司要做一个简单的音乐播放器,其中音乐列表,肯定需要排序的。以前做过排序,很简单,如下图所示

虽完成功能,但操作体验不尽如人意。 因为其它播放器都是鼠标拖拽的。有 demo,所有功能在此demo基本之上

1,挖掘demo核心代码(已修正):

请首先确定 xaml中 DataGrid 添加以下属性: AllowDrop="True"

  1 public MainWindow()
  2         {
  3             InitializeComponent();
  4             this.Loaded += MainWindow_Loaded;
  5 
  6             vm = new PublishViewModel();
  7             vm.Container = this;
  8             this.DataContext = vm;
  9 
 10 
 11             this.CommandBindings.Add(new CommandBinding(ApplicationCommands.Close, OpenCmdExecuted));
 12             this.dg.PreviewMouseLeftButtonDown += dgEmployee_PreviewMouseLeftButtonDown;
 13             this.dg.Drop += dgEmployee_Drop;
 14 
 15             this.PreviewMouseUp += MainWindow_MouseUp;  //需要完全监听鼠标弹起事件,未达到
 16 
 17             this.dg.DragOver += dg_DragOver;
 18             this.dg.DragLeave += dg_DragLeave;
 19             this.dg.DragEnter += dg_DragEnter;
 20 
 21         }
 22         void MainWindow_MouseUp(object sender, MouseButtonEventArgs e)
 23         {
 24             LogHelper.Debug("mouseUp");
 25         }
 26 
 27         void dg_DragEnter(object sender, DragEventArgs e)
 28         {
 29             if (e.Data.GetFormats()[0] == typeof(MusicInfo).ToString())
 30             {
 31 
 32             }
 33             else
 34             {
 35                 MusicInfo m = new MusicInfo("添加到文件列表");
 36                 m.IsNew = true;
 37                 this.vm.SelectedMusic = m;
 38             }
 39 
 40         }
 41 
 42         void dg_DragLeave(object sender, DragEventArgs e)
 43         {
 44             this.popup1.IsOpen = false;
 45         }
 46 
 47         /// <summary>
 48         /// 拖动时,对插入行进行着色处理。1,排序拖动;2,外部文件拖放
 49         /// </summary>
 50         /// <param name="sender"></param>
 51         /// <param name="e"></param>
 52         void dg_DragOver(object sender, DragEventArgs e)
 53         {
 54 
 55             int index = UITools.GetDataGridItemCurrentRowIndex(e.GetPosition, dg);
 56 
 57             for (int i = 0; i < dg.Items.Count; i++)
 58             {
 59                 DataGridRow r = dg.ItemContainerGenerator.ContainerFromIndex(i) as DataGridRow;
 60                 if (i != index)
 61                 {
 62                     r.BorderBrush = new SolidColorBrush(Colors.Transparent);
 63                     r.BorderThickness = new Thickness(0, 0, 0, 0);
 64                 }
 65                 else
 66                 {
 67                     r.BorderBrush = new SolidColorBrush(Color.FromRgb(32, 164, 230));
 68                     Thickness th = new Thickness(0, 0, 0, 0);
 69 
 70                     if (index > prevRowIndex) th = new Thickness(0, 0, 0, 1);
 71                     else if (index < prevRowIndex) th = new Thickness(0, 1, 0, 0);
 72                     r.BorderThickness = th;
 73                 }
 74             }
 75 
 76             if (!popup1.IsOpen)
 77             {
 78                 popup1.IsOpen = true;
 79             }
 80             Size popupSize = new Size(popup1.ActualWidth + 110, popup1.ActualHeight + 10);
 81             Point p = e.GetPosition(this);
 82             p.X += 10;
 83             p.Y += 10;
 84             popup1.PlacementRectangle = new Rect(p, popupSize);
 85 
 86             // if (row != null) dg.SelectedItem = row.Item;
 87         }
 88 
 89         int prevRowIndex = -1;
 90         /// <summary>
 91         /// Defines the Drop Position based upon the index.
 92         /// </summary>
 93         /// <param name="sender"></param>
 94         /// <param name="e"></param>
 95         void dgEmployee_Drop(object sender, DragEventArgs e)
 96         {
 97             this.popup1.IsOpen = false;
 98             int index = UITools.GetDataGridItemCurrentRowIndex(e.GetPosition, dg);
 99 
100             if (index < 0 || index == prevRowIndex) return;
101             (dg.ItemContainerGenerator.ContainerFromIndex(index) as DataGridRow).BorderThickness = new Thickness(0, 0, 0, 0);
102 
103 
104             if (index >= dg.Items.Count - 1)
105             {
106                 index = dg.Items.Count - 1;
107             }
108 
109             if (vm.SelectedMusic.IsNew) //表示拖动文件至表格
110             {
111                 string[] obj = e.Data.GetData(DataFormats.FileDrop) as string[];
112                 foreach (string str in obj)
113                 {
114                     this.vm.CheckFile(str, ++index);
115                 }
116             }
117             else
118             {
119                 vm.FileList.RemoveAt(prevRowIndex);
120                 vm.FileList.Insert(index, vm.SelectedMusic);
121                 prevRowIndex = -1;
122             }
123         }
124 
125         void dgEmployee_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
126         {
127 
128             prevRowIndex = UITools.GetDataGridItemCurrentRowIndex(e.GetPosition, dg);
129             LogHelper.Debug("X " + e.GetPosition(this.dg).X.ToString());
130             //如果选中区域在第一列,即点击选择框,则不进行
131             if (e.GetPosition(this.dg).X < 30) return;
132 
133             if (prevRowIndex < 0) return;
134             dg.SelectedIndex = prevRowIndex;
135 
136             MusicInfo selectedEmp = dg.Items[prevRowIndex] as MusicInfo;
137 
138             if (selectedEmp == null) return;
139 
140             DragDropEffects dragdropeffects = DragDropEffects.Move;
141             this.vm.SelectedMusic = selectedEmp;
142             if (DragDrop.DoDragDrop(dg, selectedEmp, dragdropeffects)
143                                 != DragDropEffects.None)
144             {
145                 dg.SelectedItem = selectedEmp;
146             }
147         }
View Code

2,demo缺陷:

  • 拖拽时没有鼠标跟随,不知道拖拽何物
  • 准备放下时,不能显示准备插入的位置
  • 启用拖指导致checkBox无法点击(估计是因为previewMouseDown事件,阻档了click事件消息)

3,针对以上缺陷的完善

  • 鼠标跟随:xaml增 Popup块,隐藏。仅在拖动时显示。Popup展示内容与当选拖动行数据关联。
  •         <Popup  x:Name="popup1" IsHitTestVisible="False" Placement="RelativePoint"  AllowsTransparency="True">
                <Border BorderBrush="LightSteelBlue"  BorderThickness="2" Background="White" Opacity="0.95">
                    <StackPanel  Orientation="Horizontal" Margin="4,3,8,3">
                        <Image Source="res/icon.png" Width="16" Height="16" />
                        <TextBlock  FontSize="14"  FontWeight="Bold" VerticalAlignment="Center"
                            Text="{Binding Path=SelectedMusic.Path}"  Margin="8,0,0,0" />
                    </StackPanel>
                </Border>
            </Popup>
    View Code

    Popup要在 DragOver时显示。 见第一段代码: dg_DragOver方法中,位置的控制。

  • 插入位置显示:dg_DragOver方法中,计算当前鼠标位置对应的数据行,更改数据行的样式,增加Border边框线显示,达到目的。 但需要循环所有表格行,不在鼠标对应行,则删除样式。估计比较占用cpu资源。
  • 关于checkBox无法点击,发现问题后,试过在 MouseLeftButtonDown 进行拖拽动,这样checkBox可以点击但有50%的概念不能启动。后分析,计划依然使用 PreviewMouseLeftButtonDown。checkBox 在第一列,宽度40. 所以启动拖拽前,判断鼠标位置,x  是否 大于40。在小于40时,不启动,则checkBox完成点击事件。

4,其它:关于Popup的灵感,来自于另外一个demo,但没有链接,找不到了。它的大概意思是全完合用鼠标按下,移动,放下事件手写处理。而本例中使用的拖拽关键类:DragDrop.DoDragDrop()。再次感叹,条条道路通罗马。

5, 文字说明结束。文笔有限,附源码下载, 欢迎交流。

项目使用 vs2012编辑。不确定使用2010是否可以正常打开。

 

posted @ 2013-05-18 10:54  HappyMouse  阅读(3054)  评论(2编辑  收藏  举报