相关知识点:WPF - Adorner
http://www.codeproject.com/Articles/484616/MVVM-Diagram-Designer
翻译好的
http://www.cnblogs.com/zhoujg/archive/2009/11/23/1608913.html
http://www.cnblogs.com/zhoujg/archive/2010/08/17/1801271.html
http://www.cnblogs.com/zhoujg/archive/2010/08/17/1801427.html
http://www.cnblogs.com/zhoujg/archive/2010/08/19/1801660.html
http://www.cnblogs.com/zhoujg/archive/2010/08/19/1801663.html
http://www.codeproject.com/Articles/30721/WPF-TreeListView-Control
http://www.codeproject.com/Articles/618014/Automatic-Scrolling-During-Drag-operation
MainWindow.xaml using System.Windows; using System.Windows.Input; namespace AutoDragScrollingDemo { /// <summary> /// Interaction logic for MainWindow.xaml /// </summary> public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } public void EnableDragDemo(object sender, MouseEventArgs e) { if (e.LeftButton == MouseButtonState.Pressed) { DragDrop.DoDragDrop(sender as DependencyObject, new object(), DragDropEffects.Move); } } } }
MainWindow.xml.cs using System.Windows; using System.Windows.Input; namespace AutoDragScrollingDemo { /// <summary> /// Interaction logic for MainWindow.xaml /// </summary> public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } public void EnableDragDemo(object sender, MouseEventArgs e) { if (e.LeftButton == MouseButtonState.Pressed) { DragDrop.DoDragDrop(sender as DependencyObject, new object(), DragDropEffects.Move); } } } }
AutoDragScrollingDemo.cs /* *This work is being distributed under the The Code Project Open License (CPOL) (http://www.codeproject.com/info/cpol10.aspx) along with all restrictions placed therein. *Attribution: *1. Source Article: http://www.codeproject.com/Articles/618014/Automatic-Scrolling-During-Drag-operation * Author: Amit Mittal (http://www.codeproject.com/Members/Amit_Mittal) */ using System.Diagnostics; using System.Windows; using System.Windows.Controls; using System.Windows.Controls.Primitives; using System.Windows.Media; namespace AutoDragScrollingDemo { public class AutoDragScrollingProvider { public static readonly DependencyProperty EnableAutomaticScrollingProperty = DependencyProperty.RegisterAttached("EnableAutomaticScrolling", typeof(bool), typeof(AutoDragScrollingProvider), new PropertyMetadata(default(bool), OnEnableAutomaticScrollingChange)); public static bool GetEnableAutomaticScrolling(DependencyObject obj) { return (bool)obj.GetValue(EnableAutomaticScrollingProperty); } public static void SetEnableAutomaticScrolling(DependencyObject obj, bool value) { obj.SetValue(EnableAutomaticScrollingProperty, value); } public static readonly DependencyProperty UseLineScrollingForVerticalChange = DependencyProperty.RegisterAttached("UseLineScrollingForVerticalChange", typeof(bool), typeof(AutoDragScrollingProvider), new PropertyMetadata(default(bool))); public static bool GetUseLineScrollingForVerticalChange(DependencyObject obj) { return (bool)obj.GetValue(UseLineScrollingForVerticalChange); } public static void SetUseLineScrollingForVerticalChange(DependencyObject obj, bool value) { obj.SetValue(UseLineScrollingForVerticalChange, value); } public static readonly DependencyProperty UseLineScrollingForHorizontalChangeProperty = DependencyProperty.RegisterAttached("UseLineScrollingForHorizontalChange", typeof(bool), typeof(AutoDragScrollingProvider), new PropertyMetadata(default(bool))); public static bool GetUseLineScrollingForHorizontalChange(DependencyObject obj) { return (bool)obj.GetValue(UseLineScrollingForHorizontalChangeProperty); } public static void SetUseLineScrollingForHorizontalChange(DependencyObject obj, bool value) { obj.SetValue(UseLineScrollingForHorizontalChangeProperty, value); } private static readonly DependencyProperty _autoDragScrollingProviderProperty = DependencyProperty.RegisterAttached("_AutoDragScrollingProvider", typeof(AutoDragScrollingProvider), typeof(AutoDragScrollingProvider), new PropertyMetadata(default(AutoDragScrollingProvider))); private static void OnEnableAutomaticScrollingChange(DependencyObject d, DependencyPropertyChangedEventArgs e) { var uiElement = d as UIElement; if (uiElement != null) { if (true.Equals(e.NewValue)) { Debug.Assert(uiElement.GetValue(_autoDragScrollingProviderProperty) == null); var scrollingManager = new AutoDragScrollingProvider(); uiElement.PreviewDragEnter += scrollingManager.HandlePreviewDragMove; uiElement.PreviewDragOver += scrollingManager.HandlePreviewDragMove; uiElement.SetValue(_autoDragScrollingProviderProperty, scrollingManager); } else { var scrollingManager = uiElement.GetValue(_autoDragScrollingProviderProperty) as AutoDragScrollingProvider; if (scrollingManager != null) { uiElement.PreviewDragEnter -= scrollingManager.HandlePreviewDragMove; uiElement.PreviewDragOver -= scrollingManager.HandlePreviewDragMove; uiElement.SetValue(_autoDragScrollingProviderProperty, null); } } } } //this caching is to avid some redundant steps but may prove troublesome //if parent tree is dynamic which in most cases is not the case. private IScrollInfo _scrollInfo; private void HandlePreviewDragMove(object sender, DragEventArgs e) { if (_scrollInfo == null) { ScrollViewer parentScrollViewer = null; var parent = e.OriginalSource as DependencyObject; while (parent != null) { parentScrollViewer = parent as ScrollViewer; if (parentScrollViewer != null) { break; } parent = VisualTreeHelper.GetParent(parent); } if (parentScrollViewer != null) { parent = e.OriginalSource as DependencyObject; while (parent != null) { _scrollInfo = parent as IScrollInfo; if (_scrollInfo != null && _scrollInfo.ScrollOwner == parentScrollViewer) { break; } _scrollInfo = null; parent = VisualTreeHelper.GetParent(parent); } } Panel scrollablePanel = _scrollInfo as Panel; if (scrollablePanel != null) { Orientation? orientation = null; //Special case handling as stack panel does not support 'smooth scrolling' or in other words fractional offset changes if (scrollablePanel is StackPanel) { orientation = (Orientation)scrollablePanel.GetValue(StackPanel.OrientationProperty); } //VirtualizingStackPanel behaves like StackPanel only if it is not hosted in an ItemsControl else if (scrollablePanel is VirtualizingStackPanel && !scrollablePanel.IsItemsHost) { orientation = (Orientation)scrollablePanel.GetValue(VirtualizingStackPanel.OrientationProperty); } if (orientation != null) { if (orientation == Orientation.Horizontal) { SetUseLineScrollingForHorizontalChange(scrollablePanel, true); } else { SetUseLineScrollingForVerticalChange(scrollablePanel, true); } } } } UIElement scrollable = _scrollInfo as UIElement; if (scrollable != null) { var mousePos = e.GetPosition(scrollable); if (_scrollInfo.CanHorizontallyScroll) { var avgWidth = scrollable.RenderSize.Width / _scrollInfo.ViewportWidth; //translate to pixels if (mousePos.X < 20) { if (GetUseLineScrollingForHorizontalChange(scrollable)) { _scrollInfo.LineLeft(); } else { var delta = (mousePos.X - 20) / avgWidth; //translate back to original unit _scrollInfo.SetHorizontalOffset(_scrollInfo.HorizontalOffset + delta); } } else if (mousePos.X > (scrollable.RenderSize.Width - 20)) { if (GetUseLineScrollingForHorizontalChange(scrollable)) { _scrollInfo.LineRight(); } else { var delta = (mousePos.X + 20 - scrollable.RenderSize.Width) / avgWidth; //translate back to original unit _scrollInfo.SetHorizontalOffset(_scrollInfo.HorizontalOffset + delta); } } } if (_scrollInfo.CanVerticallyScroll) { var avgHeight = scrollable.RenderSize.Height / _scrollInfo.ViewportHeight; //translate to pixels if (mousePos.Y < 20) { if (GetUseLineScrollingForVerticalChange(scrollable)) { _scrollInfo.LineUp(); } else { var delta = (mousePos.Y - 20) / avgHeight; //translate back to original unit _scrollInfo.SetVerticalOffset(_scrollInfo.VerticalOffset + delta); } } else if (mousePos.Y > (scrollable.RenderSize.Height - 20)) { if (GetUseLineScrollingForVerticalChange(scrollable)) { _scrollInfo.LineDown(); } else { var delta = (mousePos.Y + 20 - scrollable.RenderSize.Height) / avgHeight; //translate back to original unit _scrollInfo.SetVerticalOffset(_scrollInfo.VerticalOffset + delta); } } } } } } }
另外一个scrollviewer内容拖拽,自动滚动的例子
http://www.codeproject.com/Tips/635510/WPF-Drag-Drop-Auto-scroll
http://drwpf.com/blog/2008/03/25/itemscontrol-i-is-for-item-container/
http://drwpf.com/blog/2008/07/20/itemscontrol-g-is-for-generator/
http://drwpf.com/blog/category/itemscontrol/
http://drwpf.com/blog/category/itemscontrol/
http://www.cnblogs.com/Kation/archive/2013/05/02/xaml-contentproperty-collection.html
http://www.cnblogs.com/gnielee/archive/2010/12/17/copy-wpf-ui-to-clipboard.html
http://blogs.msdn.com/b/llobo/archive/2006/12/08/drag-drop-library.aspx
http://www.cnblogs.com/DebugLZQ/archive/2013/05/06/3062409.html.
http://www.codeproject.com/Tips/82990/XAML-Serialization
https://msdn.microsoft.com/zh-cn/library/system.windows.markup.xamlreader%28v=vs.110%29.aspx
namespace CopyAndPasteInCanvas { public partial class Window1 : Window { private Rectangle rect; private double top = 20; private double left = 20; private Stack<Shape> undoStack = new Stack<Shape>(); private Stack<Shape> redoStack = new Stack<Shape>(); public Window1() { InitializeComponent(); CommandBinding pasteCmdBinding = new CommandBinding(); pasteCmdBinding.Command = ApplicationCommands.Paste; pasteCmdBinding.Executed += pasteCmdBinding_Executed; pasteCmdBinding.CanExecute += pasteCmdBinding_CanExecute; this.CommandBindings.Add(pasteCmdBinding); CommandBinding copyCmdBinding = new CommandBinding(); copyCmdBinding.Command = ApplicationCommands.Copy; copyCmdBinding.Executed += copyCmdBinding_Executed; copyCmdBinding.CanExecute += copyCmdBinding_CanExecute; this.CommandBindings.Add(copyCmdBinding); CommandBinding undoCmdBinding = new CommandBinding(); undoCmdBinding.Command = ApplicationCommands.Undo; undoCmdBinding.CanExecute += undoCmdBinding_CanExecute; undoCmdBinding.Executed += undoCmdBinding_Executed; this.CommandBindings.Add(undoCmdBinding); CommandBinding redoCmdBinding = new CommandBinding(); redoCmdBinding.Command = ApplicationCommands.Redo; redoCmdBinding.CanExecute += redoCmdBinding_CanExecute; redoCmdBinding.Executed += redoCmdBinding_Executed; this.CommandBindings.Add(redoCmdBinding); rect = new Rectangle(); rect.Width = 60; rect.Height = 60; rect.Fill = Brushes.Red; } private void undoCmdBinding_Executed(object sender, ExecutedRoutedEventArgs e) { Shape shape = undoStack.Pop(); RemoveShape(shape); } private void undoCmdBinding_CanExecute(object sender, CanExecuteRoutedEventArgs e) { e.CanExecute = undoStack.Count > 0; } private void redoCmdBinding_Executed(object sender, ExecutedRoutedEventArgs e) { Shape shape = redoStack.Pop(); AddShape(shape); } private void redoCmdBinding_CanExecute(object sender, CanExecuteRoutedEventArgs e) { e.CanExecute = redoStack.Count > 0; } private void pasteCmdBinding_CanExecute(object sender, CanExecuteRoutedEventArgs e) { e.CanExecute = Clipboard.ContainsText(TextDataFormat.Xaml); } private void copyCmdBinding_CanExecute(object sender, CanExecuteRoutedEventArgs e) { e.CanExecute = true; } private void copyCmdBinding_Executed(object sender, ExecutedRoutedEventArgs e) { string xaml = XamlWriter.Save(rect); Clipboard.SetText(xaml, TextDataFormat.Xaml); } private void pasteCmdBinding_Executed(object sender, ExecutedRoutedEventArgs e) { string xaml = Clipboard.GetText(TextDataFormat.Xaml); if (xaml != null) { using (MemoryStream stream = new MemoryStream(xaml.Length)) { using (StreamWriter sw = new StreamWriter(stream)) { sw.Write(xaml); sw.Flush(); stream.Seek(0, SeekOrigin.Begin); Shape shape = XamlReader.Load(stream) as Shape; AddShape(shape); } } } } private void AddShape(Shape shape) { Canvas.SetLeft(shape, left); Canvas.SetTop(shape, top); top += 20; left += 20; drawingCanvas.Children.Add(shape); undoStack.Push(shape); } private void RemoveShape(Shape shape) { top -= 20; left -= 20; Canvas.SetLeft(shape, left); Canvas.SetTop(shape, top); drawingCanvas.Children.Remove(shape); redoStack.Push(shape); } } }
<Window x:Class="CopyAndPasteInCanvas.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Window1" Height="400" Width="600"> <Grid> <Canvas Name="drawingCanvas"/> </Grid> </Window>
namespace CopyAndPasteInCanvas { public partial class Window1 : Window { private Rectangle rect; private double top = 20; private double left = 20; public Window1() { InitializeComponent(); CommandBinding pasteCmdBinding = new CommandBinding(); pasteCmdBinding.Command = ApplicationCommands.Paste; pasteCmdBinding.Executed += pasteCmdBinding_Executed; pasteCmdBinding.CanExecute += pasteCmdBinding_CanExecute; this.CommandBindings.Add(pasteCmdBinding); CommandBinding copyCmdBinding = new CommandBinding(); copyCmdBinding.Command = ApplicationCommands.Copy; copyCmdBinding.Executed += copyCmdBinding_Executed; copyCmdBinding.CanExecute += copyCmdBinding_CanExecute; this.CommandBindings.Add(copyCmdBinding); rect = new Rectangle(); rect.Width = 60; rect.Height = 60; rect.Fill = Brushes.Red; } private void pasteCmdBinding_CanExecute(object sender, CanExecuteRoutedEventArgs e) { e.CanExecute = Clipboard.ContainsText(TextDataFormat.Xaml); } private void copyCmdBinding_CanExecute(object sender, CanExecuteRoutedEventArgs e) { e.CanExecute = true; } private void copyCmdBinding_Executed(object sender, ExecutedRoutedEventArgs e) { string xaml = XamlWriter.Save(rect); Clipboard.SetText(xaml, TextDataFormat.Xaml); } private void pasteCmdBinding_Executed(object sender, ExecutedRoutedEventArgs e) { string xaml = Clipboard.GetText(TextDataFormat.Xaml); if (xaml != null) { using (MemoryStream stream = new MemoryStream(xaml.Length)) { using (StreamWriter sw = new StreamWriter(stream)) { sw.Write(xaml); sw.Flush(); stream.Seek(0, SeekOrigin.Begin); Shape shape = XamlReader.Load(stream) as Shape; Canvas.SetLeft(shape, left); Canvas.SetTop(shape, top); top += 20; left += 20; drawingCanvas.Children.Add(shape); } } } } } }
http://www.codeproject.com/Articles/19550/Automated-Undo-Redo-library-Csharp-Generics-NET-C