MVVM模式下实现拖拽

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

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

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

Item实体

CS

    public class ItemModel : ViewModelBase
    {
        public string ItemName { get; set; }
    }

组实体

CS

public class GroupModel : ViewModelBase
    {
        /// <summary>
        /// 组名
        /// </summary>
        public string GroupName { get; set; }

        private int groupCount;
        /// <summary>
        /// 组数量
        /// </summary>
        public int GroupCount
        {
            get { return groupCount; }
            set { groupCount = value; base.RaisePropertyChanged("GroupCount"); }
        }

        /// <summary>
        /// 子类集合
        /// </summary>
        public ObservableCollection<ItemModel> ItemModelList { get; set; }
    }

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

XAML

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

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

XAML

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

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

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

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

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

创建自定义树

CS

public class MyTreeView : TreeView
    {
        public MyTreeView()
        {

        }

        /// <summary>
        /// 自定义TreeView选中项,支持数据Binding
        /// </summary>
        public object MySelectItem
        {
            get { return GetValue(MySelectItemProperty); }
            set { SetValue(MySelectItemProperty, value); }
        }

        public static DependencyProperty MySelectItemProperty = DependencyProperty.Register("MySelectItem", typeof(object), typeof(MyTreeView));

        /// <summary>
        /// 当改变发生时,为自定义的SelectItem属性赋值
        /// </summary>
        /// <param name="e"></param>
        protected override void OnSelectedItemChanged(RoutedPropertyChangedEventArgs<object> e)
        {
            if (this.SelectedItem != null)
                this.MySelectItem = this.SelectedItem;
            base.OnSelectedItemChanged(e);
        }
    }

XAML

 <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}">
</mc:MyTreeView>

CS

        private TreeViewItem ti = new TreeViewItem();

        private void TreeView_MouseMove(object sender, MouseEventArgs e)
        {
            if (e.LeftButton == MouseButtonState.Pressed)
            {
                if (myTree.SelectedItem == null)
                    return;
                DragDrop.DoDragDrop(ti, sender, DragDropEffects.Move);
            }
        }

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

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

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

创建ListBox

           <ListBox ItemsSource="{Binding GameSourceList}" AllowDrop="true">
                <ListBox.ItemTemplate>
                    <DataTemplate>
                        <TextBlock Text="{Binding ItemName}"/>
                    </DataTemplate>
                </ListBox.ItemTemplate>
                <i:Interaction.Triggers>
                    <i:EventTrigger EventName="DragEnter">
                        <Command:EventToCommand Command="{Binding DragEnterCommand}" PassEventArgsToCommand="True"/>
                    </i:EventTrigger>
                    <i:EventTrigger EventName="DragOver">
                        <Command:EventToCommand Command="{Binding DragEnterCommand}" PassEventArgsToCommand="True"/>
                    </i:EventTrigger>
                    <i:EventTrigger EventName="Drop">
                        <Command:EventToCommand Command="{Binding DropCommand}" PassEventArgsToCommand="True"/>
                    </i:EventTrigger>
                </i:Interaction.Triggers>
            </ListBox>

ViewModel

public class MainViewModel : ViewModelBase
    {
        public MainViewModel()
        {
            Init();
        }

        #region Properties
        /// <summary>
        /// 数据源
        /// </summary>
        public ObservableCollection<GroupModel> GroupSourceList { get; set; }

        /// <summary>
        /// 数据源
        /// </summary>
        public ObservableCollection<ItemModel> GameSourceList { get; set; }

        private object selectGame;
        /// <summary>
        /// 当前选中项
        /// </summary>
        public object SelectGame
        {
            get { return selectGame; }
            set
            {
                selectGame = value;
                base.RaisePropertyChanged("SelectGame");
            }
        }
        #endregion

        #region Methods
        private void Init()
        {
            GameSourceList = new ObservableCollection<ItemModel>();
            GroupSourceList = new ObservableCollection<GroupModel>();
            GroupModel gp1 = new GroupModel();
            #region 模拟数据
            gp1.GroupName = "竞技游戏";
            gp1.ItemModelList = new ObservableCollection<ItemModel>();
            gp1.ItemModelList.Add(new ItemModel() { ItemName = "CS GO" });
            gp1.ItemModelList.Add(new ItemModel() { ItemName = "星际争霸2" });
            gp1.ItemModelList.Add(new ItemModel() { ItemName = "FIFA 14" });
            gp1.GroupCount = gp1.ItemModelList.Count;
            GroupModel gp2 = new GroupModel();
            gp2.GroupName = "网络游戏";
            gp2.ItemModelList = new ObservableCollection<ItemModel>();
            gp2.ItemModelList.Add(new ItemModel() { ItemName = "CS OnLine" });
            gp2.ItemModelList.Add(new ItemModel() { ItemName = "街头篮球" });
            gp2.ItemModelList.Add(new ItemModel() { ItemName = "完美世界" });
            gp2.GroupCount = gp2.ItemModelList.Count;
            GroupModel gp3 = new GroupModel();
            gp3.GroupName = "休闲游戏";
            gp3.ItemModelList = new ObservableCollection<ItemModel>();
            gp3.ItemModelList.Add(new ItemModel() { ItemName = "德州扑克" });
            gp3.ItemModelList.Add(new ItemModel() { ItemName = "街头篮球" });
            gp3.ItemModelList.Add(new ItemModel() { ItemName = "完美世界" });
            GroupSourceList.Add(gp1);
            GroupSourceList.Add(gp2);
            GroupSourceList.Add(gp3);
            gp3.GroupCount = gp3.ItemModelList.Count;
            #endregion
            DragEnterCommand = new RelayCommand<DragEventArgs>(DragEnter);
            DropCommand = new RelayCommand<DragEventArgs>(Drop);
        }

        private void DragEnter(DragEventArgs args)
        {
            if (SelectGame.GetType() == typeof(ItemModel)) //如果拖拽的对象是"游戏"则接受之
            {
                args.Effects = DragDropEffects.Move;
                System.Console.WriteLine("accept");
            }
            else
            {
                args.Effects = DragDropEffects.None;       //否则拒绝接受拖拽
                System.Console.WriteLine("no accept");
            }
            args.Handled = true;
        }

        private void Drop(DragEventArgs args)
        {
            GameSourceList.Add(SelectGame as ItemModel);   //将接受到的"游戏"写入ListBox
        }
        #endregion

        #region Commands

        public ICommand DragEnterCommand { get; set; }

        public ICommand DropCommand { get; set; }
        #endregion
    }

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

QQ 3045568793 欢迎交流 , 我叫山鸡 鸡巴的鸡

时间: 2024-10-29 13:46:18

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

浅析WPF中MVVM模式下命令与委托的关系

??各位朋友大家好,我是Payne,欢迎大家关注我的博客,我的博客地址是http://qinyuanpei.com.最近因为项目上的原因开始接触WPF,或许这样一个在现在来讲显得过时的东西,我猜大家不会有兴趣去了解,可是你不会明白对某些保守的项目来讲,安全性比先进性更为重要,所以当你发现银行这类机构还在使用各种"复古"的软件系统的时候,你应该相信这类东西的确有它们存在的意义.与此同时,你会更加深刻地明白一个道理:技术是否先进性和其流行程度本身并无直接联系.由此我们可以推论出:一项不流行

MVVM模式下如何使用ReactiveCocoa响应链式编程&lt;一&gt;

前一阵子公司要求项目从新架构,但又只给不到一个月的时间,这显然是不可能的.但从新架构又是在所难免的,和同事商定后决定一部分交互逻辑比较少的界面先使用MVVM架构,然后慢慢修改.下面整理了一下这次重构的遇到的问题,并希望能给大家一些帮助. 1.ReactiveCocoa的使用 要使用MVVM模式编程收下选择一个框架,当然不仅仅是ReactiveCocoa这一个框架,这里就不多说.当然我也没用过别的,如果哪位看官用过可以多多指教.接下来我就按步骤说了: 第一步:导入ReactiveCocoa框架,建

MVVM模式下的OpenFileDialog

对于MVVM模式下的ViewModel层来说,是不应该直接访问OpenFileDialog或者FolderBrowserDialog的,否则VM会变得难以测试. 参考StackOverFlow,对ViewModel进行改造,使OpenFileDialog动作也可以测试. 首先实现接口IIOService public interface IIOService { string OpenFileDialog(string srcFilter = ""); IList<string&

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

学习笔记---Javascript事件Event.IE浏览器下的拖拽效果     1. 关于event常用属性有returnValue(是否允许事件处理继续进行, false为停止继续操作).srcElement(触发事件的事件源对象)和attachEvent("onclick",function(){...}); 2. a. 实现拖放(Drag and Drop): 目前支支持IE, 若定制某对象为可拖放对象, 则必须覆盖目标对象的dragenter和dragover事件, 可以用e

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

MVVM模式下,ViewModel和View,Model有什么区别 Model:很简单,就是业务逻辑相关的数据对象,通常从数据库映射而来,我们可以说是与数据库对应的model. View:也很简单,就是展现出来的用户界面. 基本上,绝大多数软件所做的工作无非就是从数据存储中读出数据,展现到用户界面上,然后从用户界面接收输入,写入到数据存储里面去.所以,对于数据 存储(model)和界面(view)这两层,大家基本没什么异议.但是,如何把model展现到view上,以及如何把数据从view写入到m

MVVM模式下 DataTemplate 中控件的绑定

原文:MVVM模式下 DataTemplate 中控件的绑定 今天给ListBox中通过DataTemplate生成的Button绑定命令时,一开始Button始终找不到绑定的命令.现找到了正确的绑定方式,特来记录一下. 先上个正确的示例: <ListBox Grid.Column="0" ItemsSource="{Binding CallBussiness}"> <ListBox.ItemsPanel> <ItemsPanelTem

WPF MVVM模式下动画的实现

原文:WPF MVVM模式下动画的实现 在MVVM模式下,数据的显示都是通过绑定来实现的.当我们在ViewModel里修改数据时,View里面的界面会瞬间变化.但是如果我们希望这个变化有一个动画效果,应该怎么做呢? 可能一开始我们会想到DoubleAnimation.StoryBoard这些东西,但我们很快就会发现,它们只能操作View里面的元素,我们无法在ViewModel里使用它们. 我们在这里使用的方法是:创建一个类似DoubleAnimation的类,它的操作对象就是普通的double类

MVVM 模式下iOS项目目录结构详细说明

?更多技术干货请戳:听云博客 我们在做项目的时候,会经常用到各种设计模式,最常见的要数 MVC (模型,视图,控制器)了.但是,今天我们要说的是另一种设计模式——MVVM. 所以 MVVM 到底是什么?下面,我们将结合代码,说明 MVVM 设计模式以及项目目录结构. 一.MVVM 模式介绍  MVVM 是 Model-View-View Model 的缩写,MVVM 听起来好像很复杂的样子,但它本质上就是MVC 的改进版.MVVM 就是将其中的View 的状态和行为抽象化,让我们将视图 UI 和

WPF学习笔记:MVVM模式下,ViewModel如何关闭View?

原文:http://blog.csdn.net/leftfist/article/details/32349731 矫枉过正,从一个极端走向另一个极端.MVVM模式,View只负责呈现,虽然也有后台代码,但基本上就是摆设,VM接管了一切的逻辑处理. 那么,现在,大能的VM已经完成了所有的事情,这个窗口V如何才能自动关闭呢? 据我目前少得可怜的WPF知识可知,有两种方案: 方案一.利用View里的IsEnable属性. 原理是这样的: 1.UI中的IsEnabled绑定VM中的属性 2.UI的后台