diff --git a/App.config b/App.config
new file mode 100644
index 0000000..adfec6e
--- /dev/null
+++ b/App.config
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/App.xaml b/App.xaml
new file mode 100644
index 0000000..53e826a
--- /dev/null
+++ b/App.xaml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/App.xaml.cs b/App.xaml.cs
new file mode 100644
index 0000000..26596fe
--- /dev/null
+++ b/App.xaml.cs
@@ -0,0 +1,17 @@
+using System;
+using System.Collections.Generic;
+using System.Configuration;
+using System.Data;
+using System.Linq;
+using System.Threading.Tasks;
+using System.Windows;
+
+namespace GeekDesk
+{
+ ///
+ /// App.xaml 的交互逻辑
+ ///
+ public partial class App : Application
+ {
+ }
+}
diff --git a/Command/DelegateCommand.cs b/Command/DelegateCommand.cs
new file mode 100644
index 0000000..be531b4
--- /dev/null
+++ b/Command/DelegateCommand.cs
@@ -0,0 +1,127 @@
+// Developed by doiTTeam => devdoiTTeam@gmail.com
+using System;
+using System.Windows.Input;
+
+namespace DraggAnimatedPanelExample
+{
+ ///
+ /// An whose delegates can be attached for and .
+ /// It also implements the interface, which is useful when registering this command in a that monitors command's activity.
+ ///
+ /// Parameter type.
+ ///
+ /// The constructor deliberately prevent the use of value types.
+ /// Because ICommand takes an object, having a value type for T would cause unexpected behavior when CanExecute(null) is called during XAML initialization for command bindings.
+ /// Using default(T) was considered and rejected as a solution because the implementor would not be able to distinguish between a valid and defaulted values.
+ ///
+ /// Instead, callers should support a value type by using a nullable value type and checking the HasValue property before using the Value property.
+ ///
+ ///
+ /// public MyClass()
+ /// {
+ /// this.submitCommand = new DelegateCommand<int?>(this.Submit, this.CanSubmit);
+ /// }
+ ///
+ /// private bool CanSubmit(int? customerId)
+ /// {
+ /// return (customerId.HasValue && customers.Contains(customerId.Value));
+ /// }
+ ///
+ ///
+ ///
+ public class DelegateCommand : DelegateCommandBase
+ {
+ ///
+ /// Initializes a new instance of .
+ ///
+ /// Delegate to execute when Execute is called on the command. This can be null to just hook up a CanExecute delegate.
+ ///
+ /// will always return true.
+ ///
+ public DelegateCommand(Action executeMethod)
+ : this(executeMethod, (o) => true)
+ {
+ }
+
+ ///
+ /// Initializes a new instance of .
+ ///
+ /// Delegate to execute when Execute is called on the command. This can be null to just hook up a CanExecute delegate.
+ /// Delegate to execute when CanExecute is called on the command. This can be null.
+ /// When both and ar .
+ public DelegateCommand(Action executeMethod, Func canExecuteMethod)
+ : base((o) => executeMethod((T) o), (o) => canExecuteMethod((T) o))
+ {
+ if (executeMethod == null || canExecuteMethod == null)
+ throw new ArgumentNullException("executeMethod");
+ }
+
+ ///
+ /// Determines if the command can execute by invoked the provided during construction.
+ ///
+ /// Data used by the command to determine if it can execute.
+ ///
+ /// if this command can be executed; otherwise, .
+ ///
+ public bool CanExecute(T parameter)
+ {
+ return base.CanExecute(parameter);
+ }
+
+ ///
+ /// Executes the command and invokes the provided during construction.
+ ///
+ /// Data used by the command.
+ public void Execute(T parameter)
+ {
+ base.Execute(parameter);
+ }
+ }
+
+ ///
+ /// An whose delegates do not take any parameters for and .
+ ///
+ ///
+ ///
+ public class DelegateCommand : DelegateCommandBase
+ {
+ ///
+ /// Creates a new instance of with the to invoke on execution.
+ ///
+ /// The to invoke when is called.
+ public DelegateCommand(Action executeMethod) : this(executeMethod, () => true)
+ {
+ }
+
+ ///
+ /// Creates a new instance of with the to invoke on execution
+ /// and a to query for determining if the command can execute.
+ ///
+ /// The to invoke when is called.
+ /// The to invoke when is called
+ public DelegateCommand(Action executeMethod, Func canExecuteMethod)
+ : base((o) => executeMethod(), (o) => canExecuteMethod())
+ {
+ if (executeMethod == null || canExecuteMethod == null)
+ throw new ArgumentNullException("executeMethod");
+ }
+
+
+ ///
+ /// Executes the command.
+ ///
+ public void Execute()
+ {
+ Execute(null);
+ }
+
+ ///
+ /// Determines if the command can be executed.
+ ///
+ /// Returns if the command can execute,otherwise returns .
+ public bool CanExecute()
+ {
+ return CanExecute(null);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Command/DelegateCommandBase.cs b/Command/DelegateCommandBase.cs
new file mode 100644
index 0000000..29a721f
--- /dev/null
+++ b/Command/DelegateCommandBase.cs
@@ -0,0 +1,95 @@
+// Developed by doiTTeam => devdoiTTeam@gmail.com
+using System;
+using System.Diagnostics.CodeAnalysis;
+using System.Windows.Input;
+
+namespace DraggAnimatedPanelExample
+{
+ ///
+ /// An whose delegates can be attached for and .
+ ///
+ public abstract class DelegateCommandBase : ICommand
+ {
+ private readonly Func canExecuteMethod;
+ private readonly Action executeMethod;
+
+ ///
+ /// Createse a new instance of a , specifying both the execute action and the can execute function.
+ ///
+ /// The to execute when is invoked.
+ /// The to invoked when is invoked.
+ protected DelegateCommandBase(Action executeMethod, Func canExecuteMethod)
+ {
+ if (executeMethod == null || canExecuteMethod == null)
+ throw new ArgumentNullException("executeMethod");
+
+ this.executeMethod = executeMethod;
+ this.canExecuteMethod = canExecuteMethod;
+ }
+
+ #region ICommand Members
+
+ void ICommand.Execute(object parameter)
+ {
+ Execute(parameter);
+ }
+
+ bool ICommand.CanExecute(object parameter)
+ {
+ return CanExecute(parameter);
+ }
+
+ ///
+ /// Occurs when changes occur that affect whether or not the command should execute.
+ ///
+ public event EventHandler CanExecuteChanged;
+
+ #endregion
+
+ ///
+ /// Raises on the UI thread so every
+ /// command invoker can requery to check if the
+ /// can execute.
+ ///
+ protected virtual void OnCanExecuteChanged()
+ {
+ var handlers = CanExecuteChanged;
+ if (handlers != null)
+ {
+ handlers(this, EventArgs.Empty);
+ }
+ }
+
+ ///
+ /// Raises on the UI thread so every command invoker
+ /// can requery to check if the command can execute.
+ ///
+ /// Note that this will trigger the execution of once for each invoker.
+ ///
+ ///
+ [SuppressMessage("Microsoft.Design", "CA1030:UseEventsWhereAppropriate")]
+ public void RaiseCanExecuteChanged()
+ {
+ OnCanExecuteChanged();
+ }
+
+ ///
+ /// Executes the command with the provided parameter by invoking the supplied during construction.
+ ///
+ ///
+ protected void Execute(object parameter)
+ {
+ executeMethod(parameter);
+ }
+
+ ///
+ /// Determines if the command can execute with the provided parameter by invoing the supplied during construction.
+ ///
+ /// The parameter to use when determining if this command can execute.
+ /// Returns if the command can execute. otherwise.
+ protected bool CanExecute(object parameter)
+ {
+ return canExecuteMethod == null || canExecuteMethod(parameter);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Constant/DefaultConstant.cs b/Constant/DefaultConstant.cs
new file mode 100644
index 0000000..a706f9b
--- /dev/null
+++ b/Constant/DefaultConstant.cs
@@ -0,0 +1,18 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+///
+/// 默认参数
+///
+namespace GeekDesk.Constant
+{
+ enum DefaultConstant
+ {
+ WINDOW_WIDTH = 650, //默认窗体宽度
+ WINDOW_HEIGHT = 700, //默认窗体高度
+ MENU_CARD_WIDHT = 150 //默认菜单栏宽度
+ }
+}
diff --git a/Constant/SortType.cs b/Constant/SortType.cs
new file mode 100644
index 0000000..b2238e7
--- /dev/null
+++ b/Constant/SortType.cs
@@ -0,0 +1,15 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace GeekDesk.Constant
+{
+ enum SortType
+ {
+ CUSTOM = 1, //自定义排序
+ NAME = 2, //按名称排序
+ COUNT = 3 //按使用次数排序
+ }
+}
diff --git a/DraggAnimatedPanel/DraggAnimatedPanel.Drag.cs b/DraggAnimatedPanel/DraggAnimatedPanel.Drag.cs
new file mode 100644
index 0000000..72877b9
--- /dev/null
+++ b/DraggAnimatedPanel/DraggAnimatedPanel.Drag.cs
@@ -0,0 +1,205 @@
+/*Developed by (doiTTeam)=>doiTTeam.mail = devdoiTTeam@gmail.com*/
+using System;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Animation;
+using System.Windows.Navigation;
+
+namespace DraggAnimatedPanel
+{
+ ///
+ /// Description of SafariPanel_Drag.
+ ///
+ public partial class DraggAnimatedPanel
+ {
+ #region const drag
+ const double mouseDif = 2d;
+ const int mouseTimeDif = 25;
+ #endregion
+
+ #region private
+ UIElement __draggedElement;
+
+ public UIElement _draggedElement {
+ get { return __draggedElement; }
+ set
+ {
+ __draggedElement = value;
+ }
+ }
+ int _draggedIndex;
+
+ bool _firstScrollRequest = true;
+ ScrollViewer _scrollContainer;
+ ScrollViewer scrollViewer
+ {
+ get
+ {
+ if (_firstScrollRequest && _scrollContainer == null)
+ {
+ _firstScrollRequest = false;
+ _scrollContainer = (ScrollViewer)GetParent(this as DependencyObject, (ve)=>ve is ScrollViewer);
+ }
+ return _scrollContainer;
+ }
+ }
+ #endregion
+
+ #region private drag
+ double _lastMousePosX;
+ double _lastMousePosY;
+ int _lastMouseMoveTime;
+ double _x;
+ double _y;
+ Rect _rectOnDrag;
+ #endregion
+
+
+ void OnMouseMove(object sender,MouseEventArgs e)
+ {
+ if (e.LeftButton == MouseButtonState.Pressed && _draggedElement == null && !this.IsMouseCaptured)
+ StartDrag(e);
+ else if (_draggedElement != null)
+ OnDragOver(e);
+ }
+
+ void OnDragOver(MouseEventArgs e)
+ {
+ Point mousePos = Mouse.GetPosition(this);
+ double difX = mousePos.X - _lastMousePosX;
+ double difY = mousePos.Y - _lastMousePosY;
+
+ int timeDif = e.Timestamp - _lastMouseMoveTime;
+ if ((Math.Abs(difX) > mouseDif || Math.Abs(difY) > mouseDif) && timeDif > mouseTimeDif)
+ {
+ //this lines is for keepn draged item inside control bounds
+ DoScroll();
+
+ if (_x + difX < _rectOnDrag.Location.X)
+ _x = 0;
+ else if (ItemsWidth + _x + difX > _rectOnDrag.Location.X + _rectOnDrag.Width)
+ _x = _rectOnDrag.Location.X + _rectOnDrag.Width - ItemsWidth;
+ else if (mousePos.X > _rectOnDrag.Location.X && mousePos.X < _rectOnDrag.Location.X + _rectOnDrag.Width)
+ _x += difX;
+ if (_y + difY < _rectOnDrag.Location.Y)
+ _y = 0;
+ else if (ItemsHeight + _y + difY > _rectOnDrag.Location.Y + _rectOnDrag.Height)
+ _y = _rectOnDrag.Location.Y + _rectOnDrag.Height - ItemsHeight;
+ else if (mousePos.Y > _rectOnDrag.Location.Y && mousePos.Y < _rectOnDrag.Location.Y + _rectOnDrag.Height)
+ _y += difY;
+ //lines ends
+
+ AnimateTo(_draggedElement,_x,_y, 0);
+ _lastMousePosX = mousePos.X;
+ _lastMousePosY = mousePos.Y;
+ _lastMouseMoveTime = e.Timestamp;
+ SwapElement(_x + ItemsWidth/2 , _y + ItemsHeight/2);
+ }
+ }
+
+ void StartDrag(MouseEventArgs e)
+ {
+ Point mousePos = Mouse.GetPosition(this);
+ _draggedElement = GetChildThatHasMouseOver();
+ if (_draggedElement == null)
+ return;
+ _draggedIndex = Children.IndexOf(_draggedElement);
+ _rectOnDrag = VisualTreeHelper.GetDescendantBounds(this);
+ Point p = GetItemVisualPoint(_draggedElement);
+ _x = p.X;
+ _y = p.Y;
+ SetZIndex(_draggedElement,1000);
+ _lastMousePosX = mousePos.X;
+ _lastMousePosY = mousePos.Y;
+ _lastMouseMoveTime = e.Timestamp;
+ this.InvalidateArrange();
+ e.Handled = true;
+ this.CaptureMouse();
+ }
+
+ void OnMouseUp(object sender,MouseEventArgs e)
+ {
+ if (this.IsMouseCaptured)
+ ReleaseMouseCapture();
+ }
+
+ void SwapElement(double x, double y)
+ {
+ int index = GetIndexFromPoint(x,y);
+ if (index == _draggedIndex || index < 0)
+ return;
+ if (index >= Children.Count)
+ index = Children.Count - 1;
+
+ int[] parameter = new int[]{_draggedIndex, index};
+ if (SwapCommand != null && SwapCommand.CanExecute(parameter))
+ {
+ SwapCommand.Execute(parameter);
+ _draggedElement = Children[index]; //this is bcause after changing the collection the element is other
+ FillNewDraggedChild(_draggedElement);
+ _draggedIndex = index;
+ }
+
+ this.InvalidateArrange();
+ }
+
+ void FillNewDraggedChild(UIElement child)
+ {
+ if (child.RenderTransform as TransformGroup == null)
+ {
+ child.RenderTransformOrigin = new Point(0.5, 0.5);
+ TransformGroup group = new TransformGroup();
+ child.RenderTransform = group;
+ group.Children.Add(new TranslateTransform());
+ }
+ SetZIndex(child,1000);
+ AnimateTo(child,_x,_y, 0); //need relocate the element
+ }
+
+ void OnLostMouseCapture(object sender,MouseEventArgs e)
+ {
+ FinishDrag();
+ }
+
+ void FinishDrag()
+ {
+ if (_draggedElement != null)
+ {
+ SetZIndex(_draggedElement,0);
+ _draggedElement = null;
+ this.InvalidateArrange();
+ }
+ }
+
+ void DoScroll()
+ {
+ if (scrollViewer != null)
+ {
+ Point position = Mouse.GetPosition(scrollViewer);
+ double scrollMargin = Math.Min(scrollViewer.FontSize * 2, scrollViewer.ActualHeight / 2);
+
+ if (position.X >= scrollViewer.ActualWidth - scrollMargin &&
+ scrollViewer.HorizontalOffset < scrollViewer.ExtentWidth - scrollViewer.ViewportWidth)
+ {
+ scrollViewer.LineRight();
+ }
+ else if (position.X < scrollMargin && scrollViewer.HorizontalOffset > 0)
+ {
+ scrollViewer.LineLeft();
+ }
+ else if (position.Y >= scrollViewer.ActualHeight - scrollMargin &&
+ scrollViewer.VerticalOffset < scrollViewer.ExtentHeight - scrollViewer.ViewportHeight)
+ {
+ scrollViewer.LineDown();
+ }
+ else if (position.Y < scrollMargin && scrollViewer.VerticalOffset > 0)
+ {
+ scrollViewer.LineUp();
+ }
+ }
+ }
+ }
+}
diff --git a/DraggAnimatedPanel/DraggAnimatedPanel.cs b/DraggAnimatedPanel/DraggAnimatedPanel.cs
new file mode 100644
index 0000000..81bd82d
--- /dev/null
+++ b/DraggAnimatedPanel/DraggAnimatedPanel.cs
@@ -0,0 +1,237 @@
+/*Developed by (doiTTeam)=>doiTTeam.mail = devdoiTTeam@gmail.com*/
+using System;
+using System.Linq;
+using System.Runtime.CompilerServices;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Animation;
+using System.Windows.Navigation;
+
+namespace DraggAnimatedPanel
+{
+ ///
+ /// Description of DraggAnimatedPanel.
+ ///
+ public partial class DraggAnimatedPanel : WrapPanel
+ {
+ #region private vars
+ Size _calculatedSize;
+ bool _isNotFirstArrange = false;
+ int columns, rows;
+ #endregion
+ static DraggAnimatedPanel()
+ {
+ DefaultStyleKeyProperty.OverrideMetadata(typeof(DraggAnimatedPanel), new FrameworkPropertyMetadata(typeof(DraggAnimatedPanel)));
+ }
+
+ public DraggAnimatedPanel() : base()
+ {
+ this.AddHandler(Mouse.MouseMoveEvent, new MouseEventHandler(OnMouseMove), false);
+ this.MouseLeftButtonUp += OnMouseUp;
+ this.LostMouseCapture += OnLostMouseCapture;
+ }
+
+ UIElement GetChildThatHasMouseOver()
+ {
+ return GetParent(Mouse.DirectlyOver as DependencyObject, (ve) => Children.Contains(ve as UIElement)) as UIElement;
+ }
+
+ Point GetItemVisualPoint(UIElement element)
+ {
+ TransformGroup group = (TransformGroup)element.RenderTransform;
+ TranslateTransform trans = (TranslateTransform)group.Children[0];
+
+ return new Point(trans.X, trans.Y);
+ }
+
+ int GetIndexFromPoint(double x, double y)
+ {
+ int columnIndex = (int)Math.Truncate(x / itemContainterWidth);
+ int rowIndex = (int)Math.Truncate(y / itemContainterHeight);
+ return columns * rowIndex + columnIndex;
+ }
+ int GetIndexFromPoint(Point p)
+ {
+ return GetIndexFromPoint(p.X, p.Y);
+ }
+
+ #region dependency properties
+ public static readonly DependencyProperty ItemsWidthProperty =
+ DependencyProperty.Register(
+ "ItemsWidth",
+ typeof(double),
+ typeof(DraggAnimatedPanel),
+ new FrameworkPropertyMetadata(150d));
+
+ public static readonly DependencyProperty ItemsHeightProperty =
+ DependencyProperty.Register(
+ "ItemsHeight",
+ typeof(double),
+ typeof(DraggAnimatedPanel),
+ new FrameworkPropertyMetadata(60d));
+
+ public static readonly DependencyProperty ItemSeparationProperty =
+ DependencyProperty.Register(
+ "ItemSeparation",
+ typeof(Thickness),
+ typeof(DraggAnimatedPanel),
+ new FrameworkPropertyMetadata());
+
+ // Using a DependencyProperty as the backing store for AnimationMilliseconds. This enables animation, styling, binding, etc...
+ public static readonly DependencyProperty AnimationMillisecondsProperty =
+ DependencyProperty.Register("AnimationMilliseconds", typeof(int), typeof(DraggAnimatedPanel), new FrameworkPropertyMetadata(200));
+
+ public static readonly DependencyProperty SwapCommandProperty =
+ DependencyProperty.Register(
+ "SwapCommand",
+ typeof(ICommand),
+ typeof(DraggAnimatedPanel),
+ new FrameworkPropertyMetadata(null));
+
+ #endregion
+
+ #region properties
+ public double ItemsWidth
+ {
+ get { return (double)GetValue(ItemsWidthProperty); }
+ set { SetValue(ItemsWidthProperty, value); }
+ }
+ public double ItemsHeight
+ {
+ get { return (double)GetValue(ItemsHeightProperty); }
+ set { SetValue(ItemsHeightProperty, value); }
+ }
+ public Thickness ItemSeparation
+ {
+ get { return (Thickness)this.GetValue(ItemSeparationProperty); }
+ set { this.SetValue(ItemSeparationProperty, value); }
+ }
+ public int AnimationMilliseconds
+ {
+ get { return (int)GetValue(AnimationMillisecondsProperty); }
+ set { SetValue(AnimationMillisecondsProperty, value); }
+ }
+ private double itemContainterHeight
+ {
+ get { return ItemSeparation.Top + ItemsHeight + ItemSeparation.Bottom; }
+ }
+ private double itemContainterWidth
+ {
+ get { return ItemSeparation.Left + ItemsWidth + ItemSeparation.Right; }
+ }
+ public ICommand SwapCommand
+ {
+ get { return (ICommand)GetValue(SwapCommandProperty); }
+ set { SetValue(SwapCommandProperty, value); }
+ }
+ #endregion
+
+ #region transformation things
+ private void AnimateAll()
+ {
+ //Apply exactly the same algorithm, but instide of Arrange a call AnimateTo method
+ double colPosition = 0;
+ double rowPosition = 0;
+ foreach (UIElement child in Children)
+ {
+ if (child != _draggedElement)
+ AnimateTo(child, colPosition + ItemSeparation.Left, rowPosition + ItemSeparation.Top, _isNotFirstArrange ? AnimationMilliseconds : 0);
+ //drag will locate dragged element
+ colPosition += itemContainterWidth;
+ if (colPosition + 1 > _calculatedSize.Width)
+ {
+ colPosition = 0;
+ rowPosition += itemContainterHeight;
+ }
+ }
+ }
+
+ private void AnimateTo(UIElement child, double x, double y, int duration)
+ {
+ TransformGroup group = (TransformGroup)child.RenderTransform;
+ TranslateTransform trans = (TranslateTransform)group.Children.First((groupElement) => groupElement is TranslateTransform);
+
+ trans.BeginAnimation(TranslateTransform.XProperty, MakeAnimation(x, duration));
+ trans.BeginAnimation(TranslateTransform.YProperty, MakeAnimation(y, duration));
+ }
+
+ private DoubleAnimation MakeAnimation(double to, int duration)
+ {
+ DoubleAnimation anim = new DoubleAnimation(to, TimeSpan.FromMilliseconds(duration));
+ anim.AccelerationRatio = 0.2;
+ anim.DecelerationRatio = 0.7;
+ return anim;
+ }
+ #endregion
+
+ #region measure
+ protected override Size MeasureOverride(Size availableSize)
+ {
+ Size itemContainerSize = new Size(itemContainterWidth, itemContainterHeight);
+ int count = 0; //for not call it again
+ foreach (UIElement child in Children)
+ {
+ child.Measure(itemContainerSize);
+ count++;
+ }
+ if (availableSize.Width < itemContainterWidth)
+ _calculatedSize = new Size(itemContainterWidth, count * itemContainterHeight); //the size of nX1
+ else
+ {
+ columns = (int)Math.Truncate(availableSize.Width / itemContainterWidth);
+ rows = count / columns;
+ if (count % columns != 0)
+ rows++;
+ _calculatedSize = new Size(columns * itemContainterWidth, rows * itemContainterHeight);
+ }
+ return _calculatedSize;
+ }
+ #endregion
+
+ #region arrange
+ protected override Size ArrangeOverride(Size finalSize)
+ {
+ Size _finalItemSize = new Size(ItemsWidth, ItemsHeight);
+ //if is animated then arrange elements to 0,0, and then put them on its location using the transform
+ foreach (UIElement child in InternalChildren)
+ {
+ // If this is the first time we've seen this child, add our transforms
+ if (child.RenderTransform as TransformGroup == null)
+ {
+ child.RenderTransformOrigin = new Point(0.5, 0.5);
+ TransformGroup group = new TransformGroup();
+ child.RenderTransform = group;
+ group.Children.Add(new TranslateTransform());
+ }
+ //locate all children in 0,0 point//TODO: use infinity and then scale each element to items size
+ child.Arrange(new Rect(new Point(0, 0), _finalItemSize)); //when use transformations change to childs.DesireSize
+ }
+ AnimateAll();
+
+ if (!_isNotFirstArrange)
+ _isNotFirstArrange = true;
+
+ return _calculatedSize;
+ }
+ #endregion
+
+ #region Static
+ //this can be an extension method
+ public static DependencyObject GetParent(DependencyObject o, Func matchFunction)
+ {
+ DependencyObject t = o;
+ do
+ {
+ t = VisualTreeHelper.GetParent(t);
+ } while (t != null && !matchFunction.Invoke(t));
+ return t;
+ }
+ #endregion
+
+ //TODO: Add IsEditing property
+ //TODO: Add Scale transform to items for fill items area
+ }
+}
diff --git a/GeekDesk.csproj b/GeekDesk.csproj
new file mode 100644
index 0000000..70cf898
--- /dev/null
+++ b/GeekDesk.csproj
@@ -0,0 +1,146 @@
+
+
+
+
+ Debug
+ AnyCPU
+ {B4983CEC-2281-413C-8ECF-92EE0E40A713}
+ WinExe
+ GeekDesk
+ GeekDesk
+ v4.7.2
+ 512
+ {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
+ 4
+ true
+ true
+
+
+
+ AnyCPU
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+ true
+
+
+ AnyCPU
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+ true
+
+
+
+ packages\CommonServiceLocator.2.0.6\lib\net45\CommonServiceLocator.dll
+
+
+ packages\MvvmLightLibs.5.4.1.1\lib\net45\GalaSoft.MvvmLight.dll
+
+
+ packages\MvvmLightLibs.5.4.1.1\lib\net45\GalaSoft.MvvmLight.Extras.dll
+
+
+ packages\MvvmLightLibs.5.4.1.1\lib\net45\GalaSoft.MvvmLight.Platform.dll
+
+
+ packages\HandyControl.3.1.0\lib\net452\HandyControl.dll
+
+
+ packages\Newtonsoft.Json.13.0.1\lib\net45\Newtonsoft.Json.dll
+
+
+
+
+
+ packages\System.Drawing.Common.5.0.2\lib\net461\System.Drawing.Common.dll
+
+
+ packages\MvvmLightLibs.5.4.1.1\lib\net45\System.Windows.Interactivity.dll
+
+
+
+
+
+
+
+
+ 4.0
+
+
+
+
+
+
+
+ MSBuild:Compile
+ Designer
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ MSBuild:Compile
+ Designer
+
+
+ App.xaml
+ Code
+
+
+ MainWindow.xaml
+ Code
+
+
+
+
+ Code
+
+
+ True
+ True
+ Resources.resx
+
+
+ True
+ Settings.settings
+ True
+
+
+ ResXFileCodeGenerator
+ Resources.Designer.cs
+
+
+
+ SettingsSingleFileGenerator
+ Settings.Designer.cs
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/GeekDesk.sln b/GeekDesk.sln
new file mode 100644
index 0000000..a05cf6d
--- /dev/null
+++ b/GeekDesk.sln
@@ -0,0 +1,25 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Blend for Visual Studio Version 16
+VisualStudioVersion = 16.0.30907.101
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GeekDesk", "GeekDesk.csproj", "{B4983CEC-2281-413C-8ECF-92EE0E40A713}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {B4983CEC-2281-413C-8ECF-92EE0E40A713}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {B4983CEC-2281-413C-8ECF-92EE0E40A713}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {B4983CEC-2281-413C-8ECF-92EE0E40A713}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {B4983CEC-2281-413C-8ECF-92EE0E40A713}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {7D844F27-975B-4CFF-A373-E665FB8866DE}
+ EndGlobalSection
+EndGlobal
diff --git a/MainWindow.xaml b/MainWindow.xaml
new file mode 100644
index 0000000..cae0118
--- /dev/null
+++ b/MainWindow.xaml
@@ -0,0 +1,219 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Text
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/MainWindow.xaml.cs b/MainWindow.xaml.cs
new file mode 100644
index 0000000..2c3296d
--- /dev/null
+++ b/MainWindow.xaml.cs
@@ -0,0 +1,324 @@
+using System;
+using System.Collections.Generic;
+
+using System.Windows;
+
+using System.Windows.Input;
+using System.Windows.Media.Imaging;
+
+using GeekDesk.ViewModel;
+using System.IO;
+using GeekDesk.Util;
+using GalaSoft.MvvmLight;
+using System.Windows.Controls;
+using System.Windows.Media;
+using System.Collections.ObjectModel;
+using WPF.JoshSmith.ServiceProviders.UI;
+using DraggAnimatedPanelExample;
+using System.ComponentModel;
+
+namespace GeekDesk
+{
+ ///
+ /// MainWindow.xaml 的交互逻辑
+ ///
+ ///
+ public partial class MainWindow : Window
+ {
+ private static MainModel mainModel;
+
+ ListViewDragDropManager dragMgr;
+ ListViewDragDropManager dragMgr2;
+ public MainWindow()
+ {
+ InitializeComponent();
+
+ mainModel = new MainModel();
+ //this.DataContext = mainModel;
+ //menu.Items = mainModel;
+ //System.Diagnostics.Process.Start(@"D:\SoftWare\WeGame\wegame.exe");
+ this.Loaded += Window_Loaded;
+ this.SizeChanged += MainWindow_Resize;
+ }
+
+ DelegateCommand _swap;
+ public DelegateCommand SwapCommand
+ {
+ get
+ {
+ if (_swap == null)
+ _swap = new DelegateCommand(
+ (indexes) =>
+ {
+ int fromS = indexes[0];
+ int to = indexes[1];
+ var elementSource = data.Items[to];
+ var dragged = data.Items[fromS];
+ if (fromS > to)
+ {
+ data.Items.Remove(dragged);
+ data.Items.Insert(to, dragged);
+ }
+ else
+ {
+ data.Items.Remove(dragged);
+ data.Items.Insert(to, dragged);
+ }
+ }
+ );
+ return _swap;
+ }
+ }
+ DelegateCommand _swap2;
+ public DelegateCommand SwapCommand2
+ {
+ get
+ {
+ if (_swap2 == null)
+ _swap2 = new DelegateCommand(
+ (indexes) =>
+ {
+ int fromS = indexes[0];
+ int to = indexes[1];
+ var elementSource = menu.Items[to];
+ var dragged = menu.Items[fromS];
+ if (fromS > to)
+ {
+ menu.Items.Remove(dragged);
+ menu.Items.Insert(to, dragged);
+ }
+ else
+ {
+ menu.Items.Remove(dragged);
+ menu.Items.Insert(to, dragged);
+ }
+ }
+ );
+ return _swap2;
+ }
+ }
+
+
+
+ private void Wrap_Drop(object sender, DragEventArgs e)
+ {
+ Array dropObject = (System.Array)e.Data.GetData(DataFormats.FileDrop);
+ if (dropObject == null) return;
+ string path = (string)dropObject.GetValue(0);
+ if (File.Exists(path))
+ {
+ // 文件
+ BitmapImage bi = FileIcon.GetBitmapImage(path);
+ DataInfos infos = new DataInfos();
+ infos.Path = path;
+ infos.BitmapImage = bi;
+ infos.Name = Path.GetFileNameWithoutExtension(path);
+ data.Items.Add(infos);
+ data.Items.Refresh();
+ }
+ else if (Directory.Exists(path))
+ {
+ //文件夹
+
+ }
+
+ }
+
+ //菜单点击事件
+ private void menuClick(object sender, MouseButtonEventArgs e)
+ {
+
+ }
+
+
+
+ ///
+ /// 图标点击事件
+ ///
+ ///
+ ///
+ private void dataClick(object sender, MouseButtonEventArgs e)
+ {
+ //string path = ((StackPanel)sender).Tag.ToString();
+ //System.Diagnostics.Process.Start(path);
+ }
+
+ ///
+ /// data选中事件 设置不可选中
+ ///
+ ///
+ ///
+ private void data_SelectionChanged(object sender, SelectionChangedEventArgs e)
+ {
+ if (data.SelectedIndex != -1) data.SelectedIndex = -1;
+ }
+
+ #region Window_Loaded
+ void Window_Loaded(object sender, RoutedEventArgs e)
+ {
+ AppConfig config = CommonCode.GetAppConfig();
+ this.Width = config.WindowWidth;
+ this.Height = config.WindowHeight;
+ this.DataContext = config;
+
+ this.menu.Items.Add(new ViewModel.Menu() { menu = "test1" });
+ this.menu.Items.Add(new ViewModel.Menu() { menu = "test2" });
+ this.menu.Items.Add(new ViewModel.Menu() { menu = "test3" });
+ }
+ #endregion // Window_Loaded
+
+ #region Window_Closing
+ void Window_Closing(object sender, CancelEventArgs e)
+ {
+ Rect rect = this.RestoreBounds;
+ AppConfig config = this.DataContext as AppConfig;
+ config.WindowWidth = rect.Width;
+ config.WindowHeight = rect.Height;
+ CommonCode.SaveAppConfig(config);
+ }
+ #endregion // Window_Closing
+
+ void MainWindow_Resize(object sender, System.EventArgs e)
+ {
+ if (this.DataContext != null)
+ {
+ AppConfig config = this.DataContext as AppConfig;
+ config.WindowWidth = this.Width;
+ config.WindowHeight = this.Height;
+ CommonCode.SaveAppConfig(config);
+ }
+
+ }
+
+
+
+ #region dragMgr_ProcessDrop
+
+ // Performs custom drop logic for the top ListView.
+ void dragMgr_ProcessDrop(object sender, ProcessDropEventArgs e)
+ {
+ // This shows how to customize the behavior of a drop.
+ // Here we perform a swap, instead of just moving the dropped item.
+
+ int higherIdx = Math.Max(e.OldIndex, e.NewIndex);
+ int lowerIdx = Math.Min(e.OldIndex, e.NewIndex);
+
+ if (lowerIdx < 0)
+ {
+ // The item came from the lower ListView
+ // so just insert it.
+ e.ItemsSource.Insert(higherIdx, e.DataItem);
+ }
+ else
+ {
+ // null values will cause an error when calling Move.
+ // It looks like a bug in ObservableCollection to me.
+ if (e.ItemsSource[lowerIdx] == null ||
+ e.ItemsSource[higherIdx] == null)
+ return;
+
+ // The item came from the ListView into which
+ // it was dropped, so swap it with the item
+ // at the target index.
+ e.ItemsSource.Move(lowerIdx, higherIdx);
+ e.ItemsSource.Move(higherIdx - 1, lowerIdx);
+ }
+
+ // Set this to 'Move' so that the OnListViewDrop knows to
+ // remove the item from the other ListView.
+ e.Effects = DragDropEffects.Move;
+ }
+
+ #endregion // dragMgr_ProcessDrop
+
+ #region OnListViewDragEnter
+
+ // Handles the DragEnter event for both ListViews.
+ void OnListViewDragEnter(object sender, DragEventArgs e)
+ {
+ e.Effects = DragDropEffects.Move;
+ }
+
+ #endregion // OnListViewDragEnter
+
+ #region OnListViewDrop
+
+ // Handles the Drop event for both ListViews.
+ void OnListViewDrop(object sender, DragEventArgs e)
+ {
+ if (e.Effects == DragDropEffects.None)
+ return;
+ ViewModel.Menu menuV = e.Data.GetData(typeof(ViewModel.Menu)) as ViewModel.Menu;
+ DataInfos data = e.Data.GetData(typeof(DataInfos)) as DataInfos;
+
+ if (sender == this.menu)
+ {
+ if (this.dragMgr.IsDragInProgress)
+ return;
+
+ // An item was dragged from the bottom ListView into the top ListView
+ // so remove that item from the bottom ListView.
+ (this.data.ItemsSource as ObservableCollection).Remove(data);
+ }
+ else
+ {
+ if (this.dragMgr2.IsDragInProgress)
+ return;
+
+ // An item was dragged from the top ListView into the bottom ListView
+ // so remove that item from the top ListView.
+ (this.menu.ItemsSource as ObservableCollection).Remove(menuV);
+ }
+ }
+
+ #endregion // OnListViewDrop
+
+ private void leftCard_MouseRightButtonDown(object sender, MouseButtonEventArgs e)
+ {
+
+ }
+
+ private void deleteMenu(object sender, RoutedEventArgs e)
+ {
+ //if (data.SelectedIndex == -1)
+ //{
+ // return;
+ //}
+ ViewModel.Menu pojo = (ViewModel.Menu)((ContextMenu)((MenuItem)sender).Parent).DataContext;
+ string menuTitle = pojo.menu;
+ int index = 0;
+ foreach (object obj in menu.Items)
+ {
+ string test = ((ViewModel.Menu)obj).menu;
+ if (test == menuTitle)
+ {
+ menu.Items.RemoveAt(index);
+ menu.Items.Refresh();
+ return;
+ }
+ index++;
+ }
+
+ }
+
+ public Double ConvertString(string val)
+ {
+ return Convert.ToDouble(val);
+ }
+
+ }
+
+
+
+
+ public class MainModel : ViewModelBase
+ {
+ public List MenuList { get; set; }
+
+ public List DataList { get; set; }
+
+
+ }
+
+
+}
diff --git a/Properties/AssemblyInfo.cs b/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..c057420
--- /dev/null
+++ b/Properties/AssemblyInfo.cs
@@ -0,0 +1,55 @@
+using System.Reflection;
+using System.Resources;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Windows;
+
+// 有关程序集的一般信息由以下
+// 控制。更改这些特性值可修改
+// 与程序集关联的信息。
+[assembly: AssemblyTitle("GeekDesk")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("GeekDesk")]
+[assembly: AssemblyCopyright("Copyright © 2021")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// 将 ComVisible 设置为 false 会使此程序集中的类型
+//对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型
+//请将此类型的 ComVisible 特性设置为 true。
+[assembly: ComVisible(false)]
+
+//若要开始生成可本地化的应用程序,请设置
+//.csproj 文件中的 CultureYouAreCodingWith
+//例如,如果您在源文件中使用的是美国英语,
+//使用的是美国英语,请将 设置为 en-US。 然后取消
+//对以下 NeutralResourceLanguage 特性的注释。 更新
+//以下行中的“en-US”以匹配项目文件中的 UICulture 设置。
+
+//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
+
+
+[assembly: ThemeInfo(
+ ResourceDictionaryLocation.None, //主题特定资源词典所处位置
+ //(未在页面中找到资源时使用,
+ //或应用程序资源字典中找到时使用)
+ ResourceDictionaryLocation.SourceAssembly //常规资源词典所处位置
+ //(未在页面中找到资源时使用,
+ //、应用程序或任何主题专用资源字典中找到时使用)
+)]
+
+
+// 程序集的版本信息由下列四个值组成:
+//
+// 主版本
+// 次版本
+// 生成号
+// 修订号
+//
+//可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值
+//通过使用 "*",如下所示:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/Properties/Resources.Designer.cs b/Properties/Resources.Designer.cs
new file mode 100644
index 0000000..f906b01
--- /dev/null
+++ b/Properties/Resources.Designer.cs
@@ -0,0 +1,63 @@
+//------------------------------------------------------------------------------
+//
+// 此代码由工具生成。
+// 运行时版本:4.0.30319.42000
+//
+// 对此文件的更改可能会导致不正确的行为,并且如果
+// 重新生成代码,这些更改将会丢失。
+//
+//------------------------------------------------------------------------------
+
+namespace GeekDesk.Properties {
+ using System;
+
+
+ ///
+ /// 一个强类型的资源类,用于查找本地化的字符串等。
+ ///
+ // 此类是由 StronglyTypedResourceBuilder
+ // 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。
+ // 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen
+ // (以 /str 作为命令选项),或重新生成 VS 项目。
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ internal class Resources {
+
+ private static global::System.Resources.ResourceManager resourceMan;
+
+ private static global::System.Globalization.CultureInfo resourceCulture;
+
+ [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+ internal Resources() {
+ }
+
+ ///
+ /// 返回此类使用的缓存的 ResourceManager 实例。
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Resources.ResourceManager ResourceManager {
+ get {
+ if (object.ReferenceEquals(resourceMan, null)) {
+ global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("GeekDesk.Properties.Resources", typeof(Resources).Assembly);
+ resourceMan = temp;
+ }
+ return resourceMan;
+ }
+ }
+
+ ///
+ /// 重写当前线程的 CurrentUICulture 属性,对
+ /// 使用此强类型资源类的所有资源查找执行重写。
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Globalization.CultureInfo Culture {
+ get {
+ return resourceCulture;
+ }
+ set {
+ resourceCulture = value;
+ }
+ }
+ }
+}
diff --git a/Properties/Resources.resx b/Properties/Resources.resx
new file mode 100644
index 0000000..af7dbeb
--- /dev/null
+++ b/Properties/Resources.resx
@@ -0,0 +1,117 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
\ No newline at end of file
diff --git a/Properties/Settings.Designer.cs b/Properties/Settings.Designer.cs
new file mode 100644
index 0000000..0e3a3af
--- /dev/null
+++ b/Properties/Settings.Designer.cs
@@ -0,0 +1,26 @@
+//------------------------------------------------------------------------------
+//
+// 此代码由工具生成。
+// 运行时版本:4.0.30319.42000
+//
+// 对此文件的更改可能会导致不正确的行为,并且如果
+// 重新生成代码,这些更改将会丢失。
+//
+//------------------------------------------------------------------------------
+
+namespace GeekDesk.Properties {
+
+
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "16.8.1.0")]
+ internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
+
+ private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
+
+ public static Settings Default {
+ get {
+ return defaultInstance;
+ }
+ }
+ }
+}
diff --git a/Properties/Settings.settings b/Properties/Settings.settings
new file mode 100644
index 0000000..033d7a5
--- /dev/null
+++ b/Properties/Settings.settings
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Util/CommonCode.cs b/Util/CommonCode.cs
new file mode 100644
index 0000000..d6b900f
--- /dev/null
+++ b/Util/CommonCode.cs
@@ -0,0 +1,59 @@
+using Newtonsoft.Json;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Runtime.Serialization.Formatters.Binary;
+using System.Text;
+using System.Threading.Tasks;
+using GeekDesk.ViewModel;
+
+///
+/// 提取一些代码
+///
+namespace GeekDesk.Util
+{
+ class CommonCode
+ {
+ private static string appConfigFilePath = AppDomain.CurrentDomain.BaseDirectory.Trim() + "\\config";
+ ///
+ /// 获取app配置
+ ///
+ ///
+ public static AppConfig GetAppConfig()
+ {
+ AppConfig config;
+ if (!File.Exists(appConfigFilePath))
+ {
+ using (FileStream fs = File.Create(appConfigFilePath)) { }
+ config = new AppConfig();
+ SaveAppConfig(config);
+
+ }
+ else
+ {
+ using (FileStream fs = new FileStream(appConfigFilePath, FileMode.Open))
+ {
+ BinaryFormatter bf = new BinaryFormatter();
+ string json = bf.Deserialize(fs) as string;
+ config = JsonConvert.DeserializeObject(json);
+ }
+ }
+ return config;
+ }
+
+ ///
+ /// 保存app配置
+ ///
+ ///
+ public static void SaveAppConfig(AppConfig config)
+ {
+ using (FileStream fs = new FileStream(appConfigFilePath, FileMode.Create))
+ {
+ BinaryFormatter bf = new BinaryFormatter();
+ string json = JsonConvert.SerializeObject(config);
+ bf.Serialize(fs, json);
+ }
+ }
+ }
+}
diff --git a/Util/ConsoleManager.cs b/Util/ConsoleManager.cs
new file mode 100644
index 0000000..112968f
--- /dev/null
+++ b/Util/ConsoleManager.cs
@@ -0,0 +1,105 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Security;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace GeekDesk.Util
+{
+ [SuppressUnmanagedCodeSecurity]
+ public static class ConsoleManager
+ {
+ private const string Kernel32_DllName = "kernel32.dll";
+
+ [DllImport(Kernel32_DllName)]
+ private static extern bool AllocConsole();
+
+ [DllImport(Kernel32_DllName)]
+ private static extern bool FreeConsole();
+
+ [DllImport(Kernel32_DllName)]
+ private static extern IntPtr GetConsoleWindow();
+
+ [DllImport(Kernel32_DllName)]
+ private static extern int GetConsoleOutputCP();
+
+ public static bool HasConsole
+ {
+ get { return GetConsoleWindow() != IntPtr.Zero; }
+ }
+
+ ///
+ /// Creates a new console instance if the process is not attached to a console already.
+ ///
+ public static void Show()
+ {
+ //#if DEBUG
+ if (!HasConsole)
+ {
+ AllocConsole();
+ InvalidateOutAndError();
+ }
+ //#endif
+ }
+
+ ///
+ /// If the process has a console attached to it, it will be detached and no longer visible. Writing to the System.Console is still possible, but no output will be shown.
+ ///
+ public static void Hide()
+ {
+ //#if DEBUG
+ if (HasConsole)
+ {
+ SetOutAndErrorNull();
+ FreeConsole();
+ }
+ //#endif
+ }
+
+ public static void Toggle()
+ {
+ if (HasConsole)
+ {
+ Hide();
+ }
+ else
+ {
+ Show();
+ }
+ }
+
+ static void InvalidateOutAndError()
+ {
+ Type type = typeof(System.Console);
+
+ System.Reflection.FieldInfo _out = type.GetField("_out",
+ System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic);
+
+ System.Reflection.FieldInfo _error = type.GetField("_error",
+ System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic);
+
+ System.Reflection.MethodInfo _InitializeStdOutError = type.GetMethod("InitializeStdOutError",
+ System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic);
+
+ Debug.Assert(_out != null);
+ Debug.Assert(_error != null);
+
+ Debug.Assert(_InitializeStdOutError != null);
+
+ _out.SetValue(null, null);
+ _error.SetValue(null, null);
+
+ _InitializeStdOutError.Invoke(null, new object[] { true });
+ }
+
+ static void SetOutAndErrorNull()
+ {
+ Console.SetOut(TextWriter.Null);
+ Console.SetError(TextWriter.Null);
+ }
+ }
+}
diff --git a/Util/DragAdorner.cs b/Util/DragAdorner.cs
new file mode 100644
index 0000000..e7dc001
--- /dev/null
+++ b/Util/DragAdorner.cs
@@ -0,0 +1,175 @@
+// Copyright (C) Josh Smith - January 2007
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Windows.Documents;
+using System.Windows;
+using System.Windows.Media;
+using System.Windows.Shapes;
+using System.Windows.Media.Animation;
+using System.Windows.Controls;
+
+namespace WPF.JoshSmith.Adorners
+{
+ ///
+ /// Renders a visual which can follow the mouse cursor,
+ /// such as during a drag-and-drop operation.
+ ///
+ public class DragAdorner : Adorner
+ {
+ #region Data
+
+ private Rectangle child = null;
+ private double offsetLeft = 0;
+ private double offsetTop = 0;
+
+ #endregion // Data
+
+ #region Constructor
+
+ ///
+ /// Initializes a new instance of DragVisualAdorner.
+ ///
+ /// The element being adorned.
+ /// The size of the adorner.
+ /// A brush to with which to paint the adorner.
+ public DragAdorner( UIElement adornedElement, Size size, Brush brush )
+ : base( adornedElement )
+ {
+ Rectangle rect = new Rectangle();
+ rect.Fill = brush;
+ rect.Width = size.Width;
+ rect.Height = size.Height;
+ rect.IsHitTestVisible = false;
+ this.child = rect;
+ }
+
+ #endregion // Constructor
+
+ #region Public Interface
+
+ #region GetDesiredTransform
+
+ ///
+ /// Override.
+ ///
+ ///
+ ///
+ public override GeneralTransform GetDesiredTransform( GeneralTransform transform )
+ {
+ GeneralTransformGroup result = new GeneralTransformGroup();
+ result.Children.Add( base.GetDesiredTransform( transform ) );
+ result.Children.Add( new TranslateTransform( this.offsetLeft, this.offsetTop ) );
+ return result;
+ }
+
+ #endregion // GetDesiredTransform
+
+ #region OffsetLeft
+
+ ///
+ /// Gets/sets the horizontal offset of the adorner.
+ ///
+ public double OffsetLeft
+ {
+ get { return this.offsetLeft; }
+ set
+ {
+ this.offsetLeft = value;
+ UpdateLocation();
+ }
+ }
+
+ #endregion // OffsetLeft
+
+ #region SetOffsets
+
+ ///
+ /// Updates the location of the adorner in one atomic operation.
+ ///
+ ///
+ ///
+ public void SetOffsets( double left, double top )
+ {
+ this.offsetLeft = left;
+ this.offsetTop = top;
+ this.UpdateLocation();
+ }
+
+ #endregion // SetOffsets
+
+ #region OffsetTop
+
+ ///
+ /// Gets/sets the vertical offset of the adorner.
+ ///
+ public double OffsetTop
+ {
+ get { return this.offsetTop; }
+ set
+ {
+ this.offsetTop = value;
+ UpdateLocation();
+ }
+ }
+
+ #endregion // OffsetTop
+
+ #endregion // Public Interface
+
+ #region Protected Overrides
+
+ ///
+ /// Override.
+ ///
+ ///
+ ///
+ protected override Size MeasureOverride( Size constraint )
+ {
+ this.child.Measure( constraint );
+ return this.child.DesiredSize;
+ }
+
+ ///
+ /// Override.
+ ///
+ ///
+ ///
+ protected override Size ArrangeOverride( Size finalSize )
+ {
+ this.child.Arrange( new Rect( finalSize ) );
+ return finalSize;
+ }
+
+ ///
+ /// Override.
+ ///
+ ///
+ ///
+ protected override Visual GetVisualChild( int index )
+ {
+ return this.child;
+ }
+
+ ///
+ /// Override. Always returns 1.
+ ///
+ protected override int VisualChildrenCount
+ {
+ get { return 1; }
+ }
+
+ #endregion // Protected Overrides
+
+ #region Private Helpers
+
+ private void UpdateLocation()
+ {
+ AdornerLayer adornerLayer = this.Parent as AdornerLayer;
+ if( adornerLayer != null )
+ adornerLayer.Update( this.AdornedElement );
+ }
+
+ #endregion // Private Helpers
+ }
+}
\ No newline at end of file
diff --git a/Util/FileIcon.cs b/Util/FileIcon.cs
new file mode 100644
index 0000000..7b26b17
--- /dev/null
+++ b/Util/FileIcon.cs
@@ -0,0 +1,376 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+using System.Runtime.InteropServices;
+using System.Drawing;
+using System.Drawing.Imaging;
+using System.IO;
+using System.Windows.Media.Imaging;
+
+namespace GeekDesk.Util
+{
+ class FileIcon
+ {
+
+
+ public static Icon GetIcon(string filePath)
+ {
+ IntPtr hIcon = GetJumboIcon(GetIconIndex(filePath));
+ Icon ico = Icon.FromHandle(hIcon);
+ return ico;
+ }
+
+ public static BitmapImage GetBitmapImage(string filePath)
+ {
+ //Icon ico;
+ //BitmapImage bmpImage = null;
+ //MemoryStream strm;
+ //using (ico = GetIcon(filePath))
+ //{
+ // Bitmap bmp = ico.ToBitmap();
+ // using (strm = new MemoryStream())
+ // {
+ // bmp.Save(strm, System.Drawing.Imaging.ImageFormat.Png);
+ // bmpImage = new BitmapImage();
+ // bmpImage.BeginInit();
+ // strm.Seek(0, SeekOrigin.Begin);
+ // bmpImage.StreamSource = strm;
+ // bmpImage.EndInit();
+ // }
+ //}
+ //return bmpImage;
+ Icon ico = GetIcon(filePath);
+ Bitmap bmp = ico.ToBitmap();
+ MemoryStream strm = new MemoryStream();
+ bmp.Save(strm, System.Drawing.Imaging.ImageFormat.Png);
+ BitmapImage bmpImage = new BitmapImage();
+ bmpImage.BeginInit();
+ strm.Seek(0, SeekOrigin.Begin);
+ bmpImage.StreamSource = strm;
+ bmpImage.EndInit();
+
+ return bmpImage.Clone();
+ }
+
+ public static int GetIconIndex(string pszFile)
+ {
+ SHFILEINFO sfi = new SHFILEINFO();
+ Shell32.SHGetFileInfo(pszFile
+ , 0
+ , ref sfi
+ , (uint)System.Runtime.InteropServices.Marshal.SizeOf(sfi)
+ , (uint)(SHGFI.SysIconIndex | SHGFI.LargeIcon | SHGFI.UseFileAttributes));
+ return sfi.iIcon;
+ }
+
+ // 256*256
+ public static IntPtr GetJumboIcon(int iImage)
+ {
+ IImageList spiml = null;
+ Guid guil = new Guid(IID_IImageList2);//or IID_IImageList
+
+ Shell32.SHGetImageList(Shell32.SHIL_JUMBO, ref guil, ref spiml);
+ IntPtr hIcon = IntPtr.Zero;
+ spiml.GetIcon(iImage, Shell32.ILD_TRANSPARENT | Shell32.ILD_IMAGE, ref hIcon);
+
+ return hIcon;
+ }
+
+ const string IID_IImageList = "46EB5926-582E-4017-9FDF-E8998DAA0950";
+ const string IID_IImageList2 = "192B9D83-50FC-457B-90A0-2B82A8B5DAE1";
+
+ public static class Shell32
+ {
+
+ public const int SHIL_LARGE = 0x0;
+ public const int SHIL_SMALL = 0x1;
+ public const int SHIL_EXTRALARGE = 0x2;
+ public const int SHIL_SYSSMALL = 0x3;
+ public const int SHIL_JUMBO = 0x4;
+ public const int SHIL_LAST = 0x4;
+
+ public const int ILD_TRANSPARENT = 0x00000001;
+ public const int ILD_IMAGE = 0x00000020;
+
+ [DllImport("shell32.dll", EntryPoint = "#727")]
+ public extern static int SHGetImageList(int iImageList, ref Guid riid, ref IImageList ppv);
+
+ [DllImport("user32.dll", EntryPoint = "DestroyIcon", SetLastError = true)]
+ public static unsafe extern int DestroyIcon(IntPtr hIcon);
+
+ [DllImport("shell32.dll")]
+ public static extern uint SHGetIDListFromObject([MarshalAs(UnmanagedType.IUnknown)] object iUnknown, out IntPtr ppidl);
+
+ [DllImport("Shell32.dll")]
+ public static extern IntPtr SHGetFileInfo(
+ string pszPath,
+ uint dwFileAttributes,
+ ref SHFILEINFO psfi,
+ uint cbFileInfo,
+ uint uFlags
+ );
+ }
+
+ [Flags]
+ enum SHGFI : uint
+ {
+ /// get icon
+ Icon = 0x000000100,
+ /// get display name
+ DisplayName = 0x000000200,
+ /// get type name
+ TypeName = 0x000000400,
+ /// get attributes
+ Attributes = 0x000000800,
+ /// get icon location
+ IconLocation = 0x000001000,
+ /// return exe type
+ ExeType = 0x000002000,
+ /// get system icon index
+ SysIconIndex = 0x000004000,
+ /// put a link overlay on icon
+ LinkOverlay = 0x000008000,
+ /// show icon in selected state
+ Selected = 0x000010000,
+ /// get only specified attributes
+ Attr_Specified = 0x000020000,
+ /// get large icon
+ LargeIcon = 0x000000000,
+ /// get small icon
+ SmallIcon = 0x000000001,
+ /// get open icon
+ OpenIcon = 0x000000002,
+ /// get shell size icon
+ ShellIconSize = 0x000000004,
+ /// pszPath is a pidl
+ PIDL = 0x000000008,
+ /// use passed dwFileAttribute
+ UseFileAttributes = 0x000000010,
+ /// apply the appropriate overlays
+ AddOverlays = 0x000000020,
+ /// Get the index of the overlay in the upper 8 bits of the iIcon
+ OverlayIndex = 0x000000040,
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct SHFILEINFO
+ {
+ public const int NAMESIZE = 80;
+ public IntPtr hIcon;
+ public int iIcon;
+ public uint dwAttributes;
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
+ public string szDisplayName;
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)]
+ public string szTypeName;
+ };
+
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct RECT
+ {
+ public int left, top, right, bottom;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct POINT
+ {
+ int x;
+ int y;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct IMAGELISTDRAWPARAMS
+ {
+ public int cbSize;
+ public IntPtr himl;
+ public int i;
+ public IntPtr hdcDst;
+ public int x;
+ public int y;
+ public int cx;
+ public int cy;
+ public int xBitmap; // x offest from the upperleft of bitmap
+ public int yBitmap; // y offset from the upperleft of bitmap
+ public int rgbBk;
+ public int rgbFg;
+ public int fStyle;
+ public int dwRop;
+ public int fState;
+ public int Frame;
+ public int crEffect;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct IMAGEINFO
+ {
+ public IntPtr hbmImage;
+ public IntPtr hbmMask;
+ public int Unused1;
+ public int Unused2;
+ public RECT rcImage;
+ }
+ [ComImportAttribute()]
+ [GuidAttribute("46EB5926-582E-4017-9FDF-E8998DAA0950")]
+ [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
+ public interface IImageList
+ {
+ [PreserveSig]
+ int Add(
+ IntPtr hbmImage,
+ IntPtr hbmMask,
+ ref int pi);
+
+ [PreserveSig]
+ int ReplaceIcon(
+ int i,
+ IntPtr hicon,
+ ref int pi);
+
+ [PreserveSig]
+ int SetOverlayImage(
+ int iImage,
+ int iOverlay);
+
+ [PreserveSig]
+ int Replace(
+ int i,
+ IntPtr hbmImage,
+ IntPtr hbmMask);
+
+ [PreserveSig]
+ int AddMasked(
+ IntPtr hbmImage,
+ int crMask,
+ ref int pi);
+
+ [PreserveSig]
+ int Draw(
+ ref IMAGELISTDRAWPARAMS pimldp);
+
+ [PreserveSig]
+ int Remove(int i);
+
+ [PreserveSig]
+ int GetIcon(
+ int i,
+ int flags,
+ ref IntPtr picon);
+
+ [PreserveSig]
+ int GetImageInfo(
+ int i,
+ ref IMAGEINFO pImageInfo);
+
+ [PreserveSig]
+ int Copy(
+ int iDst,
+ IImageList punkSrc,
+ int iSrc,
+ int uFlags);
+
+ [PreserveSig]
+ int Merge(
+ int i1,
+ IImageList punk2,
+ int i2,
+ int dx,
+ int dy,
+ ref Guid riid,
+ ref IntPtr ppv);
+
+ [PreserveSig]
+ int Clone(
+ ref Guid riid,
+ ref IntPtr ppv);
+
+ [PreserveSig]
+ int GetImageRect(
+ int i,
+ ref RECT prc);
+
+ [PreserveSig]
+ int GetIconSize(
+ ref int cx,
+ ref int cy);
+
+ [PreserveSig]
+ int SetIconSize(
+ int cx,
+ int cy);
+
+ [PreserveSig]
+ int GetImageCount(ref int pi);
+
+ [PreserveSig]
+ int SetImageCount(
+ int uNewCount);
+
+ [PreserveSig]
+ int SetBkColor(
+ int clrBk,
+ ref int pclr);
+
+ [PreserveSig]
+ int GetBkColor(
+ ref int pclr);
+
+ [PreserveSig]
+ int BeginDrag(
+ int iTrack,
+ int dxHotspot,
+ int dyHotspot);
+
+ [PreserveSig]
+ int EndDrag();
+
+ [PreserveSig]
+ int DragEnter(
+ IntPtr hwndLock,
+ int x,
+ int y);
+
+ [PreserveSig]
+ int DragLeave(
+ IntPtr hwndLock);
+
+ [PreserveSig]
+ int DragMove(
+ int x,
+ int y);
+
+ [PreserveSig]
+ int SetDragCursorImage(
+ ref IImageList punk,
+ int iDrag,
+ int dxHotspot,
+ int dyHotspot);
+
+ [PreserveSig]
+ int DragShowNolock(
+ int fShow);
+
+ [PreserveSig]
+ int GetDragImage(
+ ref POINT ppt,
+ ref POINT pptHotspot,
+ ref Guid riid,
+ ref IntPtr ppv);
+
+ [PreserveSig]
+ int GetItemFlags(
+ int i,
+ ref int dwFlags);
+
+ [PreserveSig]
+ int GetOverlayImage(
+ int iOverlay,
+ ref int piIndex);
+ };
+
+ }
+
+}
diff --git a/Util/ListViewDragDropManager.cs b/Util/ListViewDragDropManager.cs
new file mode 100644
index 0000000..1a680d6
--- /dev/null
+++ b/Util/ListViewDragDropManager.cs
@@ -0,0 +1,864 @@
+// Copyright (C) Josh Smith - January 2007
+using System;
+using System.Collections.ObjectModel;
+using System.ComponentModel;
+using System.Diagnostics;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Controls.Primitives;
+using System.Windows.Documents;
+using System.Windows.Media;
+using System.Windows.Input;
+using WPF.JoshSmith.Adorners;
+using WPF.JoshSmith.Controls.Utilities;
+
+namespace WPF.JoshSmith.ServiceProviders.UI
+{
+ #region ListViewDragDropManager
+
+ ///
+ /// Manages the dragging and dropping of ListViewItems in a ListView.
+ /// The ItemType type parameter indicates the type of the objects in
+ /// the ListView's items source. The ListView's ItemsSource must be
+ /// set to an instance of ObservableCollection of ItemType, or an
+ /// Exception will be thrown.
+ ///
+ /// The type of the ListView's items.
+ public class ListViewDragDropManager where ItemType : class
+ {
+ #region Data
+
+ bool canInitiateDrag;
+ DragAdorner dragAdorner;
+ double dragAdornerOpacity;
+ int indexToSelect;
+ bool isDragInProgress;
+ ItemType itemUnderDragCursor;
+ ListView listView;
+ Point ptMouseDown;
+ bool showDragAdorner;
+
+ #endregion // Data
+
+ #region Constructors
+
+ ///
+ /// Initializes a new instance of ListViewDragManager.
+ ///
+ public ListViewDragDropManager()
+ {
+ this.canInitiateDrag = false;
+ this.dragAdornerOpacity = 0.7;
+ this.indexToSelect = -1;
+ this.showDragAdorner = true;
+ }
+
+ ///
+ /// Initializes a new instance of ListViewDragManager.
+ ///
+ ///
+ public ListViewDragDropManager( ListView listView )
+ : this()
+ {
+ this.ListView = listView;
+ }
+
+ ///
+ /// Initializes a new instance of ListViewDragManager.
+ ///
+ ///
+ ///
+ public ListViewDragDropManager( ListView listView, double dragAdornerOpacity )
+ : this( listView )
+ {
+ this.DragAdornerOpacity = dragAdornerOpacity;
+ }
+
+ ///
+ /// Initializes a new instance of ListViewDragManager.
+ ///
+ ///
+ ///
+ public ListViewDragDropManager( ListView listView, bool showDragAdorner )
+ : this( listView )
+ {
+ this.ShowDragAdorner = showDragAdorner;
+ }
+
+ #endregion // Constructors
+
+ #region Public Interface
+
+ #region DragAdornerOpacity
+
+ ///
+ /// Gets/sets the opacity of the drag adorner. This property has no
+ /// effect if ShowDragAdorner is false. The default value is 0.7
+ ///
+ public double DragAdornerOpacity
+ {
+ get { return this.dragAdornerOpacity; }
+ set
+ {
+ if( this.IsDragInProgress )
+ throw new InvalidOperationException( "Cannot set the DragAdornerOpacity property during a drag operation." );
+
+ if( value < 0.0 || value > 1.0 )
+ throw new ArgumentOutOfRangeException( "DragAdornerOpacity", value, "Must be between 0 and 1." );
+
+ this.dragAdornerOpacity = value;
+ }
+ }
+
+ #endregion // DragAdornerOpacity
+
+ #region IsDragInProgress
+
+ ///
+ /// Returns true if there is currently a drag operation being managed.
+ ///
+ public bool IsDragInProgress
+ {
+ get { return this.isDragInProgress; }
+ private set { this.isDragInProgress = value; }
+ }
+
+ #endregion // IsDragInProgress
+
+ #region ListView
+
+ ///
+ /// Gets/sets the ListView whose dragging is managed. This property
+ /// can be set to null, to prevent drag management from occuring. If
+ /// the ListView's AllowDrop property is false, it will be set to true.
+ ///
+ public ListView ListView
+ {
+ get { return listView; }
+ set
+ {
+ if( this.IsDragInProgress )
+ throw new InvalidOperationException( "Cannot set the ListView property during a drag operation." );
+
+ if( this.listView != null )
+ {
+ #region Unhook Events
+
+ this.listView.PreviewMouseLeftButtonDown -= listView_PreviewMouseLeftButtonDown;
+ this.listView.PreviewMouseMove -= listView_PreviewMouseMove;
+ this.listView.DragOver -= listView_DragOver;
+ this.listView.DragLeave -= listView_DragLeave;
+ this.listView.DragEnter -= listView_DragEnter;
+ this.listView.Drop -= listView_Drop;
+
+ #endregion // Unhook Events
+ }
+
+ this.listView = value;
+
+ if( this.listView != null )
+ {
+ if( !this.listView.AllowDrop )
+ this.listView.AllowDrop = true;
+
+ #region Hook Events
+
+ this.listView.PreviewMouseLeftButtonDown += listView_PreviewMouseLeftButtonDown;
+ this.listView.PreviewMouseMove += listView_PreviewMouseMove;
+ this.listView.DragOver += listView_DragOver;
+ this.listView.DragLeave += listView_DragLeave;
+ this.listView.DragEnter += listView_DragEnter;
+ this.listView.Drop += listView_Drop;
+
+ #endregion // Hook Events
+ }
+ }
+ }
+
+ #endregion // ListView
+
+ #region ProcessDrop [event]
+
+ ///
+ /// Raised when a drop occurs. By default the dropped item will be moved
+ /// to the target index. Handle this event if relocating the dropped item
+ /// requires custom behavior. Note, if this event is handled the default
+ /// item dropping logic will not occur.
+ ///
+ public event EventHandler> ProcessDrop;
+
+ #endregion // ProcessDrop [event]
+
+ #region ShowDragAdorner
+
+ ///
+ /// Gets/sets whether a visual representation of the ListViewItem being dragged
+ /// follows the mouse cursor during a drag operation. The default value is true.
+ ///
+ public bool ShowDragAdorner
+ {
+ get { return this.showDragAdorner; }
+ set
+ {
+ if( this.IsDragInProgress )
+ throw new InvalidOperationException( "Cannot set the ShowDragAdorner property during a drag operation." );
+
+ this.showDragAdorner = value;
+ }
+ }
+
+ #endregion // ShowDragAdorner
+
+ #endregion // Public Interface
+
+ #region Event Handling Methods
+
+ #region listView_PreviewMouseLeftButtonDown
+
+ void listView_PreviewMouseLeftButtonDown( object sender, MouseButtonEventArgs e )
+ {
+ if( this.IsMouseOverScrollbar )
+ {
+ // 4/13/2007 - Set the flag to false when cursor is over scrollbar.
+ this.canInitiateDrag = false;
+ return;
+ }
+
+ int index = this.IndexUnderDragCursor;
+ this.canInitiateDrag = index > -1;
+
+ if( this.canInitiateDrag )
+ {
+ // Remember the location and index of the ListViewItem the user clicked on for later.
+ this.ptMouseDown = MouseUtilities.GetMousePosition( this.listView );
+ this.indexToSelect = index;
+ }
+ else
+ {
+ this.ptMouseDown = new Point( -10000, -10000 );
+ this.indexToSelect = -1;
+ }
+ }
+
+ #endregion // listView_PreviewMouseLeftButtonDown
+
+ #region listView_PreviewMouseMove
+
+ void listView_PreviewMouseMove( object sender, MouseEventArgs e )
+ {
+ if( !this.CanStartDragOperation )
+ return;
+
+ // Select the item the user clicked on.
+ if( this.listView.SelectedIndex != this.indexToSelect )
+ this.listView.SelectedIndex = this.indexToSelect;
+
+ // If the item at the selected index is null, there's nothing
+ // we can do, so just return;
+ if( this.listView.SelectedItem == null )
+ return;
+
+ ListViewItem itemToDrag = this.GetListViewItem( this.listView.SelectedIndex );
+ if( itemToDrag == null )
+ return;
+
+ AdornerLayer adornerLayer = this.ShowDragAdornerResolved ? this.InitializeAdornerLayer( itemToDrag ) : null;
+
+ this.InitializeDragOperation( itemToDrag );
+ this.PerformDragOperation();
+ this.FinishDragOperation( itemToDrag, adornerLayer );
+ }
+
+ #endregion // listView_PreviewMouseMove
+
+ #region listView_DragOver
+
+ void listView_DragOver( object sender, DragEventArgs e )
+ {
+ e.Effects = DragDropEffects.Move;
+
+ if( this.ShowDragAdornerResolved )
+ this.UpdateDragAdornerLocation();
+
+ // Update the item which is known to be currently under the drag cursor.
+ int index = this.IndexUnderDragCursor;
+ this.ItemUnderDragCursor = index < 0 ? null : this.ListView.Items[index] as ItemType;
+ }
+
+ #endregion // listView_DragOver
+
+ #region listView_DragLeave
+
+ void listView_DragLeave( object sender, DragEventArgs e )
+ {
+ if( !this.IsMouseOver( this.listView ) )
+ {
+ if( this.ItemUnderDragCursor != null )
+ this.ItemUnderDragCursor = null;
+
+ if( this.dragAdorner != null )
+ this.dragAdorner.Visibility = Visibility.Collapsed;
+ }
+ }
+
+ #endregion // listView_DragLeave
+
+ #region listView_DragEnter
+
+ void listView_DragEnter( object sender, DragEventArgs e )
+ {
+ if( this.dragAdorner != null && this.dragAdorner.Visibility != Visibility.Visible )
+ {
+ // Update the location of the adorner and then show it.
+ this.UpdateDragAdornerLocation();
+ this.dragAdorner.Visibility = Visibility.Visible;
+ }
+ }
+
+ #endregion // listView_DragEnter
+
+ #region listView_Drop
+
+ void listView_Drop( object sender, DragEventArgs e )
+ {
+ if( this.ItemUnderDragCursor != null )
+ this.ItemUnderDragCursor = null;
+
+ e.Effects = DragDropEffects.None;
+
+ if( !e.Data.GetDataPresent( typeof( ItemType ) ) )
+ return;
+
+ // Get the data object which was dropped.
+ ItemType data = e.Data.GetData( typeof( ItemType ) ) as ItemType;
+ if( data == null )
+ return;
+
+ // Get the ObservableCollection which contains the dropped data object.
+ ObservableCollection itemsSource = this.listView.ItemsSource as ObservableCollection;
+ if( itemsSource == null )
+ throw new Exception(
+ "A ListView managed by ListViewDragManager must have its ItemsSource set to an ObservableCollection." );
+
+ int oldIndex = itemsSource.IndexOf( data );
+ int newIndex = this.IndexUnderDragCursor;
+
+ if( newIndex < 0 )
+ {
+ // The drag started somewhere else, and our ListView is empty
+ // so make the new item the first in the list.
+ if( itemsSource.Count == 0 )
+ newIndex = 0;
+
+ // The drag started somewhere else, but our ListView has items
+ // so make the new item the last in the list.
+ else if( oldIndex < 0 )
+ newIndex = itemsSource.Count;
+
+ // The user is trying to drop an item from our ListView into
+ // our ListView, but the mouse is not over an item, so don't
+ // let them drop it.
+ else
+ return;
+ }
+
+ // Dropping an item back onto itself is not considered an actual 'drop'.
+ if( oldIndex == newIndex )
+ return;
+
+ if( this.ProcessDrop != null )
+ {
+ // Let the client code process the drop.
+ ProcessDropEventArgs args = new ProcessDropEventArgs( itemsSource, data, oldIndex, newIndex, e.AllowedEffects );
+ this.ProcessDrop( this, args );
+ e.Effects = args.Effects;
+ }
+ else
+ {
+ // Move the dragged data object from it's original index to the
+ // new index (according to where the mouse cursor is). If it was
+ // not previously in the ListBox, then insert the item.
+ if( oldIndex > -1 )
+ itemsSource.Move( oldIndex, newIndex );
+ else
+ itemsSource.Insert( newIndex, data );
+
+ // Set the Effects property so that the call to DoDragDrop will return 'Move'.
+ e.Effects = DragDropEffects.Move;
+ }
+ }
+
+ #endregion // listView_Drop
+
+ #endregion // Event Handling Methods
+
+ #region Private Helpers
+
+ #region CanStartDragOperation
+
+ bool CanStartDragOperation
+ {
+ get
+ {
+ if( Mouse.LeftButton != MouseButtonState.Pressed )
+ return false;
+
+ if( !this.canInitiateDrag )
+ return false;
+
+ if( this.indexToSelect == -1 )
+ return false;
+
+ if( !this.HasCursorLeftDragThreshold )
+ return false;
+
+ return true;
+ }
+ }
+
+ #endregion // CanStartDragOperation
+
+ #region FinishDragOperation
+
+ void FinishDragOperation( ListViewItem draggedItem, AdornerLayer adornerLayer )
+ {
+ // Let the ListViewItem know that it is not being dragged anymore.
+ ListViewItemDragState.SetIsBeingDragged( draggedItem, false );
+
+ this.IsDragInProgress = false;
+
+ if( this.ItemUnderDragCursor != null )
+ this.ItemUnderDragCursor = null;
+
+ // Remove the drag adorner from the adorner layer.
+ if( adornerLayer != null )
+ {
+ adornerLayer.Remove( this.dragAdorner );
+ this.dragAdorner = null;
+ }
+ }
+
+ #endregion // FinishDragOperation
+
+ #region GetListViewItem
+
+ ListViewItem GetListViewItem( int index )
+ {
+ if( this.listView.ItemContainerGenerator.Status != GeneratorStatus.ContainersGenerated )
+ return null;
+
+ return this.listView.ItemContainerGenerator.ContainerFromIndex( index ) as ListViewItem;
+ }
+
+ ListViewItem GetListViewItem( ItemType dataItem )
+ {
+ if( this.listView.ItemContainerGenerator.Status != GeneratorStatus.ContainersGenerated )
+ return null;
+
+ return this.listView.ItemContainerGenerator.ContainerFromItem( dataItem ) as ListViewItem;
+ }
+
+ #endregion // GetListViewItem
+
+ #region HasCursorLeftDragThreshold
+
+ bool HasCursorLeftDragThreshold
+ {
+ get
+ {
+ if( this.indexToSelect < 0 )
+ return false;
+
+ ListViewItem item = this.GetListViewItem( this.indexToSelect );
+ Rect bounds = VisualTreeHelper.GetDescendantBounds( item );
+ Point ptInItem = this.listView.TranslatePoint( this.ptMouseDown, item );
+
+ // In case the cursor is at the very top or bottom of the ListViewItem
+ // we want to make the vertical threshold very small so that dragging
+ // over an adjacent item does not select it.
+ double topOffset = Math.Abs( ptInItem.Y );
+ double btmOffset = Math.Abs( bounds.Height - ptInItem.Y );
+ double vertOffset = Math.Min( topOffset, btmOffset );
+
+ double width = SystemParameters.MinimumHorizontalDragDistance * 2;
+ double height = Math.Min( SystemParameters.MinimumVerticalDragDistance, vertOffset ) * 2;
+ Size szThreshold = new Size( width, height );
+
+ Rect rect = new Rect( this.ptMouseDown, szThreshold );
+ rect.Offset( szThreshold.Width / -2, szThreshold.Height / -2 );
+ Point ptInListView = MouseUtilities.GetMousePosition( this.listView );
+ return !rect.Contains( ptInListView );
+ }
+ }
+
+ #endregion // HasCursorLeftDragThreshold
+
+ #region IndexUnderDragCursor
+
+ ///
+ /// Returns the index of the ListViewItem underneath the
+ /// drag cursor, or -1 if the cursor is not over an item.
+ ///
+ int IndexUnderDragCursor
+ {
+ get
+ {
+ int index = -1;
+ for( int i = 0; i < this.listView.Items.Count; ++i )
+ {
+ ListViewItem item = this.GetListViewItem( i );
+ if( this.IsMouseOver( item ) )
+ {
+ index = i;
+ break;
+ }
+ }
+ return index;
+ }
+ }
+
+ #endregion // IndexUnderDragCursor
+
+ #region InitializeAdornerLayer
+
+ AdornerLayer InitializeAdornerLayer( ListViewItem itemToDrag )
+ {
+ // Create a brush which will paint the ListViewItem onto
+ // a visual in the adorner layer.
+ VisualBrush brush = new VisualBrush( itemToDrag );
+
+ // Create an element which displays the source item while it is dragged.
+ this.dragAdorner = new DragAdorner( this.listView, itemToDrag.RenderSize, brush );
+
+ // Set the drag adorner's opacity.
+ this.dragAdorner.Opacity = this.DragAdornerOpacity;
+
+ AdornerLayer layer = AdornerLayer.GetAdornerLayer( this.listView );
+ layer.Add( dragAdorner );
+
+ // Save the location of the cursor when the left mouse button was pressed.
+ this.ptMouseDown = MouseUtilities.GetMousePosition( this.listView );
+
+ return layer;
+ }
+
+ #endregion // InitializeAdornerLayer
+
+ #region InitializeDragOperation
+
+ void InitializeDragOperation( ListViewItem itemToDrag )
+ {
+ // Set some flags used during the drag operation.
+ this.IsDragInProgress = true;
+ this.canInitiateDrag = false;
+
+ // Let the ListViewItem know that it is being dragged.
+ ListViewItemDragState.SetIsBeingDragged( itemToDrag, true );
+ }
+
+ #endregion // InitializeDragOperation
+
+ #region IsMouseOver
+
+ bool IsMouseOver( Visual target )
+ {
+ // We need to use MouseUtilities to figure out the cursor
+ // coordinates because, during a drag-drop operation, the WPF
+ // mechanisms for getting the coordinates behave strangely.
+
+ Rect bounds = VisualTreeHelper.GetDescendantBounds( target );
+ Point mousePos = MouseUtilities.GetMousePosition( target );
+ return bounds.Contains( mousePos );
+ }
+
+ #endregion // IsMouseOver
+
+ #region IsMouseOverScrollbar
+
+ ///
+ /// Returns true if the mouse cursor is over a scrollbar in the ListView.
+ ///
+ bool IsMouseOverScrollbar
+ {
+ get
+ {
+ Point ptMouse = MouseUtilities.GetMousePosition( this.listView );
+ HitTestResult res = VisualTreeHelper.HitTest( this.listView, ptMouse );
+ if( res == null )
+ return false;
+
+ DependencyObject depObj = res.VisualHit;
+ while( depObj != null )
+ {
+ if( depObj is ScrollBar )
+ return true;
+
+ // VisualTreeHelper works with objects of type Visual or Visual3D.
+ // If the current object is not derived from Visual or Visual3D,
+ // then use the LogicalTreeHelper to find the parent element.
+ if( depObj is Visual || depObj is System.Windows.Media.Media3D.Visual3D )
+ depObj = VisualTreeHelper.GetParent( depObj );
+ else
+ depObj = LogicalTreeHelper.GetParent( depObj );
+ }
+
+ return false;
+ }
+ }
+
+ #endregion // IsMouseOverScrollbar
+
+ #region ItemUnderDragCursor
+
+ ItemType ItemUnderDragCursor
+ {
+ get { return this.itemUnderDragCursor; }
+ set
+ {
+ if( this.itemUnderDragCursor == value )
+ return;
+
+ // The first pass handles the previous item under the cursor.
+ // The second pass handles the new one.
+ for( int i = 0; i < 2; ++i )
+ {
+ if( i == 1 )
+ this.itemUnderDragCursor = value;
+
+ if( this.itemUnderDragCursor != null )
+ {
+ ListViewItem listViewItem = this.GetListViewItem( this.itemUnderDragCursor );
+ if( listViewItem != null )
+ ListViewItemDragState.SetIsUnderDragCursor( listViewItem, i == 1 );
+ }
+ }
+ }
+ }
+
+ #endregion // ItemUnderDragCursor
+
+ #region PerformDragOperation
+
+ void PerformDragOperation()
+ {
+ ItemType selectedItem = this.listView.SelectedItem as ItemType;
+ DragDropEffects allowedEffects = DragDropEffects.Move | DragDropEffects.Move | DragDropEffects.Link;
+ if( DragDrop.DoDragDrop( this.listView, selectedItem, allowedEffects ) != DragDropEffects.None )
+ {
+ // The item was dropped into a new location,
+ // so make it the new selected item.
+ this.listView.SelectedItem = selectedItem;
+ }
+ }
+
+ #endregion // PerformDragOperation
+
+ #region ShowDragAdornerResolved
+
+ bool ShowDragAdornerResolved
+ {
+ get { return this.ShowDragAdorner && this.DragAdornerOpacity > 0.0; }
+ }
+
+ #endregion // ShowDragAdornerResolved
+
+ #region UpdateDragAdornerLocation
+
+ void UpdateDragAdornerLocation()
+ {
+ if( this.dragAdorner != null )
+ {
+ Point ptCursor = MouseUtilities.GetMousePosition( this.ListView );
+
+ double left = ptCursor.X - this.ptMouseDown.X;
+
+ // 4/13/2007 - Made the top offset relative to the item being dragged.
+ ListViewItem itemBeingDragged = this.GetListViewItem( this.indexToSelect );
+ Point itemLoc = itemBeingDragged.TranslatePoint( new Point( 0, 0 ), this.ListView );
+ double top = itemLoc.Y + ptCursor.Y - this.ptMouseDown.Y;
+
+ this.dragAdorner.SetOffsets( left, top );
+ }
+ }
+
+ #endregion // UpdateDragAdornerLocation
+
+ #endregion // Private Helpers
+ }
+
+ #endregion // ListViewDragDropManager
+
+ #region ListViewItemDragState
+
+ ///
+ /// Exposes attached properties used in conjunction with the ListViewDragDropManager class.
+ /// Those properties can be used to allow triggers to modify the appearance of ListViewItems
+ /// in a ListView during a drag-drop operation.
+ ///
+ public static class ListViewItemDragState
+ {
+ #region IsBeingDragged
+
+ ///
+ /// Identifies the ListViewItemDragState's IsBeingDragged attached property.
+ /// This field is read-only.
+ ///
+ public static readonly DependencyProperty IsBeingDraggedProperty =
+ DependencyProperty.RegisterAttached(
+ "IsBeingDragged",
+ typeof( bool ),
+ typeof( ListViewItemDragState ),
+ new UIPropertyMetadata( false ) );
+
+ ///
+ /// Returns true if the specified ListViewItem is being dragged, else false.
+ ///
+ /// The ListViewItem to check.
+ public static bool GetIsBeingDragged( ListViewItem item )
+ {
+ return (bool)item.GetValue( IsBeingDraggedProperty );
+ }
+
+ ///
+ /// Sets the IsBeingDragged attached property for the specified ListViewItem.
+ ///
+ /// The ListViewItem to set the property on.
+ /// Pass true if the element is being dragged, else false.
+ internal static void SetIsBeingDragged( ListViewItem item, bool value )
+ {
+ item.SetValue( IsBeingDraggedProperty, value );
+ }
+
+ #endregion // IsBeingDragged
+
+ #region IsUnderDragCursor
+
+ ///
+ /// Identifies the ListViewItemDragState's IsUnderDragCursor attached property.
+ /// This field is read-only.
+ ///
+ public static readonly DependencyProperty IsUnderDragCursorProperty =
+ DependencyProperty.RegisterAttached(
+ "IsUnderDragCursor",
+ typeof( bool ),
+ typeof( ListViewItemDragState ),
+ new UIPropertyMetadata( false ) );
+
+ ///
+ /// Returns true if the specified ListViewItem is currently underneath the cursor
+ /// during a drag-drop operation, else false.
+ ///
+ /// The ListViewItem to check.
+ public static bool GetIsUnderDragCursor( ListViewItem item )
+ {
+ return (bool)item.GetValue( IsUnderDragCursorProperty );
+ }
+
+ ///
+ /// Sets the IsUnderDragCursor attached property for the specified ListViewItem.
+ ///
+ /// The ListViewItem to set the property on.
+ /// Pass true if the element is underneath the drag cursor, else false.
+ internal static void SetIsUnderDragCursor( ListViewItem item, bool value )
+ {
+ item.SetValue( IsUnderDragCursorProperty, value );
+ }
+
+ #endregion // IsUnderDragCursor
+ }
+
+ #endregion // ListViewItemDragState
+
+ #region ProcessDropEventArgs
+
+ ///
+ /// Event arguments used by the ListViewDragDropManager.ProcessDrop event.
+ ///
+ /// The type of data object being dropped.
+ public class ProcessDropEventArgs : EventArgs where ItemType : class
+ {
+ #region Data
+
+ ObservableCollection itemsSource;
+ ItemType dataItem;
+ int oldIndex;
+ int newIndex;
+ DragDropEffects allowedEffects = DragDropEffects.None;
+ DragDropEffects effects = DragDropEffects.None;
+
+ #endregion // Data
+
+ #region Constructor
+
+ internal ProcessDropEventArgs(
+ ObservableCollection itemsSource,
+ ItemType dataItem,
+ int oldIndex,
+ int newIndex,
+ DragDropEffects allowedEffects )
+ {
+ this.itemsSource = itemsSource;
+ this.dataItem = dataItem;
+ this.oldIndex = oldIndex;
+ this.newIndex = newIndex;
+ this.allowedEffects = allowedEffects;
+ }
+
+ #endregion // Constructor
+
+ #region Public Properties
+
+ ///
+ /// The items source of the ListView where the drop occurred.
+ ///
+ public ObservableCollection ItemsSource
+ {
+ get { return this.itemsSource; }
+ }
+
+ ///
+ /// The data object which was dropped.
+ ///
+ public ItemType DataItem
+ {
+ get { return this.dataItem; }
+ }
+
+ ///
+ /// The current index of the data item being dropped, in the ItemsSource collection.
+ ///
+ public int OldIndex
+ {
+ get { return this.oldIndex; }
+ }
+
+ ///
+ /// The target index of the data item being dropped, in the ItemsSource collection.
+ ///
+ public int NewIndex
+ {
+ get { return this.newIndex; }
+ }
+
+ ///
+ /// The drag drop effects allowed to be performed.
+ ///
+ public DragDropEffects AllowedEffects
+ {
+ get { return allowedEffects; }
+ }
+
+ ///
+ /// The drag drop effect(s) performed on the dropped item.
+ ///
+ public DragDropEffects Effects
+ {
+ get { return effects; }
+ set { effects = value; }
+ }
+
+ #endregion // Public Properties
+ }
+
+ #endregion // ProcessDropEventArgs
+}
\ No newline at end of file
diff --git a/Util/MenuWidthConvert.cs b/Util/MenuWidthConvert.cs
new file mode 100644
index 0000000..d83a00a
--- /dev/null
+++ b/Util/MenuWidthConvert.cs
@@ -0,0 +1,29 @@
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Data;
+
+namespace GeekDesk.Util
+{
+ class MenuWidthConvert : IValueConverter
+ {
+ public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
+ {
+ if (value != null && value.ToString().Length>0)
+ {
+ return System.Convert.ToDouble(value.ToString()) - 10d;
+ } else
+ {
+ return 0d;
+ }
+ }
+
+ public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
+ {
+ throw new NotImplementedException();
+ }
+ }
+}
diff --git a/Util/MouseUtilities.cs b/Util/MouseUtilities.cs
new file mode 100644
index 0000000..ef5aea4
--- /dev/null
+++ b/Util/MouseUtilities.cs
@@ -0,0 +1,58 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Runtime.InteropServices;
+using System.Windows;
+using System.Windows.Media;
+
+namespace WPF.JoshSmith.Controls.Utilities
+{
+ ///
+ /// Provides access to the mouse location by calling unmanaged code.
+ ///
+ ///
+ /// This class was written by Dan Crevier (Microsoft).
+ /// http://blogs.msdn.com/llobo/archive/2006/09/06/Scrolling-Scrollviewer-on-Mouse-Drag-at-the-boundaries.aspx
+ ///
+ public class MouseUtilities
+ {
+ [StructLayout( LayoutKind.Sequential )]
+ private struct Win32Point
+ {
+ public Int32 X;
+ public Int32 Y;
+ };
+
+ [DllImport( "user32.dll" )]
+ private static extern bool GetCursorPos( ref Win32Point pt );
+
+ [DllImport( "user32.dll" )]
+ private static extern bool ScreenToClient( IntPtr hwnd, ref Win32Point pt );
+
+ ///
+ /// Returns the mouse cursor location. This method is necessary during
+ /// a drag-drop operation because the WPF mechanisms for retrieving the
+ /// cursor coordinates are unreliable.
+ ///
+ /// The Visual to which the mouse coordinates will be relative.
+ public static Point GetMousePosition( Visual relativeTo )
+ {
+ Win32Point mouse = new Win32Point();
+ GetCursorPos( ref mouse );
+
+ // Using PointFromScreen instead of Dan Crevier's code (commented out below)
+ // is a bug fix created by William J. Roberts. Read his comments about the fix
+ // here: http://www.codeproject.com/useritems/ListViewDragDropManager.asp?msg=1911611#xx1911611xx
+ return relativeTo.PointFromScreen( new Point( (double)mouse.X, (double)mouse.Y ) );
+
+ #region Commented Out
+ //System.Windows.Interop.HwndSource presentationSource =
+ // (System.Windows.Interop.HwndSource)PresentationSource.FromVisual( relativeTo );
+ //ScreenToClient( presentationSource.Handle, ref mouse );
+ //GeneralTransform transform = relativeTo.TransformToAncestor( presentationSource.RootVisual );
+ //Point offset = transform.Transform( new Point( 0, 0 ) );
+ //return new Point( mouse.X - offset.X, mouse.Y - offset.Y );
+ #endregion // Commented Out
+ }
+ }
+}
\ No newline at end of file
diff --git a/Util/SystemIcon.cs b/Util/SystemIcon.cs
new file mode 100644
index 0000000..337714b
--- /dev/null
+++ b/Util/SystemIcon.cs
@@ -0,0 +1,152 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Drawing;
+using Microsoft.Win32;
+using System.Runtime.InteropServices;
+using System.Drawing.Imaging;
+using GeekDesk.Util;
+
+namespace GeekDesk.Util
+{
+ class SystemIcon
+ {
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
+ public struct SHFILEINFO
+ {
+ public IntPtr hIcon;
+ public int iIcon;
+ public uint dwAttributes;
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
+ public string szDisplayName;
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)]
+ public string szTypeName;
+ }
+ [DllImport("Shell32.dll", EntryPoint = "SHGetFileInfo", SetLastError = true, CharSet = CharSet.Auto)]
+ public static extern IntPtr SHGetFileInfo(string pszPath, uint dwFileAttributes, ref SHFILEINFO psfi, uint cbFileInfo, uint uFlags);
+ [DllImport("User32.dll", EntryPoint = "DestroyIcon")]
+ public static extern int DestroyIcon(IntPtr hIcon);
+ #region API 参数的常量定义
+ public enum FileInfoFlags : uint
+ {
+ SHGFI_ICON = 0x000000100, // get icon
+ SHGFI_DISPLAYNAME = 0x000000200, // get display name
+ SHGFI_TYPENAME = 0x000000400, // get type name
+ SHGFI_ATTRIBUTES = 0x000000800, // get attributes
+ SHGFI_ICONLOCATION = 0x000001000, // get icon location
+ SHGFI_EXETYPE = 0x000002000, // return exe type
+ SHGFI_SYSICONINDEX = 0x000004000, // get system icon index
+ SHGFI_LINKOVERLAY = 0x000008000, // put a link overlay on icon
+ SHGFI_SELECTED = 0x000010000, // show icon in selected state
+ SHGFI_ATTR_SPECIFIED = 0x000020000, // get only specified attributes
+ SHGFI_LARGEICON = 0x000000000, // get large icon
+ SHGFI_SMALLICON = 0x000000001, // get small icon
+ SHGFI_OPENICON = 0x000000002, // get open icon
+ SHGFI_SHELLICONSIZE = 0x000000004, // get shell size icon
+ SHGFI_PIDL = 0x000000008, // pszPath is a pidl
+ SHGFI_USEFILEATTRIBUTES = 0x000000010, // use passed dwFileAttribute
+ SHGFI_ADDOVERLAYS = 0x000000020, // apply the appropriate overlays
+ SHGFI_OVERLAYINDEX = 0x000000040 // Get the index of the overlay
+ }
+ public enum FileAttributeFlags : uint
+ {
+ FILE_ATTRIBUTE_READONLY = 0x00000001,
+ FILE_ATTRIBUTE_HIDDEN = 0x00000002,
+ FILE_ATTRIBUTE_SYSTEM = 0x00000004,
+ FILE_ATTRIBUTE_DIRECTORY = 0x00000010,
+ FILE_ATTRIBUTE_ARCHIVE = 0x00000020,
+ FILE_ATTRIBUTE_DEVICE = 0x00000040,
+ FILE_ATTRIBUTE_NORMAL = 0x00000080,
+ FILE_ATTRIBUTE_TEMPORARY = 0x00000100,
+ FILE_ATTRIBUTE_SPARSE_FILE = 0x00000200,
+ FILE_ATTRIBUTE_REPARSE_POINT = 0x00000400,
+ FILE_ATTRIBUTE_COMPRESSED = 0x00000800,
+ FILE_ATTRIBUTE_OFFLINE = 0x00001000,
+ FILE_ATTRIBUTE_NOT_CONTENT_INDEXED = 0x00002000,
+ FILE_ATTRIBUTE_ENCRYPTED = 0x00004000
+ }
+ #endregion
+ ///
+ /// 获取文件类型的关联图标
+ ///
+ /// 文件类型的扩展名或文件的绝对路径
+ /// 是否返回大图标
+ /// 获取到的图标
+ public static Icon GetIcon(string fileName, bool isLargeIcon)
+ {
+ //SHFILEINFO shfi = new SHFILEINFO();
+ //IntPtr hI;
+ //if (isLargeIcon)
+ // hI = SHGetFileInfo(fileName, 0, ref shfi, (uint)Marshal.SizeOf(shfi), (uint)FileInfoFlags.SHGFI_ICON | (uint)FileInfoFlags.SHGFI_USEFILEATTRIBUTES | (uint)FileInfoFlags.SHGFI_LARGEICON);
+ //else
+ // hI = SHGetFileInfo(fileName, 0, ref shfi, (uint)Marshal.SizeOf(shfi), (uint)FileInfoFlags.SHGFI_ICON | (uint)FileInfoFlags.SHGFI_USEFILEATTRIBUTES | (uint)FileInfoFlags.SHGFI_SMALLICON);
+ //Icon icon = Icon.FromHandle(shfi.hIcon).Clone() as Icon;
+ //DestroyIcon(shfi.hIcon); //释放资源
+
+ //选中文件中的图标总数
+ //var iconTotalCount = PrivateExtractIcons(fileName, 0, 0, 0, null, null, 1, 0);
+ //用于接收获取到的图标指针
+ //IntPtr[] hIcons = new IntPtr[1];
+ ////对应的图标id
+ //int[] ids = new int[1];
+ ////成功获取到的图标个数
+ //int successCount = PrivateExtractIcons(fileName, 0, 0, 0, hIcons, ids, 1, 0);
+ //Icon ico = Icon.FromHandle(hIcons[0]);
+ //var myIcon = ico.ToBitmap();
+ //myIcon.Save("D:\\" + ids[0].ToString("000") + ".png", ImageFormat.Png);
+ IntPtr hIcon = FileIcon.GetJumboIcon(FileIcon.GetIconIndex(fileName));
+ //IntPtr hIcon = GetJumboIcon(GetIconIndex("*." + ext));
+
+ // from native to managed
+ Icon ico = Icon.FromHandle(hIcon);
+ string path = "D:\\test\\" + System.Guid.NewGuid().ToString() + ".png";
+ //using ( ico = (Icon)Icon.FromHandle(hIcon).Clone())
+ //{
+ // // save to file (or show in a picture box)
+ // ico.ToBitmap().Save(path, ImageFormat.Png);
+ //}
+ //FileIcon.Shell32.DestroyIcon(hIcon); // don't forget to cleanup
+
+ return ico;
+ }
+ ///
+ /// 获取文件夹图标
+ ///
+ /// 图标
+ public static Icon GetDirectoryIcon(bool isLargeIcon)
+ {
+ SHFILEINFO _SHFILEINFO = new SHFILEINFO();
+ IntPtr _IconIntPtr;
+ if (isLargeIcon)
+ {
+ _IconIntPtr = SHGetFileInfo(@"", 0, ref _SHFILEINFO, (uint)Marshal.SizeOf(_SHFILEINFO), ((uint)FileInfoFlags.SHGFI_ICON | (uint)FileInfoFlags.SHGFI_LARGEICON));
+ }
+ else
+ {
+ _IconIntPtr = SHGetFileInfo(@"", 0, ref _SHFILEINFO, (uint)Marshal.SizeOf(_SHFILEINFO), ((uint)FileInfoFlags.SHGFI_ICON | (uint)FileInfoFlags.SHGFI_SMALLICON));
+ }
+ if (_IconIntPtr.Equals(IntPtr.Zero)) return null;
+ Icon _Icon = System.Drawing.Icon.FromHandle(_SHFILEINFO.hIcon);
+ return _Icon;
+ }
+
+ [DllImport("User32.dll")]
+ public static extern int PrivateExtractIcons(
+ string lpszFile, //file name
+ int nIconIndex, //The zero-based index of the first icon to extract.
+ int cxIcon, //The horizontal icon size wanted.
+ int cyIcon, //The vertical icon size wanted.
+ IntPtr[] phicon, //(out) A pointer to the returned array of icon handles.
+ int[] piconid, //(out) A pointer to a returned resource identifier.
+ int nIcons, //The number of icons to extract from the file. Only valid when *.exe and *.dll
+ int flags //Specifies flags that control this function.
+ );
+
+ //[DllImport("User32.dll")]
+ //public static extern bool DestroyIcon(
+ // IntPtr hIcon //A handle to the icon to be destroyed. The icon must not be in use.
+ // );
+ }
+}
diff --git a/ViewModel/AppConfig.cs b/ViewModel/AppConfig.cs
new file mode 100644
index 0000000..3b74363
--- /dev/null
+++ b/ViewModel/AppConfig.cs
@@ -0,0 +1,88 @@
+using GalaSoft.MvvmLight;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using GeekDesk.Constant;
+
+namespace GeekDesk.ViewModel
+{
+ [Serializable]
+ public class AppConfig : ViewModelBase
+ {
+ private int menuSortType = (int)SortType.CUSTOM; //菜单排序类型
+ private int iconSortType = (int)SortType.CUSTOM; //图表排序类型
+ private double windowWidth = (double)DefaultConstant.WINDOW_WIDTH; //窗口宽度
+ private double windowHeight = (double)DefaultConstant.WINDOW_HEIGHT; //窗口高度
+ private double menuCardWidth = (double)DefaultConstant.MENU_CARD_WIDHT;//菜单栏宽度
+
+
+ #region GetSet
+ public int MenuSortType {
+ get
+ {
+ return menuSortType;
+ }
+ set
+ {
+ menuSortType = value;
+ RaisePropertyChanged();
+ }
+ }
+
+ public int IconSortType
+ {
+ get
+ {
+ return iconSortType;
+ }
+ set
+ {
+ iconSortType = value;
+ RaisePropertyChanged();
+ }
+ }
+
+ public double WindowWidth
+ {
+ get
+ {
+ return windowWidth;
+ }
+ set
+ {
+ windowWidth = value;
+ RaisePropertyChanged();
+ }
+ }
+
+ public double WindowHeight
+ {
+ get
+ {
+ return windowHeight;
+ }
+ set
+ {
+ windowHeight = value;
+ RaisePropertyChanged();
+ }
+ }
+
+ public double MenuCardWidth
+ {
+ get
+ {
+ return menuCardWidth;
+ }
+ set
+ {
+ menuCardWidth = value;
+ RaisePropertyChanged();
+ }
+ }
+ #endregion
+
+ }
+}
diff --git a/ViewModel/DataInfos.cs b/ViewModel/DataInfos.cs
new file mode 100644
index 0000000..7b0bae1
--- /dev/null
+++ b/ViewModel/DataInfos.cs
@@ -0,0 +1,70 @@
+using GalaSoft.MvvmLight;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Media.Imaging;
+
+namespace GeekDesk.ViewModel
+{
+ public class DataInfos : ViewModelBase
+ {
+ private string path; //路径
+ private string name; //文件名
+ private int count = 0; //打开次数
+ private BitmapImage bitmapImage; //位图
+
+ public int Count
+ {
+ get
+ {
+ return count;
+ }
+ set
+ {
+ count = value;
+ RaisePropertyChanged();
+ }
+ }
+
+ public string Name
+ {
+ get
+ {
+ return name;
+ }
+ set
+ {
+ name = value;
+ RaisePropertyChanged();
+ }
+ }
+
+ public string Path
+ {
+ get
+ {
+ return path;
+ }
+ set
+ {
+ path = value;
+ RaisePropertyChanged();
+ }
+ }
+
+ public BitmapImage BitmapImage
+ {
+ get
+ {
+ return bitmapImage;
+ }
+ set
+ {
+ bitmapImage = value;
+ RaisePropertyChanged();
+ }
+ }
+ }
+}
diff --git a/ViewModel/MainModel.cs b/ViewModel/MainModel.cs
new file mode 100644
index 0000000..86f5601
--- /dev/null
+++ b/ViewModel/MainModel.cs
@@ -0,0 +1,12 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace GeekDesk.ViewModel
+{
+ class MainModel
+ {
+ }
+}
diff --git a/ViewModel/MainViewModel.cs b/ViewModel/MainViewModel.cs
new file mode 100644
index 0000000..e4bfb26
--- /dev/null
+++ b/ViewModel/MainViewModel.cs
@@ -0,0 +1,34 @@
+using GalaSoft.MvvmLight;
+
+namespace GeekDesk.ViewModel
+{
+ ///
+ /// This class contains properties that the main View can data bind to.
+ ///
+ /// Use the mvvminpc snippet to add bindable properties to this ViewModel.
+ ///
+ ///
+ /// You can also use Blend to data bind with the tool's support.
+ ///
+ ///
+ /// See http://www.galasoft.ch/mvvm
+ ///
+ ///
+ public class MainViewModel : ViewModelBase
+ {
+ ///
+ /// Initializes a new instance of the MainViewModel class.
+ ///
+ public MainViewModel()
+ {
+ ////if (IsInDesignMode)
+ ////{
+ //// // Code runs in Blend --> create design time data.
+ ////}
+ ////else
+ ////{
+ //// // Code runs "for real"
+ ////}
+ }
+ }
+}
\ No newline at end of file
diff --git a/ViewModel/MenuViewModel.cs b/ViewModel/MenuViewModel.cs
new file mode 100644
index 0000000..419c2cb
--- /dev/null
+++ b/ViewModel/MenuViewModel.cs
@@ -0,0 +1,36 @@
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace GeekDesk.ViewModel
+{
+ class MenuViewModel
+ {
+
+ public MenuViewModel()
+ {
+
+ }
+
+ public ObservableCollection GetMenus()
+ {
+ ObservableCollection menus = new ObservableCollection();
+ menus.Add(new Menu() { menu = "test1" });
+ menus.Add(new Menu() { menu = "test2" });
+ menus.Add(new Menu() { menu = "test3" });
+ return menus;
+ }
+
+
+ }
+
+
+
+ public class Menu
+ {
+ public string menu { get; set; }
+ }
+}
diff --git a/packages.config b/packages.config
new file mode 100644
index 0000000..a705136
--- /dev/null
+++ b/packages.config
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file