在文章開始以前先看一看效果圖網絡
咱們能夠拖拽一個"遊戲"給ListBox,而且ListBox也能接受拖拽過來的數據, 可是咱們不能拖拽一個"遊戲類型"給它。ide
因此當拖拽開始發生的時候咱們必須添加一些限制條件,以防止接受不正確的數據。this
Item實體spa
CScode
public class ItemModel : ViewModelBase { public string ItemName { get; set; } }
組實體對象
CSblog
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 歡迎交流