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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM