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 欢迎交流 

转载于:https://www.cnblogs.com/ShenNan/p/4275494.html

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在WPF MVVM模式下,窗口的ShowDialog实现是通过使用自定义的对话框服务来实现的。 首先,我们需要创建一个实现了IDialogService接口的自定义对话框服务类,该接口定义了ShowDialog方法。例如: ``` public interface IDialogService { bool? ShowDialog(object viewModel); } ``` 然后,在实际的对话框服务类中,我们可以使用WPF的Window或者其他自定义的Window来实现ShowDialog方法。在ShowDialog方法内部,我们可以根据传入的ViewModel来创建对应的视图,并将ViewModel与视图进行关联。例如: ``` public class DialogService : IDialogService { public bool? ShowDialog(object viewModel) { var dialogWindow = new DialogWindow(); dialogWindow.DataContext = viewModel; return dialogWindow.ShowDialog(); } } ``` 在ViewModel中,我们需要使用对话框服务来调用ShowDialog方法,并将当前的视图模型作为参数传入。在调用ShowDialog方法后,可以根据返回值来判断对话框是通过"确定"按钮还是"取消"按钮关闭的。例如: ``` public class MainViewModel { private readonly IDialogService _dialogService; public MainViewModel(IDialogService dialogService) { _dialogService = dialogService; } public void OpenDialog() { var dialogViewModel = new DialogViewModel(); var result = _dialogService.ShowDialog(dialogViewModel); if (result == true) { // 确定按钮被点击 } else if (result == false) { // 取消按钮被点击 } } } ``` 最后,在使用MVVM模式的主视图或者其他视图中,我们可以通过依赖注入或者其他方式来创建对话框服务的实例,并将其作为参数传入ViewModel的构造函数中,以便于在ViewModel中调用ShowDialog方法来展示对话框。例如: ``` public partial class MainWindow : Window { private readonly MainViewModel _viewModel; public MainWindow() { InitializeComponent(); var dialogService = new DialogService(); _viewModel = new MainViewModel(dialogService); DataContext = _viewModel; } private void OpenDialogButton_Click(object sender, RoutedEventArgs e) { _viewModel.OpenDialog(); } } ``` 通过以上步骤,我们就可以实现在WPF MVVM模式下窗口ShowDialog的功能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值