在文章开始之前先看一看效果图

我们可以拖拽一个"游戏"给ListBox,并且ListBox也能接受拖拽过来的数据, 但是我们不能拖拽一个"游戏类型"给它。

所以当拖拽开始发生的时候我们必须添加一些限制条件,以防止接受不正确的数据。

Item实体

CS

1
2
3
4
public class ItemModel : ViewModelBase
{
    public string ItemName { get; set; }
}

组实体

CS

  1. public class GroupModel : ViewModelBase
  2. {
  3. /// <summary>
  4. /// 组名
  5. /// </summary>
  6. public string GroupName { get; set; }
  7.  
  8. private int groupCount;
  9. /// <summary>
  10. /// 组数量
  11. /// </summary>
  12. public int GroupCount
  13. {
  14. get { return groupCount; }
  15. set { groupCount = value; base.RaisePropertyChanged("GroupCount"); }
  16. }
  17.  
  18. /// <summary>
  19. /// 子类集合
  20. /// </summary>
  21. public ObservableCollection<ItemModel> ItemModelList { get; set; }
  22. }

给"游戏"实体创建一个模板

XAML

  1. <HierarchicalDataTemplate x:Key="template_Item">
  2. <TextBlock Text="{Binding ItemName}"/>
  3. </HierarchicalDataTemplate>

给"游戏组"实体创建一个模板

XAML

  1. <HierarchicalDataTemplate x:Key="template_Group" ItemsSource="{Binding ItemModelList}" ItemTemplate="{StaticResource template_Item}">
  2. <StackPanel Orientation="Horizontal">
  3. <TextBlock Text="{Binding GroupName}"/>
  4. <TextBlock Text="{Binding GroupCount}" Margin="5,0,0,0"/>
  5. </StackPanel>
  6. </HierarchicalDataTemplate>

但是当我准备给TreeView赋值的时候 , 我想起来TreeView的SelectedItem属性不是依赖属性 , 它不支持Binding操作

所以只有自己写一个控件继承TreeView了。为它扩展一个MySelectedItem属性出来。并且重写SelectedItemChange事件

把TreeView的SelectedItem交给扩展的依赖属性MySelectedItem .这样在界面上就可以Binding选中项了

不过由于TreeView各个节点的数据实体可能类型不相同,所以扩展的属性只能定义为object类型

创建自定义树

CS

  1. public class MyTreeView : TreeView
  2. {
  3. public MyTreeView()
  4. {
  5.  
  6. }
  7.  
  8. /// <summary>
  9. /// 自定义TreeView选中项,支持数据Binding
  10. /// </summary>
  11. public object MySelectItem
  12. {
  13. get { return GetValue(MySelectItemProperty); }
  14. set { SetValue(MySelectItemProperty, value); }
  15. }
  16.  
  17. public static DependencyProperty MySelectItemProperty = DependencyProperty.Register("MySelectItem", typeof(object), typeof(MyTreeView));
  18.  
  19. /// <summary>
  20. /// 当改变发生时,为自定义的SelectItem属性赋值
  21. /// </summary>
  22. /// <param name="e"></param>
  23. protected override void OnSelectedItemChanged(RoutedPropertyChangedEventArgs<object> e)
  24. {
  25. if (this.SelectedItem != null)
  26. this.MySelectItem = this.SelectedItem;
  27. base.OnSelectedItemChanged(e);
  28. }
  29. }

XAML

  1. <mc:MyTreeView x:Name="myTree" MouseMove="TreeView_MouseMove" TextBlock.FontSize="14" MySelectItem="{Binding SelectGame,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" ItemsSource="{Binding GroupSourceList}" ItemTemplate="{StaticResource template_Group}">
  2. </mc:MyTreeView>

CS

  1. private TreeViewItem ti = new TreeViewItem();
  2.  
  3. private void TreeView_MouseMove(object sender, MouseEventArgs e)
  4. {
  5. if (e.LeftButton == MouseButtonState.Pressed)
  6. {
  7. if (myTree.SelectedItem == null)
  8. return;
  9. DragDrop.DoDragDrop(ti, sender, DragDropEffects.Move);
  10. }
  11. }

DragDrop.DoDragDrop方法需要传入一个DependencyObject对象以设置其拖拽时的效果。

但由于TreeView做了数据绑定, 所以它的SelectItem取出来是一个数据实体。而不是一个DependencyObject对象了。

所以我用了一个比较SB的办法就是new一个TreeViewItem。然后设置拖拽移动的效果。

创建ListBox

  1. <ListBox ItemsSource="{Binding GameSourceList}" AllowDrop="true">
  2. <ListBox.ItemTemplate>
  3. <DataTemplate>
  4. <TextBlock Text="{Binding ItemName}"/>
  5. </DataTemplate>
  6. </ListBox.ItemTemplate>
  7. <i:Interaction.Triggers>
  8. <i:EventTrigger EventName="DragEnter">
  9. <Command:EventToCommand Command="{Binding DragEnterCommand}" PassEventArgsToCommand="True"/>
  10. </i:EventTrigger>
  11. <i:EventTrigger EventName="DragOver">
  12. <Command:EventToCommand Command="{Binding DragEnterCommand}" PassEventArgsToCommand="True"/>
  13. </i:EventTrigger>
  14. <i:EventTrigger EventName="Drop">
  15. <Command:EventToCommand Command="{Binding DropCommand}" PassEventArgsToCommand="True"/>
  16. </i:EventTrigger>
  17. </i:Interaction.Triggers>
  18. </ListBox>

ViewModel

  1. public class MainViewModel : ViewModelBase
  2. {
  3. public MainViewModel()
  4. {
  5. Init();
  6. }
  7.  
  8. #region Properties
  9. /// <summary>
  10. /// 数据源
  11. /// </summary>
  12. public ObservableCollection<GroupModel> GroupSourceList { get; set; }
  13.  
  14. /// <summary>
  15. /// 数据源
  16. /// </summary>
  17. public ObservableCollection<ItemModel> GameSourceList { get; set; }
  18.  
  19. private object selectGame;
  20. /// <summary>
  21. /// 当前选中项
  22. /// </summary>
  23. public object SelectGame
  24. {
  25. get { return selectGame; }
  26. set
  27. {
  28. selectGame = value;
  29. base.RaisePropertyChanged("SelectGame");
  30. }
  31. }
  32. #endregion
  33.  
  34. #region Methods
  35. private void Init()
  36. {
  37. GameSourceList = new ObservableCollection<ItemModel>();
  38. GroupSourceList = new ObservableCollection<GroupModel>();
  39. GroupModel gp1 = new GroupModel();
  40. #region 模拟数据
  41. gp1.GroupName = "竞技游戏";
  42. gp1.ItemModelList = new ObservableCollection<ItemModel>();
  43. gp1.ItemModelList.Add(new ItemModel() { ItemName = "CS GO" });
  44. gp1.ItemModelList.Add(new ItemModel() { ItemName = "星际争霸2" });
  45. gp1.ItemModelList.Add(new ItemModel() { ItemName = "FIFA 14" });
  46. gp1.GroupCount = gp1.ItemModelList.Count;
  47. GroupModel gp2 = new GroupModel();
  48. gp2.GroupName = "网络游戏";
  49. gp2.ItemModelList = new ObservableCollection<ItemModel>();
  50. gp2.ItemModelList.Add(new ItemModel() { ItemName = "CS OnLine" });
  51. gp2.ItemModelList.Add(new ItemModel() { ItemName = "街头篮球" });
  52. gp2.ItemModelList.Add(new ItemModel() { ItemName = "完美世界" });
  53. gp2.GroupCount = gp2.ItemModelList.Count;
  54. GroupModel gp3 = new GroupModel();
  55. gp3.GroupName = "休闲游戏";
  56. gp3.ItemModelList = new ObservableCollection<ItemModel>();
  57. gp3.ItemModelList.Add(new ItemModel() { ItemName = "德州扑克" });
  58. gp3.ItemModelList.Add(new ItemModel() { ItemName = "街头篮球" });
  59. gp3.ItemModelList.Add(new ItemModel() { ItemName = "完美世界" });
  60. GroupSourceList.Add(gp1);
  61. GroupSourceList.Add(gp2);
  62. GroupSourceList.Add(gp3);
  63. gp3.GroupCount = gp3.ItemModelList.Count;
  64. #endregion
  65. DragEnterCommand = new RelayCommand<DragEventArgs>(DragEnter);
  66. DropCommand = new RelayCommand<DragEventArgs>(Drop);
  67. }
  68.  
  69. private void DragEnter(DragEventArgs args)
  70. {
  71. if (SelectGame.GetType() == typeof(ItemModel)) //如果拖拽的对象是"游戏"则接受之
  72. {
  73. args.Effects = DragDropEffects.Move;
  74. System.Console.WriteLine("accept");
  75. }
  76. else
  77. {
  78. args.Effects = DragDropEffects.None; //否则拒绝接受拖拽
  79. System.Console.WriteLine("no accept");
  80. }
  81. args.Handled = true;
  82. }
  83.  
  84. private void Drop(DragEventArgs args)
  85. {
  86. GameSourceList.Add(SelectGame as ItemModel); //将接受到的"游戏"写入ListBox
  87. }
  88. #endregion
  89.  
  90. #region Commands
  91.  
  92. public ICommand DragEnterCommand { get; set; }
  93.  
  94. public ICommand DropCommand { get; set; }
  95. #endregion
  96. }

到这里一个简单的拖拽就完成了。

原地址:http://www.cnblogs.com/ShenNan/p/4275494.html

MVVM模式下实现拖拽的更多相关文章

  1. MVVM模式下弹出窗体

    原地址:http://www.cnblogs.com/yk250/p/5773425.html 在mvvm模式下弹出窗体,有使用接口模式传入参数new一个对象的,还有的是继承于一个window,然后在 ...

  2. Silverlight中在MVVM模式下对DatagridRow选择控件封装

    在项目中,凡是涉及到表格的地方用的最多的控件,自然少不了DataGrid的身影,它明了的展示各种数据让人十分喜欢.现在要实现一个功能,使DataGrid具有全选和项选中的功能,如果在传统后台代码中完成 ...

  3. js架构设计模式——MVVM模式下,ViewModel和View,Model有什么区别

    MVVM模式下,ViewModel和View,Model有什么区别 Model:很简单,就是业务逻辑相关的数据对象,通常从数据库映射而来,我们可以说是与数据库对应的model. View:也很简单,就 ...

  4. MVVM模式下 DataTemplate 中控件的绑定

    今天给ListBox中通过DataTemplate生成的Button绑定命令时,一开始Button始终找不到绑定的命令.现找到了正确的绑定方式,特来记录一下. 先上个正确的示例: <ListBo ...

  5. WPF中在MVVM模式下,后台绑定ListCollectionView事件触发问题

    问题:WPF中MVVM模式下 ListView绑定ListCollectionView时,CurrentChanged无法触发 解决方案: 初期方案:利用ListView的SelectionChang ...

  6. WPF实战案例-MVVM模式下在Xaml中弹出窗体

    相信很多学习和开发wpf项目的同学都了解过mvvm模式,同样,在mvvm模式下会有一个不可忽视的问题,就是怎么在xaml中弹出窗体,而不破坏MVVM本身的结构. 关于弹出窗体的方式还是很多的,本文先讲 ...

  7. 学习笔记---Javascript事件Event、IE浏览器下的拖拽效果

    学习笔记---Javascript事件Event.IE浏览器下的拖拽效果     1. 关于event常用属性有returnValue(是否允许事件处理继续进行, false为停止继续操作).srcE ...

  8. WPF MVVM模式下ComboBox级联效果 选择第一项

    MVVM模式下做的省市区的级联效果.通过改变ComboBox执行命令改变市,区. 解决主要问题就是默认选中第一项 1.首先要定义一个属性,继承自INotifyPropertyChanged接口.我这里 ...

  9. MVVM模式下 修改 store的ajax请求url。

    MVVM模式下 修改 store的ajax请求url. view.down('Pro').getViewModel().getStore('xx_store').proxy.url = "s ...

随机推荐

  1. MAC OS X 常用通用快捷键

    注:由于使用的是Windows键盘,习惯了Ctrl + c/v复制粘贴,所以修改了修饰键,Command(⌘)键和Control(^)键互换,以下的Ctrl键均为Command键,对应键盘上的实际左C ...

  2. code vs1506传话(塔尖)+tarjan图文详解

    1506 传话  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 白银 Silver 题解   题目描述 Description 一个朋友网络,如果a认识b,那么如果a第一次收到 ...

  3. 将xml文件作为一个小的数据库,进行学生的增删改查

    1.xml文件: <?xml version="1.0" encoding="UTF-8"?><Students> <studen ...

  4. OSG快速生成一个带有纹理的四边形Geometry

    可以使用Geometry头文件中的 Geometry* createTexturedQuadGeometry osg::ref_ptr<osg::Texture2D> texture = ...

  5. IIS 发布mvc 403.14

    转载: iis7 发布mvc3 遇到的HTTP错误 403.14-Forbidden Web 服务器被配置为不列出此目录的内容及Login on failed for “IIS APPPOOL\ASP ...

  6. cocospod 安装和使用 podfile 问题解决

    Podfile 不识别 usr_framework!,系本地Pods版本太低,要在0.36以上. 以下转自:http://blog.csdn.net/eqera/article/details/393 ...

  7. #import、#include、#import<>和#import””的区别

    一.#import与#include #import不会引起交叉编译的问题.因为在Objective-C中会存在C/C++和Object-C混编的问题,如果用#include引入头文件,会导致交叉编译 ...

  8. 优化MyBatis配置文件中的配置

    一.为实体类定义别名,简化sql映射xml文件中的引用 之前,我们在sql映射xml文件中的引用实体类时,需要写上实体类的全类名(包名+类名),如下: <!-- 创建用户(Create) --& ...

  9. 解决passwd 为普通用户设密码 不成功的方法

    echo "xxxxxxxxx"|passwd --stdin user_name #这样设置密码就可以成功!

  10. MySQL 主从同步

    http://blog.csdn.net/z69183787/article/details/53897894