using System; using System.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; using Tango.Core.IO; namespace Tango.FileSystem { public class FileExplorerControl : Control { private ListBox _listBox; private DataGrid _datagrid; private bool _preventSynchronization; private Point _dragOutStartPoint; private bool _isMouseDown; private List _selectedItemsBeforeDrag; public IFileSystemContainer CurrentItem { get { return (IFileSystemContainer)GetValue(CurrentItemProperty); } set { SetValue(CurrentItemProperty, value); } } public static readonly DependencyProperty CurrentItemProperty = DependencyProperty.Register("CurrentItem", typeof(IFileSystemContainer), typeof(FileExplorerControl), new PropertyMetadata(null)); public FileSystemItem SelectedItem { get { return (FileSystemItem)GetValue(SelectedItemProperty); } set { SetValue(SelectedItemProperty, value); } } public static readonly DependencyProperty SelectedItemProperty = DependencyProperty.Register("SelectedItem", typeof(FileSystemItem), typeof(FileExplorerControl), new PropertyMetadata(null)); public ICommand ItemDoubleClickedCommand { get { return (ICommand)GetValue(ItemDoubleClickedCommandProperty); } set { SetValue(ItemDoubleClickedCommandProperty, value); } } public static readonly DependencyProperty ItemDoubleClickedCommandProperty = DependencyProperty.Register("ItemDoubleClickedCommand", typeof(ICommand), typeof(FileExplorerControl), new PropertyMetadata(null)); public ICommand DeleteCommand { get { return (ICommand)GetValue(DeleteCommandProperty); } set { SetValue(DeleteCommandProperty, value); } } public static readonly DependencyProperty DeleteCommandProperty = DependencyProperty.Register("DeleteCommand", typeof(ICommand), typeof(FileExplorerControl), new PropertyMetadata(null)); public ICommand DropCommand { get { return (ICommand)GetValue(DropCommandProperty); } set { SetValue(DropCommandProperty, value); } } public static readonly DependencyProperty DropCommandProperty = DependencyProperty.Register("DropCommand", typeof(ICommand), typeof(FileExplorerControl), new PropertyMetadata(null)); public ICommand DragCommand { get { return (ICommand)GetValue(DragCommandProperty); } set { SetValue(DragCommandProperty, value); } } public static readonly DependencyProperty DragCommandProperty = DependencyProperty.Register("DragCommand", typeof(ICommand), typeof(FileExplorerControl), new PropertyMetadata(null)); public ImageSource DriveIcon { get { return (ImageSource)GetValue(DriveIconProperty); } set { SetValue(DriveIconProperty, value); } } public static readonly DependencyProperty DriveIconProperty = DependencyProperty.Register("DriveIcon", typeof(ImageSource), typeof(FileExplorerControl), new PropertyMetadata(null)); public ImageSource FolderIcon { get { return (ImageSource)GetValue(FolderIconProperty); } set { SetValue(FolderIconProperty, value); } } public static readonly DependencyProperty FolderIconProperty = DependencyProperty.Register("FolderIcon", typeof(ImageSource), typeof(FileExplorerControl), new PropertyMetadata(null)); public FileExplorerControlMode Mode { get { return (FileExplorerControlMode)GetValue(ModeProperty); } set { SetValue(ModeProperty, value); } } public static readonly DependencyProperty ModeProperty = DependencyProperty.Register("Mode", typeof(FileExplorerControlMode), typeof(FileExplorerControl), new PropertyMetadata(FileExplorerControlMode.Large)); public ObservableCollection SelectedItems { get { return (ObservableCollection)GetValue(SelectedItemsProperty); } set { SetValue(SelectedItemsProperty, value); } } public static readonly DependencyProperty SelectedItemsProperty = DependencyProperty.Register("SelectedItems", typeof(ObservableCollection), typeof(FileExplorerControl), new PropertyMetadata(null, (d, e) => (d as FileExplorerControl).OnSelectedItemsChanged())); public bool AllowDrag { get { return (bool)GetValue(AllowDragProperty); } set { SetValue(AllowDragProperty, value); } } public static readonly DependencyProperty AllowDragProperty = DependencyProperty.Register("AllowDrag", typeof(bool), typeof(FileExplorerControl), new PropertyMetadata(null)); static FileExplorerControl() { DefaultStyleKeyProperty.OverrideMetadata(typeof(FileExplorerControl), new FrameworkPropertyMetadata(typeof(FileExplorerControl))); } public FileExplorerControl() { _selectedItemsBeforeDrag = new List(); } public override void OnApplyTemplate() { base.OnApplyTemplate(); _listBox = GetTemplateChild("PART_listbox") as ListBox; _datagrid = GetTemplateChild("PART_datagrid") as DataGrid; _listBox.SelectionChanged += _listBox_SelectionChanged; _datagrid.SelectionChanged += _datagrid_SelectionChanged; } protected override void OnPreviewKeyUp(KeyEventArgs e) { base.OnPreviewKeyUp(e); if (e.Key == Key.Delete) { if (SelectedItems != null && SelectedItems.Count > 0) { DeleteCommand?.Execute(SelectedItems); } } } private void _datagrid_SelectionChanged(object sender, SelectionChangedEventArgs e) { if (!_preventSynchronization) { _preventSynchronization = true; _listBox.SelectedItems.Clear(); foreach (var item in _datagrid.SelectedItems) { _listBox.SelectedItems.Add(item); } SynchronizeSelectedItems(_listBox.SelectedItems); _preventSynchronization = false; } } private void _listBox_SelectionChanged(object sender, SelectionChangedEventArgs e) { if (!_preventSynchronization) { _preventSynchronization = true; _datagrid.SelectedItems.Clear(); foreach (var item in _listBox.SelectedItems) { _datagrid.SelectedItems.Add(item); } SynchronizeSelectedItems(_listBox.SelectedItems); _preventSynchronization = false; } } private void SynchronizeSelectedItems(IList items) { if (SelectedItems == null) { SelectedItems = items.Cast().ToObservableCollection(); } else { SelectedItems.Clear(); foreach (var item in items.Cast().ToList()) { SelectedItems.Add(item); } } } private void OnSelectedItemsChanged() { if (SelectedItems != null) { SelectedItems.CollectionChanged -= SelectedItems_CollectionChanged; SelectedItems.CollectionChanged += SelectedItems_CollectionChanged; SynchronizeControls(); } } private void SelectedItems_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) { SynchronizeControls(); } private void SynchronizeControls() { if (_listBox == null) return; if (!_preventSynchronization) { _preventSynchronization = true; _listBox.SelectedItems.Clear(); _datagrid.SelectedItems.Clear(); foreach (var item in SelectedItems) { _listBox.SelectedItems.Add(item); _datagrid.SelectedItems.Add(item); } _preventSynchronization = false; } } protected override void OnDrop(DragEventArgs e) { base.OnDrop(e); try { string[] items = (string[])e.Data.GetData(DataFormats.FileDrop, false); if (items != null && items.Length > 0) { List fItems = new List(); foreach (var item in items) { if (Directory.Exists(item)) { fItems.Add(new FolderItem() { Path = item }); } else if (File.Exists(item)) { fItems.Add(new FileItem() { Path = item }); } } if (fItems.Count > 0) { DropCommand?.Execute(fItems); } } } catch { } //Ignore } protected override void OnPreviewMouseLeftButtonDown(MouseButtonEventArgs e) { base.OnPreviewMouseLeftButtonDown(e); if (!AllowDrag) return; if (e.OriginalSource is FrameworkElement) { var listBoxItem = (e.OriginalSource as FrameworkElement).FindAncestor(); var dataGridRow = (e.OriginalSource as FrameworkElement).FindAncestor(); if (listBoxItem == null && dataGridRow == null) { return; } } _selectedItemsBeforeDrag.Clear(); _selectedItemsBeforeDrag.AddRange(SelectedItems); _isMouseDown = true; AllowDrop = false; _dragOutStartPoint = e.GetPosition(null); } protected override void OnPreviewMouseLeftButtonUp(MouseButtonEventArgs e) { base.OnPreviewMouseLeftButtonUp(e); AllowDrop = true; _isMouseDown = false; } protected async override void OnPreviewMouseMove(MouseEventArgs e) { base.OnPreviewMouseMove(e); if (_isMouseDown) { Point mpos = e.GetPosition(null); Vector diff = this._dragOutStartPoint - mpos; if (e.LeftButton == MouseButtonState.Pressed && Math.Abs(diff.X) > SystemParameters.MinimumHorizontalDragDistance || Math.Abs(diff.Y) > SystemParameters.MinimumVerticalDragDistance) { if (SelectedItems.Count == 0) { return; } SelectedItems.Clear(); foreach (var item in _selectedItemsBeforeDrag) { SelectedItems.Add(item); } List> dropItems = new List>(); foreach (var item in SelectedItems) { var tempFile = TemporaryManager.Default.CreateFile(".remote"); dropItems.Add(new Tuple(item, tempFile)); } List notifyItems = new List(); List watchers = new List(); FileSystemEventHandler handler = (x, args) => { var detectedDropItem = dropItems.SingleOrDefault(y => y.Item2.FileName == System.IO.Path.GetFileName(args.FullPath)); Debug.WriteLine($"File Created: {args.FullPath}"); if (detectedDropItem != null) { try { detectedDropItem.Item2.Delete(); //Delete temp file. if (File.Exists(args.FullPath)) { File.Delete(args.FullPath); //Delete dropped fake file. dropItems.Remove(detectedDropItem); notifyItems.Add(new DragItem() { FileSystemItem = detectedDropItem.Item1, Destination = System.IO.Path.GetDirectoryName(args.FullPath), }); if (dropItems.Count == 0) { foreach (var watcher in watchers) { watcher.Dispose(); } //Notify to user with all items! Dispatcher.BeginInvoke(new Action(() => { DragCommand?.Execute(notifyItems); })); } } } catch { } } else { Debug.WriteLine($"Not Found: {args.FullPath}"); } }; foreach (var drive in DriveInfo.GetDrives().Where(x => x.IsReady && (x.DriveType == DriveType.Fixed || x.DriveType == DriveType.Removable))) { FileSystemWatcher watcher = new FileSystemWatcher(drive.RootDirectory.FullName, "*.remote"); watcher.IncludeSubdirectories = true; watcher.EnableRaisingEvents = true; watcher.Created += handler; watchers.Add(watcher); } string[] files = dropItems.Select(x => x.Item2.Path).ToArray(); var ef = DragDrop.DoDragDrop(this, new DataObject(DataFormats.FileDrop, files, false), DragDropEffects.Copy); await Task.Delay(3000); foreach (var watcher in watchers) { watcher.Dispose(); } if (dropItems.Count > 0) { //Notify about problem! } _isMouseDown = false; AllowDrop = true; } } } } }